Skip to content

Commit 91f2ea5

Browse files
authored
Merge pull request #16164 from tamasvajk/buildless/nuget-feed-fallback-feed-check
C#: Check fallback nuget feeds before trying to use them in the fallb…
2 parents 5cebcad + c004f92 commit 91f2ea5

File tree

14 files changed

+270
-48
lines changed

14 files changed

+270
-48
lines changed

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

Lines changed: 157 additions & 34 deletions
Large diffs are not rendered by default.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ private void AddNetFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet
339339
{
340340
logger.LogInfo("No .NET Desktop Runtime location found. Attempting to restore the .NET Framework reference assemblies manually.");
341341

342-
if (TryRestorePackageManually(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies, null))
342+
if (TryRestorePackageManually(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies))
343343
{
344344
runtimeLocation = GetPackageDirectory(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies, missingPackageDirectory);
345345
}

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ public bool AddPackage(string folder, string package)
9595

9696
public IList<string> GetListedSdks() => GetResultList("--list-sdks");
9797

98-
private IList<string> GetResultList(string args)
98+
private IList<string> GetResultList(string args, string? workingDirectory = null)
9999
{
100-
if (dotnetCliInvoker.RunCommand(args, out var results))
100+
if (dotnetCliInvoker.RunCommand(args, workingDirectory, out var results))
101101
{
102102
return results;
103103
}
@@ -111,7 +111,19 @@ public bool Exec(string execArgs)
111111
return dotnetCliInvoker.RunCommand(args);
112112
}
113113

114-
public IList<string> GetNugetFeeds(string nugetConfig) => GetResultList($"nuget list source --format Short --configfile \"{nugetConfig}\"");
114+
private const string nugetListSourceCommand = "nuget list source --format Short";
115+
116+
public IList<string> GetNugetFeeds(string nugetConfig)
117+
{
118+
logger.LogInfo($"Getting Nuget feeds from '{nugetConfig}'...");
119+
return GetResultList($"{nugetListSourceCommand} --configfile \"{nugetConfig}\"");
120+
}
121+
122+
public IList<string> GetNugetFeedsFromFolder(string folderPath)
123+
{
124+
logger.LogInfo($"Getting Nuget feeds in folder '{folderPath}'...");
125+
return GetResultList(nugetListSourceCommand, folderPath);
126+
}
115127

116128
// The version number should be kept in sync with the version .NET version used for building the application.
117129
public const string LatestDotNetSdkVersion = "8.0.101";

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,41 +21,49 @@ public DotNetCliInvoker(ILogger logger, string exec)
2121
this.Exec = exec;
2222
}
2323

24-
private ProcessStartInfo MakeDotnetStartInfo(string args)
24+
private ProcessStartInfo MakeDotnetStartInfo(string args, string? workingDirectory)
2525
{
2626
var startInfo = new ProcessStartInfo(Exec, args)
2727
{
2828
UseShellExecute = false,
2929
RedirectStandardOutput = true,
3030
RedirectStandardError = true
3131
};
32+
if (!string.IsNullOrWhiteSpace(workingDirectory))
33+
{
34+
startInfo.WorkingDirectory = workingDirectory;
35+
}
3236
// Set the .NET CLI language to English to avoid localized output.
3337
startInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"] = "en";
3438
startInfo.EnvironmentVariables["MSBUILDDISABLENODEREUSE"] = "1";
3539
startInfo.EnvironmentVariables["DOTNET_SKIP_FIRST_TIME_EXPERIENCE"] = "true";
3640
return startInfo;
3741
}
3842

39-
private bool RunCommandAux(string args, out IList<string> output)
43+
private bool RunCommandAux(string args, string? workingDirectory, out IList<string> output)
4044
{
41-
logger.LogInfo($"Running {Exec} {args}");
42-
var pi = MakeDotnetStartInfo(args);
45+
var dirLog = string.IsNullOrWhiteSpace(workingDirectory) ? "" : $" in {workingDirectory}";
46+
logger.LogInfo($"Running {Exec} {args}{dirLog}");
47+
var pi = MakeDotnetStartInfo(args, workingDirectory);
4348
var threadId = Environment.CurrentManagedThreadId;
4449
void onOut(string s) => logger.LogInfo(s, threadId);
4550
void onError(string s) => logger.LogError(s, threadId);
4651
var exitCode = pi.ReadOutput(out output, onOut, onError);
4752
if (exitCode != 0)
4853
{
49-
logger.LogError($"Command {Exec} {args} failed with exit code {exitCode}");
54+
logger.LogError($"Command {Exec} {args}{dirLog} failed with exit code {exitCode}");
5055
return false;
5156
}
5257
return true;
5358
}
5459

5560
public bool RunCommand(string args) =>
56-
RunCommandAux(args, out _);
61+
RunCommandAux(args, null, out _);
5762

5863
public bool RunCommand(string args, out IList<string> output) =>
59-
RunCommandAux(args, out output);
64+
RunCommandAux(args, null, out output);
65+
66+
public bool RunCommand(string args, string? workingDirectory, out IList<string> output) =>
67+
RunCommandAux(args, workingDirectory, out output);
6068
}
6169
}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,28 @@ internal class EnvironmentVariableNames
3333
public const string NugetFeedResponsivenessInitialTimeout = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_TIMEOUT";
3434

3535
/// <summary>
36-
/// Specifies how many requests to make to the NuGet feed to check its responsiveness.
36+
/// Specifies the timeout (as an integer) in milliseconds for the initial check of fallback NuGet feeds responsiveness. The value is then doubled for each subsequent check.
37+
/// This is primarily used in testing.
38+
/// </summary>
39+
internal const string NugetFeedResponsivenessInitialTimeoutForFallback = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_FALLBACK_TIMEOUT";
40+
41+
/// <summary>
42+
/// Specifies how many requests to make to the NuGet feeds to check their responsiveness.
3743
/// </summary>
3844
public const string NugetFeedResponsivenessRequestCount = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_LIMIT";
3945

46+
/// <summary>
47+
/// Specifies how many requests to make to the fallback NuGet feeds to check their responsiveness.
48+
/// This is primarily used in testing.
49+
/// </summary>
50+
internal const string NugetFeedResponsivenessRequestCountForFallback = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_CHECK_FALLBACK_LIMIT";
51+
52+
/// <summary>
53+
/// Specifies the NuGet feeds to use for fallback Nuget dependency fetching. The value is a space-separated list of feed URLs.
54+
/// The default value is `https://api.nuget.org/v3/index.json`.
55+
/// </summary>
56+
public const string FallbackNugetFeeds = "CODEQL_EXTRACTOR_CSHARP_BUILDLESS_NUGET_FEEDS_FALLBACK";
57+
4058
/// <summary>
4159
/// Specifies the location of the diagnostic directory.
4260
/// </summary>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public interface IDotNet
1414
IList<string> GetListedSdks();
1515
bool Exec(string execArgs);
1616
IList<string> GetNugetFeeds(string nugetConfig);
17+
IList<string> GetNugetFeedsFromFolder(string folderPath);
1718
}
1819

1920
public record class RestoreSettings(string File, string PackageDirectory, bool ForceDotnetRefAssemblyFetching, string? PathToNugetConfig = null, bool ForceReevaluation = false);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,11 @@ internal interface IDotNetCliInvoker
1919
/// The output of the command is returned in `output`.
2020
/// </summary>
2121
bool RunCommand(string args, out IList<string> output);
22+
23+
/// <summary>
24+
/// Execute `dotnet <args>` in `<workingDirectory>` and return true if the command succeeded, otherwise false.
25+
/// The output of the command is returned in `output`.
26+
/// </summary>
27+
bool RunCommand(string args, string? workingDirectory, out IList<string> output);
2228
}
2329
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ private void RunMonoNugetCommand(string command, out IList<string> stdout)
243243
private void AddDefaultPackageSource(string nugetConfig)
244244
{
245245
logger.LogInfo("Adding default package source...");
246-
RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source https://api.nuget.org/v3/index.json -ConfigFile \"{nugetConfig}\"", out var _);
246+
RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source {DependencyManager.PublicNugetFeed} -ConfigFile \"{nugetConfig}\"", out var _);
247247
}
248248

249249
public void Dispose()

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ internal class DotNetCliInvokerStub : IDotNetCliInvoker
1010
{
1111
private readonly IList<string> output;
1212
private string lastArgs = "";
13+
public string WorkingDirectory { get; private set; } = "";
1314
public bool Success { get; set; } = true;
1415

1516
public DotNetCliInvokerStub(IList<string> output)
@@ -32,6 +33,12 @@ public bool RunCommand(string args, out IList<string> output)
3233
return Success;
3334
}
3435

36+
public bool RunCommand(string args, string? workingDirectory, out IList<string> output)
37+
{
38+
WorkingDirectory = workingDirectory ?? "";
39+
return RunCommand(args, out output);
40+
}
41+
3542
public string GetLastArgs() => lastArgs;
3643
}
3744

@@ -262,5 +269,36 @@ public void TestDotnetExec()
262269
var lastArgs = dotnetCliInvoker.GetLastArgs();
263270
Assert.Equal("exec myarg1 myarg2", lastArgs);
264271
}
272+
273+
[Fact]
274+
public void TestNugetFeeds()
275+
{
276+
// Setup
277+
var dotnetCliInvoker = new DotNetCliInvokerStub(new List<string>());
278+
var dotnet = MakeDotnet(dotnetCliInvoker);
279+
280+
// Execute
281+
dotnet.GetNugetFeeds("abc");
282+
283+
// Verify
284+
var lastArgs = dotnetCliInvoker.GetLastArgs();
285+
Assert.Equal("nuget list source --format Short --configfile \"abc\"", lastArgs);
286+
}
287+
288+
[Fact]
289+
public void TestNugetFeedsFromFolder()
290+
{
291+
// Setup
292+
var dotnetCliInvoker = new DotNetCliInvokerStub(new List<string>());
293+
var dotnet = MakeDotnet(dotnetCliInvoker);
294+
295+
// Execute
296+
dotnet.GetNugetFeedsFromFolder("abc");
297+
298+
// Verify
299+
var lastArgs = dotnetCliInvoker.GetLastArgs();
300+
Assert.Equal("nuget list source --format Short", lastArgs);
301+
Assert.Equal("abc", dotnetCliInvoker.WorkingDirectory);
302+
}
265303
}
266304
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public DotNetStub(IList<string> runtimes, IList<string> sdks)
2828
public bool Exec(string execArgs) => true;
2929

3030
public IList<string> GetNugetFeeds(string nugetConfig) => [];
31+
32+
public IList<string> GetNugetFeedsFromFolder(string folderPath) => [];
3133
}
3234

3335
public class RuntimeTests

0 commit comments

Comments
 (0)