diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyDirectory.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyDirectory.cs
new file mode 100644
index 00000000000..8efcb5d7d78
--- /dev/null
+++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/DependencyDirectory.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+using Semmle.Util;
+using Semmle.Util.Logging;
+
+namespace Semmle.Extraction.CSharp.DependencyFetching
+{
+ ///
+ /// A directory used for storing fetched dependencies.
+ /// When a specific directory is set via the dependency directory extractor option,
+ /// we store dependencies in that directory for caching purposes.
+ /// Otherwise, we create a temporary directory that is deleted upon disposal.
+ ///
+ public sealed class DependencyDirectory : IDisposable
+ {
+ private readonly string userReportedDirectoryPurpose;
+ private readonly ILogger logger;
+ private readonly bool attemptCleanup;
+
+ public DirectoryInfo DirInfo { get; }
+
+ public DependencyDirectory(string subfolderName, string userReportedDirectoryPurpose, ILogger logger)
+ {
+ this.logger = logger;
+ this.userReportedDirectoryPurpose = userReportedDirectoryPurpose;
+
+ string path;
+ if (EnvironmentVariables.GetBuildlessDependencyDir() is string dir)
+ {
+ path = dir;
+ attemptCleanup = false;
+ }
+ else
+ {
+ path = FileUtils.GetTemporaryWorkingDirectory(out _);
+ attemptCleanup = true;
+ }
+ DirInfo = new DirectoryInfo(Path.Join(path, subfolderName));
+ DirInfo.Create();
+ }
+
+ public void Dispose()
+ {
+ if (!attemptCleanup)
+ {
+ logger.LogInfo($"Keeping {userReportedDirectoryPurpose} directory {DirInfo.FullName} for possible caching purposes.");
+ return;
+ }
+
+ try
+ {
+ DirInfo.Delete(true);
+ }
+ catch (Exception exc)
+ {
+ logger.LogInfo($"Couldn't delete {userReportedDirectoryPurpose} directory {exc.Message}");
+ }
+ }
+
+ public override string ToString() => DirInfo.FullName.ToString();
+ }
+}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs
index c77daa8899c..10d89b1e009 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetExeWrapper.cs
@@ -25,15 +25,15 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
///
/// The computed packages directory.
- /// This will be in the Temp location
+ /// This will be in the Cached or Temp location
/// so as to not trample the source tree.
///
- private readonly TemporaryDirectory packageDirectory;
+ private readonly DependencyDirectory packageDirectory;
///
/// Create the package manager for a specified source tree.
///
- public NugetExeWrapper(FileProvider fileProvider, TemporaryDirectory packageDirectory, Semmle.Util.Logging.ILogger logger)
+ public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger)
{
this.fileProvider = fileProvider;
this.packageDirectory = packageDirectory;
diff --git a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs
index e0e1bc649fa..e2e548a46a9 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp.DependencyFetching/NugetPackageRestorer.cs
@@ -24,12 +24,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
private readonly IDotNet dotnet;
private readonly DependabotProxy? dependabotProxy;
private readonly IDiagnosticsWriter diagnosticsWriter;
- private readonly TemporaryDirectory legacyPackageDirectory;
- private readonly TemporaryDirectory missingPackageDirectory;
+ private readonly DependencyDirectory legacyPackageDirectory;
+ private readonly DependencyDirectory missingPackageDirectory;
private readonly ILogger logger;
private readonly ICompilationInfoContainer compilationInfoContainer;
- public TemporaryDirectory PackageDirectory { get; }
+ public DependencyDirectory PackageDirectory { get; }
public NugetPackageRestorer(
FileProvider fileProvider,
@@ -48,9 +48,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
this.logger = logger;
this.compilationInfoContainer = compilationInfoContainer;
- PackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath("packages"), "package", logger);
- legacyPackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath("legacypackages"), "legacy package", logger);
- missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath("missingpackages"), "missing package", logger);
+ PackageDirectory = new DependencyDirectory("packages", "package", logger);
+ legacyPackageDirectory = new DependencyDirectory("legacypackages", "legacy package", logger);
+ missingPackageDirectory = new DependencyDirectory("missingpackages", "missing package", logger);
}
public string? TryRestore(string package)
diff --git a/csharp/extractor/Semmle.Util/EnvironmentVariables.cs b/csharp/extractor/Semmle.Util/EnvironmentVariables.cs
index edce64a53fe..9f1519653de 100644
--- a/csharp/extractor/Semmle.Util/EnvironmentVariables.cs
+++ b/csharp/extractor/Semmle.Util/EnvironmentVariables.cs
@@ -76,5 +76,15 @@ namespace Semmle.Util
{
return Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OVERLAY_BASE_METADATA_OUT");
}
+
+ ///
+ /// If set, returns the directory where buildless dependencies should be stored.
+ /// This is needed for caching dependencies.
+ ///
+ ///
+ public static string? GetBuildlessDependencyDir()
+ {
+ return Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_BUILDLESS_DEPENDENCY_DIR");
+ }
}
}