Skip to content

Commit 30095e3

Browse files
committed
Refactor dotnet restore calls
1 parent d742cd3 commit 30095e3

File tree

5 files changed

+70
-82
lines changed

5 files changed

+70
-82
lines changed

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyManager.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -677,9 +677,9 @@ private IEnumerable<string> RestoreSolutions(IEnumerable<string> solutions, out
677677
var projects = solutions.SelectMany(solution =>
678678
{
679679
logger.LogInfo($"Restoring solution {solution}...");
680-
var success = dotnet.RestoreSolutionToDirectory(solution, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: true, out var restoredProjects, out var a);
681-
assetFiles.AddRange(a);
682-
return restoredProjects;
680+
var res = dotnet.Restore(new(solution, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
681+
assetFiles.AddRange(res.AssetsFilePaths);
682+
return res.RestoredProjects;
683683
});
684684
assets = assetFiles;
685685
return projects;
@@ -697,8 +697,8 @@ private void RestoreProjects(IEnumerable<string> projects, out IEnumerable<strin
697697
Parallel.ForEach(projects, new ParallelOptions { MaxDegreeOfParallelism = options.Threads }, project =>
698698
{
699699
logger.LogInfo($"Restoring project {project}...");
700-
var success = dotnet.RestoreProjectToDirectory(project, packageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: true, out var a, out var _);
701-
assetFiles.AddRange(a);
700+
var res = dotnet.Restore(new(project, packageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: true));
701+
assetFiles.AddRange(res.AssetsFilePaths);
702702
});
703703
assets = assetFiles;
704704
}
@@ -757,18 +757,18 @@ private void DownloadMissingPackages(List<FileInfo> allFiles, ISet<string> dllPa
757757
return;
758758
}
759759

760-
success = dotnet.RestoreProjectToDirectory(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: false, out var _, out var outputLines, pathToNugetConfig: nugetConfig);
761-
if (!success)
760+
var res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: nugetConfig));
761+
if (!res.Success)
762762
{
763-
if (outputLines?.Any(s => s.Contains("NU1301")) == true)
763+
if (res.HasNugetPackageSourceError)
764764
{
765765
// Restore could not be completed because the listed source is unavailable. Try without the nuget.config:
766-
success = dotnet.RestoreProjectToDirectory(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, forceDotnetRefAssemblyFetching: false, out var _, out var _, pathToNugetConfig: null, force: true);
766+
res = dotnet.Restore(new(tempDir.DirInfo.FullName, missingPackageDirectory.DirInfo.FullName, ForceDotnetRefAssemblyFetching: false, PathToNugetConfig: null, ForceReevaluation: true));
767767
}
768768

769769
// TODO: the restore might fail, we could retry with a prerelease (*-* instead of *) version of the package.
770770

771-
if (!success)
771+
if (!res.Success)
772772
{
773773
logger.LogInfo($"Failed to restore nuget package {package}");
774774
}

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DotNet.cs

+10-38
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ private void Info()
4141
}
4242
}
4343

44-
private string GetRestoreArgs(string projectOrSolutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching)
44+
private string GetRestoreArgs(RestoreSettings restoreSettings)
4545
{
46-
var args = $"restore --no-dependencies \"{projectOrSolutionFile}\" --packages \"{packageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal";
46+
var args = $"restore --no-dependencies \"{restoreSettings.File}\" --packages \"{restoreSettings.PackageDirectory}\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal";
4747

48-
if (forceDotnetRefAssemblyFetching)
48+
if (restoreSettings.ForceDotnetRefAssemblyFetching)
4949
{
5050
// Ugly hack: we set the TargetFrameworkRootPath and NetCoreTargetingPackRoot properties to an empty folder:
5151
var path = ".empty";
@@ -58,46 +58,24 @@ private string GetRestoreArgs(string projectOrSolutionFile, string packageDirect
5858
args += $" /p:TargetFrameworkRootPath=\"{path}\" /p:NetCoreTargetingPackRoot=\"{path}\"";
5959
}
6060

61-
return args;
62-
}
63-
64-
private static IEnumerable<string> GetFirstGroupOnMatch(Regex regex, IEnumerable<string> lines) =>
65-
lines
66-
.Select(line => regex.Match(line))
67-
.Where(match => match.Success)
68-
.Select(match => match.Groups[1].Value);
69-
70-
private static IEnumerable<string> GetAssetsFilePaths(IEnumerable<string> lines) =>
71-
GetFirstGroupOnMatch(AssetsFileRegex(), lines);
72-
73-
private static IEnumerable<string> GetRestoredProjects(IEnumerable<string> lines) =>
74-
GetFirstGroupOnMatch(RestoredProjectRegex(), lines);
75-
76-
public bool RestoreProjectToDirectory(string projectFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> assets, out IList<string> outputLines, string? pathToNugetConfig = null, bool force = false)
77-
{
78-
var args = GetRestoreArgs(projectFile, packageDirectory, forceDotnetRefAssemblyFetching);
79-
if (pathToNugetConfig != null)
61+
if (restoreSettings.PathToNugetConfig != null)
8062
{
81-
args += $" --configfile \"{pathToNugetConfig}\"";
63+
args += $" --configfile \"{restoreSettings.PathToNugetConfig}\"";
8264
}
8365

84-
if (force)
66+
if (restoreSettings.ForceReevaluation)
8567
{
8668
args += " --force";
8769
}
8870

89-
var success = dotnetCliInvoker.RunCommand(args, out outputLines);
90-
assets = success ? GetAssetsFilePaths(outputLines) : Array.Empty<string>();
91-
return success;
71+
return args;
9272
}
9373

94-
public bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects, out IEnumerable<string> assets)
74+
public RestoreResult Restore(RestoreSettings restoreSettings)
9575
{
96-
var args = GetRestoreArgs(solutionFile, packageDirectory, forceDotnetRefAssemblyFetching);
76+
var args = GetRestoreArgs(restoreSettings);
9777
var success = dotnetCliInvoker.RunCommand(args, out var output);
98-
projects = success ? GetRestoredProjects(output) : Array.Empty<string>();
99-
assets = success ? GetAssetsFilePaths(output) : Array.Empty<string>();
100-
return success;
78+
return new(success, output);
10179
}
10280

10381
public bool New(string folder)
@@ -130,11 +108,5 @@ public bool Exec(string execArgs)
130108
var args = $"exec {execArgs}";
131109
return dotnetCliInvoker.RunCommand(args);
132110
}
133-
134-
[GeneratedRegex("Restored\\s+(.+\\.csproj)", RegexOptions.Compiled)]
135-
private static partial Regex RestoredProjectRegex();
136-
137-
[GeneratedRegex("[Assets\\sfile\\shas\\snot\\schanged.\\sSkipping\\sassets\\sfile\\swriting.|Writing\\sassets\\sfile\\sto\\sdisk.]\\sPath:\\s(.+)", RegexOptions.Compiled)]
138-
private static partial Regex AssetsFileRegex();
139111
}
140112
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,43 @@
1+
using System;
12
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text.RegularExpressions;
25

36
namespace Semmle.Extraction.CSharp.DependencyFetching
47
{
58
internal interface IDotNet
69
{
7-
bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> assets, out IList<string> outputLines, string? pathToNugetConfig = null, bool force = false);
8-
bool RestoreSolutionToDirectory(string solutionFile, string packageDirectory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects, out IEnumerable<string> assets);
10+
RestoreResult Restore(RestoreSettings restoreSettings);
911
bool New(string folder);
1012
bool AddPackage(string folder, string package);
1113
IList<string> GetListedRuntimes();
1214
IList<string> GetListedSdks();
1315
bool Exec(string execArgs);
1416
}
17+
18+
internal record class RestoreSettings(string File, string PackageDirectory, bool ForceDotnetRefAssemblyFetching, string? PathToNugetConfig = null, bool ForceReevaluation = false);
19+
20+
internal partial record class RestoreResult(bool Success, IList<string> Output)
21+
{
22+
private readonly Lazy<IEnumerable<string>> assetsFilePaths = new(() => GetFirstGroupOnMatch(AssetsFileRegex(), Output));
23+
public IEnumerable<string> AssetsFilePaths => Success ? assetsFilePaths.Value : Array.Empty<string>();
24+
25+
private readonly Lazy<IEnumerable<string>> restoredProjects = new(() => GetFirstGroupOnMatch(RestoredProjectRegex(), Output));
26+
public IEnumerable<string> RestoredProjects => Success ? restoredProjects.Value : Array.Empty<string>();
27+
28+
private readonly Lazy<bool> hasNugetPackageSourceError = new(() => Output.Any(s => s.Contains("NU1301")));
29+
public bool HasNugetPackageSourceError => hasNugetPackageSourceError.Value;
30+
31+
private static IEnumerable<string> GetFirstGroupOnMatch(Regex regex, IEnumerable<string> lines) =>
32+
lines
33+
.Select(line => regex.Match(line))
34+
.Where(match => match.Success)
35+
.Select(match => match.Groups[1].Value);
36+
37+
[GeneratedRegex("Restored\\s+(.+\\.csproj)", RegexOptions.Compiled)]
38+
private static partial Regex RestoredProjectRegex();
39+
40+
[GeneratedRegex("[Assets\\sfile\\shas\\snot\\schanged.\\sSkipping\\sassets\\sfile\\swriting.|Writing\\sassets\\sfile\\sto\\sdisk.]\\sPath:\\s(.+)", RegexOptions.Compiled)]
41+
private static partial Regex AssetsFileRegex();
42+
}
1543
}

csharp/extractor/Semmle.Extraction.Tests/DotNet.cs

+19-19
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ public void TestDotnetRestoreProjectToDirectory1()
101101
var dotnet = MakeDotnet(dotnetCliInvoker);
102102

103103
// Execute
104-
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false, out var assets, out var _);
104+
dotnet.Restore(new("myproject.csproj", "mypackages", false));
105105

106106
// Verify
107107
var lastArgs = dotnetCliInvoker.GetLastArgs();
@@ -116,14 +116,14 @@ public void TestDotnetRestoreProjectToDirectory2()
116116
var dotnet = MakeDotnet(dotnetCliInvoker);
117117

118118
// Execute
119-
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false, out var assets, out var _, pathToNugetConfig: "myconfig.config");
119+
var res = dotnet.Restore(new("myproject.csproj", "mypackages", false, "myconfig.config"));
120120

121121
// Verify
122122
var lastArgs = dotnetCliInvoker.GetLastArgs();
123123
Assert.Equal("restore --no-dependencies \"myproject.csproj\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile \"myconfig.config\"", lastArgs);
124-
Assert.Equal(2, assets.Count());
125-
Assert.Contains("/path/to/project.assets.json", assets);
126-
Assert.Contains("/path/to/project2.assets.json", assets);
124+
Assert.Equal(2, res.AssetsFilePaths.Count());
125+
Assert.Contains("/path/to/project.assets.json", res.AssetsFilePaths);
126+
Assert.Contains("/path/to/project2.assets.json", res.AssetsFilePaths);
127127
}
128128

129129
[Fact]
@@ -134,14 +134,14 @@ public void TestDotnetRestoreProjectToDirectory3()
134134
var dotnet = MakeDotnet(dotnetCliInvoker);
135135

136136
// Execute
137-
dotnet.RestoreProjectToDirectory("myproject.csproj", "mypackages", false, out var assets, out var _, pathToNugetConfig: "myconfig.config", force: true);
137+
var res = dotnet.Restore(new("myproject.csproj", "mypackages", false, "myconfig.config", true));
138138

139139
// Verify
140140
var lastArgs = dotnetCliInvoker.GetLastArgs();
141141
Assert.Equal("restore --no-dependencies \"myproject.csproj\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile \"myconfig.config\" --force", lastArgs);
142-
Assert.Equal(2, assets.Count());
143-
Assert.Contains("/path/to/project.assets.json", assets);
144-
Assert.Contains("/path/to/project2.assets.json", assets);
142+
Assert.Equal(2, res.AssetsFilePaths.Count());
143+
Assert.Contains("/path/to/project.assets.json", res.AssetsFilePaths);
144+
Assert.Contains("/path/to/project2.assets.json", res.AssetsFilePaths);
145145
}
146146

147147
[Fact]
@@ -152,17 +152,17 @@ public void TestDotnetRestoreSolutionToDirectory1()
152152
var dotnet = MakeDotnet(dotnetCliInvoker);
153153

154154
// Execute
155-
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects, out var assets);
155+
var res = dotnet.Restore(new("mysolution.sln", "mypackages", false));
156156

157157
// Verify
158158
var lastArgs = dotnetCliInvoker.GetLastArgs();
159159
Assert.Equal("restore --no-dependencies \"mysolution.sln\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal", lastArgs);
160-
Assert.Equal(2, projects.Count());
161-
Assert.Contains("/path/to/project.csproj", projects);
162-
Assert.Contains("/path/to/project2.csproj", projects);
163-
Assert.Equal(2, assets.Count());
164-
Assert.Contains("/path/to/project.assets.json", assets);
165-
Assert.Contains("/path/to/project2.assets.json", assets);
160+
Assert.Equal(2, res.RestoredProjects.Count());
161+
Assert.Contains("/path/to/project.csproj", res.RestoredProjects);
162+
Assert.Contains("/path/to/project2.csproj", res.RestoredProjects);
163+
Assert.Equal(2, res.AssetsFilePaths.Count());
164+
Assert.Contains("/path/to/project.assets.json", res.AssetsFilePaths);
165+
Assert.Contains("/path/to/project2.assets.json", res.AssetsFilePaths);
166166
}
167167

168168
[Fact]
@@ -174,13 +174,13 @@ public void TestDotnetRestoreSolutionToDirectory2()
174174
dotnetCliInvoker.Success = false;
175175

176176
// Execute
177-
dotnet.RestoreSolutionToDirectory("mysolution.sln", "mypackages", false, out var projects, out var assets);
177+
var res = dotnet.Restore(new("mysolution.sln", "mypackages", false));
178178

179179
// Verify
180180
var lastArgs = dotnetCliInvoker.GetLastArgs();
181181
Assert.Equal("restore --no-dependencies \"mysolution.sln\" --packages \"mypackages\" /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal", lastArgs);
182-
Assert.Empty(projects);
183-
Assert.Empty(assets);
182+
Assert.Empty(res.RestoredProjects);
183+
Assert.Empty(res.AssetsFilePaths);
184184
}
185185

186186
[Fact]

csharp/extractor/Semmle.Extraction.Tests/Runtime.cs

+1-13
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,7 @@ public DotNetStub(IList<string> runtimes, IList<string> sdks)
1919

2020
public bool New(string folder) => true;
2121

22-
public bool RestoreProjectToDirectory(string project, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> assets, out IList<string> outputLines, string? pathToNugetConfig = null, bool force = false)
23-
{
24-
assets = Array.Empty<string>();
25-
outputLines = Array.Empty<string>();
26-
return true;
27-
}
28-
29-
public bool RestoreSolutionToDirectory(string solution, string directory, bool forceDotnetRefAssemblyFetching, out IEnumerable<string> projects, out IEnumerable<string> assets)
30-
{
31-
projects = Array.Empty<string>();
32-
assets = Array.Empty<string>();
33-
return true;
34-
}
22+
public RestoreResult Restore(RestoreSettings restoreSettings) => new(true, Array.Empty<string>());
3523

3624
public IList<string> GetListedRuntimes() => runtimes;
3725

0 commit comments

Comments
 (0)