Skip to content

Commit e3fe9f7

Browse files
committed
Move Nuget restore logic from DependencyManager to dedicated class
1 parent 5406fac commit e3fe9f7

File tree

4 files changed

+160
-112
lines changed

4 files changed

+160
-112
lines changed

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

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,26 @@
1212

1313
namespace Semmle.Extraction.CSharp.DependencyFetching
1414
{
15+
public interface ICompilationInfoContainer
16+
{
17+
/// <summary>
18+
/// List of `(key, value)` tuples, that are stored in the DB for telemetry purposes.
19+
/// </summary>
20+
List<(string, string)> CompilationInfos { get; }
21+
}
22+
1523
/// <summary>
1624
/// Main implementation of the build analysis.
1725
/// </summary>
18-
public sealed partial class DependencyManager : IDisposable
26+
public sealed partial class DependencyManager : IDisposable, ICompilationInfoContainer
1927
{
2028
private readonly AssemblyCache assemblyCache;
2129
private readonly ILogger logger;
2230
private readonly IDiagnosticsWriter diagnosticsWriter;
31+
private readonly NugetPackageRestorer nugetPackageRestorer;
32+
private readonly IDotNet dotnet;
33+
private readonly FileContent fileContent;
34+
private readonly FileProvider fileProvider;
2335

2436
// Only used as a set, but ConcurrentDictionary is the only concurrent set in .NET.
2537
private readonly IDictionary<string, bool> usedReferences = new ConcurrentDictionary<string, bool>();
@@ -30,18 +42,14 @@ public sealed partial class DependencyManager : IDisposable
3042
private int conflictedReferences = 0;
3143
private readonly DirectoryInfo sourceDir;
3244
private string? dotnetPath;
33-
private readonly IDotNet dotnet;
34-
private readonly FileContent fileContent;
35-
private readonly TemporaryDirectory packageDirectory;
36-
private readonly TemporaryDirectory legacyPackageDirectory;
37-
private readonly TemporaryDirectory missingPackageDirectory;
45+
3846
private readonly TemporaryDirectory tempWorkingDirectory;
39-
private readonly FileProvider fileProvider;
4047
private readonly bool cleanupTempWorkingDirectory;
4148

4249
private readonly Lazy<Runtime> runtimeLazy;
4350
private Runtime Runtime => runtimeLazy.Value;
44-
private readonly int threads = EnvironmentVariables.GetDefaultNumberOfThreads();
51+
52+
internal static readonly int Threads = EnvironmentVariables.GetDefaultNumberOfThreads();
4553

4654
/// <summary>
4755
/// Performs C# dependency fetching.
@@ -74,10 +82,6 @@ public DependencyManager(string srcDir, ILogger logger)
7482
$"dependency-manager-{DateTime.UtcNow:yyyyMMddHHmm}-{Environment.ProcessId}.jsonc"));
7583
this.sourceDir = new DirectoryInfo(srcDir);
7684

77-
packageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "packages"));
78-
legacyPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "legacypackages"));
79-
missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectory(sourceDir.FullName, "missingpackages"));
80-
8185
tempWorkingDirectory = new TemporaryDirectory(FileUtils.GetTemporaryWorkingDirectory(out cleanupTempWorkingDirectory));
8286

8387
this.fileProvider = new FileProvider(sourceDir, logger);
@@ -112,8 +116,10 @@ void exitCallback(int ret, string msg, bool silent)
112116
throw;
113117
}
114118

119+
nugetPackageRestorer = new NugetPackageRestorer(fileProvider, fileContent, dotnet, diagnosticsWriter, logger, this);
120+
115121
var dllLocations = fileProvider.Dlls.Select(x => new AssemblyLookupLocation(x)).ToHashSet();
116-
RestoreNugetPackages(dllLocations);
122+
dllLocations.UnionWith(nugetPackageRestorer.Restore());
117123
// Find DLLs in the .Net / Asp.Net Framework
118124
// This needs to come after the nuget restore, because the nuget restore might fetch the .NET Core/Framework reference assemblies.
119125
var frameworkLocations = AddFrameworkDlls(dllLocations);
@@ -221,11 +227,7 @@ private HashSet<string> AddFrameworkDlls(HashSet<AssemblyLookupLocation> dllLoca
221227

222228
private void RemoveNugetAnalyzerReferences()
223229
{
224-
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
225-
if (packageFolder == null)
226-
{
227-
return;
228-
}
230+
var packageFolder = nugetPackageRestorer.PackageDirectory.DirInfo.FullName.ToLowerInvariant();
229231

230232
foreach (var filename in usedReferences.Keys)
231233
{
@@ -299,7 +301,7 @@ private void AddNetFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet
299301
var packagesInPrioOrder = FrameworkPackageNames.NetFrameworks;
300302

301303
var frameworkPaths = packagesInPrioOrder
302-
.Select((s, index) => (Index: index, Path: GetPackageDirectory(s, packageDirectory)))
304+
.Select((s, index) => (Index: index, Path: GetPackageDirectory(s)))
303305
.Where(pair => pair.Path is not null)
304306
.ToArray();
305307

@@ -330,11 +332,7 @@ private void AddNetFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet
330332
if (runtimeLocation is null)
331333
{
332334
logger.LogInfo("No .NET Desktop Runtime location found. Attempting to restore the .NET Framework reference assemblies manually.");
333-
334-
if (TryRestorePackageManually(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies))
335-
{
336-
runtimeLocation = GetPackageDirectory(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies, missingPackageDirectory);
337-
}
335+
runtimeLocation = nugetPackageRestorer.TryRestoreLatestNetFrameworkReferenceAssemblies();
338336
}
339337
}
340338

@@ -354,12 +352,7 @@ private void AddNetFrameworkDlls(ISet<AssemblyLookupLocation> dllLocations, ISet
354352

355353
private void RemoveNugetPackageReference(string packagePrefix, ISet<AssemblyLookupLocation> dllLocations)
356354
{
357-
var packageFolder = packageDirectory.DirInfo.FullName.ToLowerInvariant();
358-
if (packageFolder == null)
359-
{
360-
return;
361-
}
362-
355+
var packageFolder = nugetPackageRestorer.PackageDirectory.DirInfo.FullName.ToLowerInvariant();
363356
var packagePathPrefix = Path.Combine(packageFolder, packagePrefix.ToLowerInvariant());
364357
var toRemove = dllLocations.Where(s => s.Path.StartsWith(packagePathPrefix, StringComparison.InvariantCultureIgnoreCase));
365358
foreach (var path in toRemove)
@@ -382,7 +375,7 @@ private void AddAspNetCoreFrameworkDlls(ISet<AssemblyLookupLocation> dllLocation
382375
}
383376

384377
// First try to find ASP.NET Core assemblies in the NuGet packages
385-
if (GetPackageDirectory(FrameworkPackageNames.AspNetCoreFramework, packageDirectory) is string aspNetCorePackage)
378+
if (GetPackageDirectory(FrameworkPackageNames.AspNetCoreFramework) is string aspNetCorePackage)
386379
{
387380
SelectNewestFrameworkPath(aspNetCorePackage, "ASP.NET Core", dllLocations, frameworkLocations);
388381
return;
@@ -398,15 +391,20 @@ private void AddAspNetCoreFrameworkDlls(ISet<AssemblyLookupLocation> dllLocation
398391

399392
private void AddMicrosoftWindowsDesktopDlls(ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
400393
{
401-
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework, packageDirectory) is string windowsDesktopApp)
394+
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework) is string windowsDesktopApp)
402395
{
403396
SelectNewestFrameworkPath(windowsDesktopApp, "Windows Desktop App", dllLocations, frameworkLocations);
404397
}
405398
}
406399

407-
private string? GetPackageDirectory(string packagePrefix, TemporaryDirectory root)
400+
private string? GetPackageDirectory(string packagePrefix)
408401
{
409-
return new DirectoryInfo(root.DirInfo.FullName)
402+
return GetPackageDirectory(packagePrefix, nugetPackageRestorer.PackageDirectory.DirInfo);
403+
}
404+
405+
internal static string? GetPackageDirectory(string packagePrefix, DirectoryInfo root)
406+
{
407+
return new DirectoryInfo(root.FullName)
410408
.EnumerateDirectories(packagePrefix + "*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
411409
.FirstOrDefault()?
412410
.FullName;
@@ -495,22 +493,6 @@ private void GenerateSourceFilesFromWebViews()
495493
}
496494
}
497495

498-
/// <summary>
499-
/// Computes a unique temp directory for the packages associated
500-
/// with this source tree. Use a SHA1 of the directory name.
501-
/// </summary>
502-
/// <returns>The full path of the temp directory.</returns>
503-
private static string ComputeTempDirectory(string srcDir, string subfolderName)
504-
{
505-
var bytes = Encoding.Unicode.GetBytes(srcDir);
506-
var sha = SHA1.HashData(bytes);
507-
var sb = new StringBuilder();
508-
foreach (var b in sha.Take(8))
509-
sb.AppendFormat("{0:x2}", b);
510-
511-
return Path.Combine(FileUtils.GetTemporaryWorkingDirectory(out var _), sb.ToString(), subfolderName);
512-
}
513-
514496
/// <summary>
515497
/// Creates a temporary directory with the given subfolder name.
516498
/// The created directory might be inside the repo folder, and it is deleted when the object is disposed.
@@ -634,7 +616,7 @@ private void ResolveConflicts(IEnumerable<string> frameworkPaths)
634616

635617
private void AnalyseSolutions(IEnumerable<string> solutions)
636618
{
637-
Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = threads }, solutionFile =>
619+
Parallel.ForEach(solutions, new ParallelOptions { MaxDegreeOfParallelism = Threads }, solutionFile =>
638620
{
639621
try
640622
{
@@ -683,7 +665,7 @@ private void AnalyseProject(FileInfo project)
683665
}
684666
}
685667

686-
public void Dispose(TemporaryDirectory? dir, string name)
668+
public static void DisposeTempDirectory(TemporaryDirectory? dir, string name, ILogger logger)
687669
{
688670
try
689671
{
@@ -697,15 +679,13 @@ public void Dispose(TemporaryDirectory? dir, string name)
697679

698680
public void Dispose()
699681
{
700-
Dispose(packageDirectory, "package");
701-
Dispose(legacyPackageDirectory, "legacy package");
702-
Dispose(missingPackageDirectory, "missing package");
703682
if (cleanupTempWorkingDirectory)
704683
{
705-
Dispose(tempWorkingDirectory, "temporary working");
684+
DisposeTempDirectory(tempWorkingDirectory, "temporary working", logger);
706685
}
707686

708687
diagnosticsWriter?.Dispose();
688+
nugetPackageRestorer?.Dispose();
709689
}
710690
}
711691
}

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class FileProvider
1212
private static readonly HashSet<string> binaryFileExtensions = [".dll", ".exe"]; // TODO: add more binary file extensions.
1313

1414
private readonly ILogger logger;
15-
private readonly Lazy<FileInfo[]> all;
15+
private readonly FileInfo[] all;
1616
private readonly Lazy<FileInfo[]> allNonBinary;
1717
private readonly Lazy<string[]> smallNonBinary;
1818
private readonly Lazy<string[]> sources;
@@ -29,8 +29,8 @@ public FileProvider(DirectoryInfo sourceDir, ILogger logger)
2929
SourceDir = sourceDir;
3030
this.logger = logger;
3131

32-
all = new Lazy<FileInfo[]>(GetAllFiles);
33-
allNonBinary = new Lazy<FileInfo[]>(() => all.Value.Where(f => !binaryFileExtensions.Contains(f.Extension.ToLowerInvariant())).ToArray());
32+
all = GetAllFiles();
33+
allNonBinary = new Lazy<FileInfo[]>(() => all.Where(f => !binaryFileExtensions.Contains(f.Extension.ToLowerInvariant())).ToArray());
3434
smallNonBinary = new Lazy<string[]>(() =>
3535
{
3636
var ret = SelectSmallFiles(allNonBinary.Value).SelectFileNames().ToArray();
@@ -45,7 +45,7 @@ public FileProvider(DirectoryInfo sourceDir, ILogger logger)
4545
globalJsons = new Lazy<string[]>(() => allNonBinary.Value.SelectFileNamesByName("global.json").ToArray());
4646
razorViews = new Lazy<string[]>(() => SelectTextFileNamesByExtension("razor view", ".cshtml", ".razor"));
4747

48-
rootNugetConfig = new Lazy<string?>(() => all.Value.SelectRootFiles(SourceDir).SelectFileNamesByName("nuget.config").FirstOrDefault());
48+
rootNugetConfig = new Lazy<string?>(() => all.SelectRootFiles(SourceDir).SelectFileNamesByName("nuget.config").FirstOrDefault());
4949
}
5050

5151
private string[] SelectTextFileNamesByExtension(string filetype, params string[] extensions)
@@ -57,7 +57,7 @@ private string[] SelectTextFileNamesByExtension(string filetype, params string[]
5757

5858
private string[] SelectBinaryFileNamesByExtension(string filetype, params string[] extensions)
5959
{
60-
var ret = all.Value.SelectFileNamesByExtension(extensions).ToArray();
60+
var ret = all.SelectFileNamesByExtension(extensions).ToArray();
6161
logger.LogInfo($"Found {ret.Length} {filetype} files in {SourceDir}.");
6262
return ret;
6363
}

csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackages.cs renamed to csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
namespace Semmle.Extraction.CSharp.DependencyFetching
99
{
1010
/// <summary>
11-
/// Manage the downloading of NuGet packages.
11+
/// Manage the downloading of NuGet packages with nuget.exe.
1212
/// Locates packages in a source tree and downloads all of the
1313
/// referenced assemblies to a temp folder.
1414
/// </summary>
15-
internal class NugetPackages : IDisposable
15+
internal class NugetExeWrapper : IDisposable
1616
{
1717
private readonly string? nugetExe;
1818
private readonly Util.Logging.ILogger logger;
@@ -37,7 +37,7 @@ internal class NugetPackages : IDisposable
3737
/// <summary>
3838
/// Create the package manager for a specified source tree.
3939
/// </summary>
40-
public NugetPackages(string sourceDir, TemporaryDirectory packageDirectory, Util.Logging.ILogger logger)
40+
public NugetExeWrapper(string sourceDir, TemporaryDirectory packageDirectory, Util.Logging.ILogger logger)
4141
{
4242
this.packageDirectory = packageDirectory;
4343
this.logger = logger;
@@ -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 {DependencyManager.PublicNugetFeed} -ConfigFile \"{nugetConfig}\"", out var _);
246+
RunMonoNugetCommand($"sources add -Name DefaultNugetOrg -Source {NugetPackageRestorer.PublicNugetOrgFeed} -ConfigFile \"{nugetConfig}\"", out var _);
247247
}
248248

249249
public void Dispose()

0 commit comments

Comments
 (0)