예제 #1
0
        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>
            <Platforms>x64</Platforms>
        </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());
            }
        }
예제 #2
0
        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 referenceLocations = new Dictionary <string, string>();
            var assemblyFileNames  = _assemblyNames.Select(Path.GetFileName).ToList();

            foreach (var fileName in Directory.GetFiles(_binPath, "*.dll", SearchOption.TopDirectoryOnly)
                     .Union(Directory.GetFiles(_binPath, "*.exe", SearchOption.TopDirectoryOnly)))
            {
                var assemblyPath = Path.GetFullPath(fileName);
                if (assemblyFileNames.Contains(Path.GetFileName(assemblyPath)))
                {
                    continue;
                }

                Assembly assembly;
                try
                {
                    assembly = Assembly.LoadFile(assemblyPath);
                }
                catch (Exception)
                {
                    continue;
                }
                var assemblyName     = assembly.GetName().Name;
                var assemblyLocation = assembly.Location;

                var assemblyLocationUri          = new Uri(assemblyLocation);
                var assemblyLocationRelativePath = new Uri(Path.GetFullPath(directoryPath)).MakeRelativeUri(assemblyLocationUri).ToString();
                referenceLocations.Add(assemblyName, assemblyLocationRelativePath);
            }

            var conditionToPackageInfo = new Dictionary <string, List <Tuple <string, string, string> > >();

            var execAssembly = Assembly.GetExecutingAssembly();
            var projFile     = Path.Combine(Path.GetDirectoryName(execAssembly.Location), $@"{execAssembly.GetName().Name}.csproj");
            var doc          = XDocument.Load(projFile);

            foreach (var itemGroup in doc.Descendants("ItemGroup"))
            {
                var itemGroupCondition = itemGroup.Attributes().FirstOrDefault(a => a.Name == "Condition");
                var condition          = itemGroupCondition == null ? string.Empty : 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 packageMode          = packageNameAttribute.Name.ToString();

                    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 List <Tuple <string, string, string> >());
                    }
                    conditionToPackageInfo[condition].Add(new Tuple <string, string, string>(packageMode, packageName, packageVersion));
                }
            }

            var conditionalPackageReferences = new List <string>();

            foreach (var cpi in conditionToPackageInfo)
            {
                var packageReferences = new List <string>();
                foreach (var pi in cpi.Value)
                {
                    packageReferences.Add(
                        $@"     <PackageReference {pi.Item1}=""{pi.Item2}"" Version=""{pi.Item3}"" />");
                }

                if (cpi.Key == String.Empty || cpi.Key == _targetFramework)
                {
                    conditionalPackageReferences.Add(
                        $@" <ItemGroup>
{string.Join("\n", packageReferences)}
    </ItemGroup>
");
                }
            }

            var references = new List <string>();

            foreach (var rl in referenceLocations)
            {
                references.Add(
                    $@"     <Reference Include=""{rl.Key}"">
            <HintPath>{rl.Value}</HintPath>
        </Reference>");
            }

            var referencesItemGroup =
                $@" <ItemGroup>
{string.Join("\n", references)}
    </ItemGroup>
";

            var projectFileSource =
                $@" <Project Sdk=""Microsoft.NET.Sdk"">
    <PropertyGroup>
        <TargetFramework>{_targetFramework}</TargetFramework>
    </PropertyGroup>
{referencesItemGroup}{string.Join(string.Empty, conditionalPackageReferences)}</Project>";
            var projectSourceFile =
                new SourceFile()
            {
                FileName = $"{_outputAssemblyName}.csproj", SourceCode = projectFileSource
            };

            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());
            }
        }