in Clients/CSharp/AmbrosiaCS/Program.cs [34:267]
private static void RunCodeGen()
{
var directoryName = @"latest";
var generatedDirectory = "GeneratedSourceFiles";
if (!Directory.Exists(generatedDirectory))
{
Directory.CreateDirectory(generatedDirectory); // let any exceptions bleed through
}
var projectDirectory = Path.Combine(generatedDirectory, _outputAssemblyName);
if (!Directory.Exists(projectDirectory))
{
Directory.CreateDirectory(projectDirectory); // let any exceptions bleed through
}
var directoryPath = Path.Combine(projectDirectory, directoryName);
if (Directory.Exists(directoryPath))
{
var oldDirectoryPath = Path.Combine(projectDirectory, Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));
Directory.Move(directoryPath, oldDirectoryPath);
}
Directory.CreateDirectory(directoryPath); // let any exceptions bleed through
// Add references for assemblies referenced by the input assembly
var sourceFiles = new List<SourceFile>();
var generatedProxyNames = new List<string>();
var generatedProxyNamespaces = new List<string>();
foreach (var assemblyName in _assemblyNames)
{
var assembly = Assembly.LoadFrom(assemblyName);
foreach (var t in assembly.DefinedTypes)
{
if (t.IsInterface)
{
var internalTypeRepresentation = Utilities.GetTypeDefinitionInformation(t);
var proxyInterfacesSource = new ProxyInterfaceGenerator(internalTypeRepresentation).TransformText();
sourceFiles.Add(new SourceFile() { FileName = $"ProxyInterfaces_{t.Name}.cs", SourceCode = proxyInterfacesSource, });
var immortalSource = new DispatcherGenerator(internalTypeRepresentation).TransformText();
sourceFiles.Add(new SourceFile() { FileName = $"Dispatcher_{t.Name}.cs", SourceCode = immortalSource, });
var instanceProxySource = new ProxyGenerator(internalTypeRepresentation, internalTypeRepresentation.Name + "Proxy").TransformText();
sourceFiles.Add(new SourceFile() { FileName = $"Proxy_{t.Name}.cs", SourceCode = instanceProxySource, });
generatedProxyNames.Add($"{internalTypeRepresentation.Name}Proxy_Implementation");
generatedProxyNamespaces.Add(internalTypeRepresentation.Namespace);
}
else if (t.IsValueType)
{
// This code creates a generated source file holding the definition of any
// struct that was defined in the input assembly.
//
// The short-term reason for this code is to support cases like
// PerformanceTestInterruptible's IJob.cs where the IDL interface definition
// relies on custom structs.
//
// The long-term reason for this code is that structs are supported by many
// different languages and serialization formats, so once we have a true
// cross-language IDL, it makes sense to have structs be a part of that IDL.
// very silly hack!
var sb = new StringBuilder();
sb.AppendLine($"using System;");
sb.AppendLine($"using System.Runtime.Serialization;");
sb.AppendLine($"namespace {t.Namespace} {{");
foreach (var customAttribute in t.CustomAttributes)
{
sb.AppendLine($"[{customAttribute.AttributeType.Name}]");
}
sb.AppendLine($"public struct {t.Name}");
sb.AppendLine($"{{");
foreach (var field in t.GetFields())
{
if (field.CustomAttributes.Count() > 0)
{
foreach (var ca in field.CustomAttributes)
{
sb.AppendLine($" [{ca.AttributeType.Name}]");
}
}
sb.AppendLine($" public {field.FieldType.Name} {field.Name};");
}
sb.AppendLine($"}}");
sb.AppendLine($"}}");
sourceFiles.Add(new SourceFile() { FileName = $"{t.Name}.cs", SourceCode = sb.ToString(), });
}
}
}
var immortalSerializerSource = new ImmortalSerializerGenerator(generatedProxyNames, generatedProxyNamespaces).TransformText();
sourceFiles.Add(new SourceFile { FileName = $"ImmortalSerializer.cs", SourceCode = immortalSerializerSource, });
var conditionToPackageInfo = new Dictionary<string, Dictionary<string, HashSet<PackageReferenceInfo>>>();
var conditionToProjectReference = new Dictionary<string, HashSet<string>>();
var execAssembly = Assembly.GetExecutingAssembly();
var projFile = Path.Combine(Path.GetDirectoryName(execAssembly.Location), $@"{execAssembly.GetName().Name}.csproj");
_projectFiles.Add(projFile);
var defaultConditionString = string.Empty;
foreach (var projectFile in _projectFiles)
{
var doc = XDocument.Load(projectFile);
foreach (var itemGroup in doc.Descendants("ItemGroup"))
{
var itemGroupCondition = itemGroup.Attributes().FirstOrDefault(a => a.Name == "Condition");
var condition = itemGroupCondition == null ? defaultConditionString : itemGroupCondition.Value;
foreach (var packageReference in itemGroup.Descendants("PackageReference"))
{
var elements = packageReference.Elements();
var attributes = packageReference.Attributes().ToList();
var packageIncludeAttribute = attributes.FirstOrDefault(a => a.Name == "Include");
var packageUpdateAttribute = attributes.FirstOrDefault(a => a.Name == "Update");
if (packageIncludeAttribute == null && packageUpdateAttribute == null) continue;
var packageNameAttribute = packageIncludeAttribute ?? packageUpdateAttribute;
var packageName = packageNameAttribute.Value;
var versionAttribute = attributes.FirstOrDefault(a => a.Name == "Version");
string packageVersion;
if (versionAttribute == null)
{
var packageVersionElement = elements.FirstOrDefault(e => e.Name == "Version");
if (packageVersionElement == null) continue;
packageVersion = packageVersionElement.Value;
}
else
{
packageVersion = versionAttribute.Value;
}
if (!conditionToPackageInfo.ContainsKey(condition))
{
conditionToPackageInfo.Add(condition, new Dictionary<string, HashSet<PackageReferenceInfo>>());
}
var packageReferenceInfo = new PackageReferenceInfo(packageName, packageVersion, packageReference.ToString());
if (!conditionToPackageInfo[condition].ContainsKey(packageName))
{
conditionToPackageInfo[condition].Add(packageName, new HashSet<PackageReferenceInfo>());
}
conditionToPackageInfo[condition][packageName].Add(packageReferenceInfo);
}
foreach (var projectReference in itemGroup.Descendants("ProjectReference"))
{
var attributes = projectReference.Attributes().ToList();
var projectIncludeAttribute = attributes.FirstOrDefault(a => a.Name == "Include");
var projectPath = projectIncludeAttribute.Value;
var formerBasePath = new Uri(new FileInfo(projectFile).Directory.FullName + Path.DirectorySeparatorChar);
var currentBasePath = new Uri(new DirectoryInfo(directoryPath).FullName + Path.DirectorySeparatorChar);
var projectPathUri = new Uri(formerBasePath, projectPath);
var newRelativePath = currentBasePath.MakeRelativeUri(projectPathUri);
if (!conditionToProjectReference.ContainsKey(condition))
{
conditionToProjectReference.Add(condition, new HashSet<string>());
}
conditionToProjectReference[condition].Add(projectReference.ToString().Replace(projectPath.ToString(), newRelativePath.ToString()));
}
}
}
var defaultConditionInfo = conditionToPackageInfo.ContainsKey(defaultConditionString) ? conditionToPackageInfo[defaultConditionString] : null;
foreach (var cp in conditionToPackageInfo)
{
foreach (var nameToInfo in cp.Value)
{
var packageInfos = new HashSet<PackageReferenceInfo>(nameToInfo.Value.Union(
defaultConditionInfo == null || !defaultConditionInfo.ContainsKey(nameToInfo.Key)
? new List<PackageReferenceInfo>() : defaultConditionInfo[nameToInfo.Key].ToList()));
if (packageInfos.Count > 1)
{
Console.WriteLine($"WARNING: Detected multiple versions of package {nameToInfo.Key} : {string.Join(",", packageInfos.Select(pi => pi.PackageVersion))}");
}
}
}
var conditionalPackageReferences = new List<string>();
foreach (var cpi in conditionToPackageInfo)
{
conditionalPackageReferences.Add($"<ItemGroup{(cpi.Key != string.Empty ? $" Condition=\"{cpi.Key}\"" : string.Empty)}>{string.Join("\n", cpi.Value.SelectMany(v => v.Value).Select(pri => pri.ReferenceString))}</ItemGroup>");
}
var conditionalProjectReferences = new List<string>();
foreach (var cpi in conditionToProjectReference)
{
conditionalProjectReferences.Add($"<ItemGroup{(cpi.Key != string.Empty ? $" Condition=\"{cpi.Key}\"" : string.Empty)}>{string.Join("\n", cpi.Value)}</ItemGroup>");
}
var projectFileSource =
$@" <Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
<TargetFrameworks>{string.Join(";", _targetFrameworks)}</TargetFrameworks>
</PropertyGroup>
{string.Join(string.Empty, conditionalPackageReferences)}
{string.Join(string.Empty, conditionalProjectReferences)}
</Project>";
var projectFileXml = XDocument.Parse(projectFileSource);
var projectSourceFile = new SourceFile { FileName = $"{_outputAssemblyName}.csproj", SourceCode = projectFileXml.ToString() };
sourceFiles.Add(projectSourceFile);
var trees = sourceFiles
.Select(s => CSharpSyntaxTree.ParseText(
s.SourceCode,
path: Path.Combine(directoryPath, s.FileName),
encoding: Encoding.GetEncoding(0)
));
string directory = null;
foreach (var tree in trees)
{
if (directory == null)
{
directory = Path.GetDirectoryName(tree.FilePath);
}
var sourceFile = tree.FilePath;
File.WriteAllText(sourceFile, tree.GetRoot().ToFullString());
}
}