diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs index 8f2572871f4..facfb73543e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs @@ -352,10 +352,10 @@ namespace Semmle.Extraction.CSharp.DependencyFetching } - private bool RestoreProject(string project, string? pathToNugetConfig = null) => - dotnet.RestoreProjectToDirectory(project, packageDirectory.DirInfo.FullName, pathToNugetConfig); + private bool RestoreProject(string project, out string stdout, string? pathToNugetConfig = null) => + dotnet.RestoreProjectToDirectory(project, packageDirectory.DirInfo.FullName, out stdout, pathToNugetConfig); - private bool RestoreSolution(string solution, out IList projects) => + private bool RestoreSolution(string solution, out IEnumerable projects) => dotnet.RestoreSolutionToDirectory(solution, packageDirectory.DirInfo.FullName, out projects); /// @@ -370,8 +370,22 @@ namespace Semmle.Extraction.CSharp.DependencyFetching return restoredProjects; }); - private void RestoreProjects(IEnumerable projects) => - Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, project => RestoreProject(project)); + private void RestoreProjects(IEnumerable projects) + { + var stdoutLines = projects + .AsParallel() + .WithDegreeOfParallelism(options.Threads) + .Select(project => + { + RestoreProject(project, out var stdout); + return stdout; + }) + .ToList(); + foreach (var line in stdoutLines) + { + Console.WriteLine(line); + } + } private void DownloadMissingPackages(List allFiles) { @@ -412,7 +426,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching continue; } - success = RestoreProject(tempDir.DirInfo.FullName, nugetConfig); + success = RestoreProject(tempDir.DirInfo.FullName, out var stdout, nugetConfig); + Console.WriteLine(stdout); // TODO: the restore might fail, we could retry with a prerelease (*-* instead of *) version of the package. if (!success) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs index 4adf7fa1c5d..ac8434f7b8f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs @@ -33,12 +33,17 @@ namespace Semmle.Extraction.CSharp.DependencyFetching } } - private ProcessStartInfo MakeDotnetStartInfo(string args, bool redirectStandardOutput) => - new ProcessStartInfo(dotnet, args) + private ProcessStartInfo MakeDotnetStartInfo(string args, bool redirectStandardOutput) + { + var startInfo = new ProcessStartInfo(dotnet, args) { UseShellExecute = false, RedirectStandardOutput = redirectStandardOutput }; + // Set the .NET CLI language to English to avoid localized output. + startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"] = "en"; + return startInfo; + } private bool RunCommand(string args) { @@ -70,17 +75,19 @@ namespace Semmle.Extraction.CSharp.DependencyFetching private static string GetRestoreArgs(string projectOrSolutionFile, string packageDirectory) => $"restore --no-dependencies \"{projectOrSolutionFile}\" --packages \"{packageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true"; - public bool RestoreProjectToDirectory(string projectFile, string packageDirectory, string? pathToNugetConfig = null) + public bool RestoreProjectToDirectory(string projectFile, string packageDirectory, out string stdout, string? pathToNugetConfig = null) { var args = GetRestoreArgs(projectFile, packageDirectory); if (pathToNugetConfig != null) { args += $" --configfile \"{pathToNugetConfig}\""; } - return RunCommand(args); + var success = RunCommand(args, out var output); + stdout = string.Join("\n", output); + return success; } - public bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, out IList projects) + public bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, out IEnumerable projects) { var args = GetRestoreArgs(solutionFile, packageDirectory); args += " --verbosity normal"; @@ -90,12 +97,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching projects = output .Select(line => regex.Match(line)) .Where(match => match.Success) - .Select(match => match.Groups[1].Value) - .ToList(); + .Select(match => match.Groups[1].Value); return true; } - projects = new List(); + projects = Array.Empty(); return false; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs index 9a3f8b5ec64..f4fe6714ea7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/IDotNet.cs @@ -4,8 +4,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching { internal interface IDotNet { - bool RestoreProjectToDirectory(string project, string directory, string? pathToNugetConfig = null); - bool RestoreSolutionToDirectory(string solution, string directory, out IList projects); + bool RestoreProjectToDirectory(string project, string directory, out string stdout, string? pathToNugetConfig = null); + bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, out IEnumerable projects); bool New(string folder); bool AddPackage(string folder, string package); IList GetListedRuntimes(); diff --git a/csharp/extractor/Semmle.Extraction.Tests/Runtime.cs b/csharp/extractor/Semmle.Extraction.Tests/Runtime.cs index 75b3f98b688..64d06c9a1e7 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Runtime.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/Runtime.cs @@ -1,4 +1,5 @@ using Xunit; +using System; using System.Collections.Generic; using Semmle.Extraction.CSharp.DependencyFetching; @@ -18,11 +19,15 @@ namespace Semmle.Extraction.Tests public bool New(string folder) => true; - public bool RestoreProjectToDirectory(string project, string directory, string? pathToNugetConfig = null) => true; - - public bool RestoreSolutionToDirectory(string solution, string directory, out IList projects) + public bool RestoreProjectToDirectory(string project, string directory, out string stdout, string? pathToNugetConfig = null) { - projects = new List(); + stdout = ""; + return true; + } + + public bool RestoreSolutionToDirectory(string solution, string directory, out IEnumerable projects) + { + projects = Array.Empty(); return true; }