diff --git a/src/SourceBrowser/src/BinLogToSln/BinLogToSln.csproj b/src/SourceBrowser/src/BinLogToSln/BinLogToSln.csproj index 37b0df1..c7adf93 100644 --- a/src/SourceBrowser/src/BinLogToSln/BinLogToSln.csproj +++ b/src/SourceBrowser/src/BinLogToSln/BinLogToSln.csproj @@ -9,11 +9,12 @@ 1.0.1 - - - - - + + + + + + diff --git a/src/SourceBrowser/src/BinLogToSln/Program.cs b/src/SourceBrowser/src/BinLogToSln/Program.cs index 5def968..84a0ffd 100644 --- a/src/SourceBrowser/src/BinLogToSln/Program.cs +++ b/src/SourceBrowser/src/BinLogToSln/Program.cs @@ -1,18 +1,17 @@ +using LibGit2Sharp; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.SourceBrowser.BinLogParser; +using Mono.Options; +using NuGet.Frameworks; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Numerics; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; -using LibGit2Sharp; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.SourceBrowser.BinLogParser; -using Mono.Options; -using NuGet.Frameworks; [assembly: InternalsVisibleTo("BinLogToSln.Tests")] @@ -146,6 +145,7 @@ private static bool ShouldExcludeInvocation(CompilerInvocation invocation) return false; } + static void Main(string[] args) { string binlog = null; @@ -205,7 +205,7 @@ static void Main(string[] args) WriteSolutionHeader(sln); IEnumerable invocations = BinLogCompilerInvocationsReader.ExtractInvocations(binlog); - + // Group invocations by assembly name and select the best one for each var invocationGroups = invocations .Where(invocation => !ShouldExcludeInvocation(invocation)) @@ -240,11 +240,10 @@ static void Main(string[] args) using var projFile = new FileStream(projectFilePath, FileMode.Create); using var project = new StreamWriter(projFile); - string typeGuid = invocation.Language switch + (string typeGuid, bool isCSharp) = invocation.Language switch { - LanguageNames.CSharp => CSharpProjectTypeGuid, - LanguageNames.VisualBasic => VBProjectTypeGuid, - _ => CSharpProjectTypeGuid, + LanguageNames.VisualBasic => (VBProjectTypeGuid, false), + _ => (CSharpProjectTypeGuid, true), }; sln.WriteLine($"Project(\"{typeGuid}\") = \"{projectName}\", \"{Path.Join("src", repoRelativeProjectPath)}\", \"{GetProjectGuid()}\""); sln.WriteLine("EndProject"); @@ -255,6 +254,7 @@ static void Main(string[] args) project.WriteLine(" false"); project.WriteLine(" false"); project.WriteLine(" true"); + project.WriteLine(" <_SkipAnalyzers>true"); project.WriteLine($" {invocation.AssemblyName}"); int idx = 1; if (invocation.Parsed.CompilationOptions is CSharpCompilationOptions cSharpOptions) @@ -269,7 +269,7 @@ static void Main(string[] args) } if (cSharpOptions.CryptoKeyFile != null) { - includeFile(cSharpOptions.CryptoKeyFile, out string projectRelativePath, out _); + string projectRelativePath = includeFile(cSharpOptions.CryptoKeyFile, includeCompile: false); project.WriteLine($" {projectRelativePath}"); } } @@ -283,25 +283,33 @@ static void Main(string[] args) project.WriteLine(" "); foreach (CommandLineSourceFile sourceFile in invocation.Parsed.SourceFiles) { - includeFile(sourceFile.Path, out string projectRelativePath, out string link); - project.WriteLine($" "); + includeFile(sourceFile.Path); } project.WriteLine(" "); project.WriteLine(" "); foreach (CommandLineReference reference in invocation.Parsed.MetadataReferences) { - string path = reference.Reference; - if (!File.Exists(path)) + includeReference("ReferencePath", reference.Reference); + } + project.WriteLine(" "); + + // Add generated files. + project.WriteLine(" "); + foreach (var generatedFile in getGeneratedFiles()) + { + string filePath = generatedFile.FilePath; + if (!File.Exists(filePath)) { - Console.WriteLine($"Could not find reference '{path}'"); - continue; + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + var stream = generatedFile.Stream; + stream.Position = 0; + using var fileStream = File.OpenWrite(filePath); + stream.CopyTo(fileStream); } - string projToRepoPath = Path.GetRelativePath(invocation.ProjectDirectory, repoRoot); - string projToOutputPath = Path.Join(projToRepoPath, ".."); - string refPath = DedupeReference(output, path); - project.WriteLine($" "); + includeFile(filePath); } project.WriteLine(" "); + project.WriteLine(""); if (!string.IsNullOrEmpty(invocation.OutputAssemblyPath)) { @@ -311,12 +319,13 @@ static void Main(string[] args) File.Copy(invocation.OutputAssemblyPath, outputFilePath, true); } - void includeFile(string originalPath, out string projectRelativePath, out string link) + string includeFile(string originalPath, bool includeCompile = true) { string filePath = Path.GetFullPath(originalPath); string repoRelativePath = Path.GetRelativePath(repoRoot, filePath); string outputFile; - link = null; + string link = null; + string projectRelativePath; if (repoRelativePath.StartsWith("..\\", StringComparison.Ordinal) || repoRelativePath.StartsWith("../", StringComparison.Ordinal) || Path.IsPathRooted(repoRelativePath)) { string externalPath = Path.Join("_external", idx++.ToString(), Path.GetFileName(filePath)); @@ -338,6 +347,44 @@ void includeFile(string originalPath, out string projectRelativePath, out string { File.Copy(filePath, outputFile); } + + if (includeCompile) + { + project.WriteLine($" "); + } + + return projectRelativePath; + } + + void includeReference(string kind, string path) + { + if (!File.Exists(path)) + { + Console.WriteLine($"Could not find {kind} '{path}'"); + return; + } + + string projToRepoPath = Path.GetRelativePath(invocation.ProjectDirectory, repoRoot); + string projToOutputPath = Path.Join(projToRepoPath, ".."); + string refPath = DedupeReference(output, path); + project.WriteLine($" <{kind} Include=\"{Path.Join(projToOutputPath, refPath)}\"/>"); + } + + IEnumerable<(string FilePath, MemoryStream Stream)> getGeneratedFiles() + { + try + { + return Basic.CompilerLog.Util.RoslynUtil.ReadGeneratedFilesFromPdb( + isCSharp: isCSharp, + diagnosticName: invocation.ProjectFilePath, + invocation.Parsed); + } + catch (Exception ex) + { + // We don't want to fail official builds during stage 1, so just log a warning. + Console.WriteLine($"##vso[task.logissue type=warning;]Error processing generated files for '{invocation.ProjectFilePath}': {ex}"); + return []; + } } } @@ -386,7 +433,7 @@ private static string GetProjectGuid() return Guid.NewGuid().ToString("B"); } - private static string CSharpProjectTypeGuid = "{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"; - private static string VBProjectTypeGuid = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"; + private static readonly string CSharpProjectTypeGuid = "{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"; + private static readonly string VBProjectTypeGuid = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"; } } diff --git a/src/SourceBrowser/src/Directory.Packages.props b/src/SourceBrowser/src/Directory.Packages.props index 9c77671..ceb1502 100644 --- a/src/SourceBrowser/src/Directory.Packages.props +++ b/src/SourceBrowser/src/Directory.Packages.props @@ -41,6 +41,7 @@ +