Skip to content

Commit 638c98b

Browse files
authored
Merge pull request #20832 from michaelnebel/csharp/dependencycaching
C#: Add extractor option for the dependency directory in BMN.
2 parents 8d72040 + 5c454d2 commit 638c98b

File tree

12 files changed

+139
-10
lines changed

12 files changed

+139
-10
lines changed

csharp/codeql-extractor.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,8 @@ options:
7474
[EXPERIMENTAL] The value is a path to the MsBuild binary log file that should be extracted.
7575
This option only works when `--build-mode none` is also specified.
7676
type: array
77+
buildless_dependency_dir:
78+
title: The path where buildless (standalone) extraction should keep dependencies.
79+
description: >
80+
If set, the buildless (standalone) extractor will store dependencies in this directory.
81+
type: string
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.IO;
3+
using Semmle.Util;
4+
using Semmle.Util.Logging;
5+
6+
namespace Semmle.Extraction.CSharp.DependencyFetching
7+
{
8+
/// <summary>
9+
/// A directory used for storing fetched dependencies.
10+
/// When a specific directory is set via the dependency directory extractor option,
11+
/// we store dependencies in that directory for caching purposes.
12+
/// Otherwise, we create a temporary directory that is deleted upon disposal.
13+
/// </summary>
14+
public sealed class DependencyDirectory : IDisposable
15+
{
16+
private readonly string userReportedDirectoryPurpose;
17+
private readonly ILogger logger;
18+
private readonly bool attemptCleanup;
19+
20+
public DirectoryInfo DirInfo { get; }
21+
22+
public DependencyDirectory(string subfolderName, string userReportedDirectoryPurpose, ILogger logger)
23+
{
24+
this.logger = logger;
25+
this.userReportedDirectoryPurpose = userReportedDirectoryPurpose;
26+
27+
string path;
28+
if (EnvironmentVariables.GetBuildlessDependencyDir() is string dir)
29+
{
30+
path = dir;
31+
attemptCleanup = false;
32+
}
33+
else
34+
{
35+
path = FileUtils.GetTemporaryWorkingDirectory(out _);
36+
attemptCleanup = true;
37+
}
38+
DirInfo = new DirectoryInfo(Path.Join(path, subfolderName));
39+
DirInfo.Create();
40+
}
41+
42+
public void Dispose()
43+
{
44+
if (!attemptCleanup)
45+
{
46+
logger.LogInfo($"Keeping {userReportedDirectoryPurpose} directory {DirInfo.FullName} for possible caching purposes.");
47+
return;
48+
}
49+
50+
try
51+
{
52+
DirInfo.Delete(true);
53+
}
54+
catch (Exception exc)
55+
{
56+
logger.LogInfo($"Couldn't delete {userReportedDirectoryPurpose} directory {exc.Message}");
57+
}
58+
}
59+
60+
public override string ToString() => DirInfo.FullName;
61+
}
62+
}

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ internal class NugetExeWrapper : IDisposable
2424
private readonly FileProvider fileProvider;
2525

2626
/// <summary>
27-
/// The computed packages directory.
28-
/// This will be in the Temp location
27+
/// The packages directory.
28+
/// This will be in the user-specified or computed Temp location
2929
/// so as to not trample the source tree.
3030
/// </summary>
31-
private readonly TemporaryDirectory packageDirectory;
31+
private readonly DependencyDirectory packageDirectory;
3232

3333
/// <summary>
3434
/// Create the package manager for a specified source tree.
3535
/// </summary>
36-
public NugetExeWrapper(FileProvider fileProvider, TemporaryDirectory packageDirectory, Semmle.Util.Logging.ILogger logger)
36+
public NugetExeWrapper(FileProvider fileProvider, DependencyDirectory packageDirectory, Semmle.Util.Logging.ILogger logger)
3737
{
3838
this.fileProvider = fileProvider;
3939
this.packageDirectory = packageDirectory;

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ internal sealed partial class NugetPackageRestorer : IDisposable
2424
private readonly IDotNet dotnet;
2525
private readonly DependabotProxy? dependabotProxy;
2626
private readonly IDiagnosticsWriter diagnosticsWriter;
27-
private readonly TemporaryDirectory legacyPackageDirectory;
28-
private readonly TemporaryDirectory missingPackageDirectory;
27+
private readonly DependencyDirectory legacyPackageDirectory;
28+
private readonly DependencyDirectory missingPackageDirectory;
2929
private readonly ILogger logger;
3030
private readonly ICompilationInfoContainer compilationInfoContainer;
3131

32-
public TemporaryDirectory PackageDirectory { get; }
32+
public DependencyDirectory PackageDirectory { get; }
3333

3434
public NugetPackageRestorer(
3535
FileProvider fileProvider,
@@ -48,9 +48,9 @@ public NugetPackageRestorer(
4848
this.logger = logger;
4949
this.compilationInfoContainer = compilationInfoContainer;
5050

51-
PackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath("packages"), "package", logger);
52-
legacyPackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath("legacypackages"), "legacy package", logger);
53-
missingPackageDirectory = new TemporaryDirectory(ComputeTempDirectoryPath("missingpackages"), "missing package", logger);
51+
PackageDirectory = new DependencyDirectory("packages", "package", logger);
52+
legacyPackageDirectory = new DependencyDirectory("legacypackages", "legacy package", logger);
53+
missingPackageDirectory = new DependencyDirectory("missingpackages", "missing package", logger);
5454
}
5555

5656
public string? TryRestore(string package)

csharp/extractor/Semmle.Util/EnvironmentVariables.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,14 @@ public static IEnumerable<string> GetURLs(string name)
7676
{
7777
return Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OVERLAY_BASE_METADATA_OUT");
7878
}
79+
80+
/// <summary>
81+
/// If set, returns the directory where buildless dependencies should be stored.
82+
/// This can be used for caching dependencies.
83+
/// </summary>
84+
public static string? GetBuildlessDependencyDir()
85+
{
86+
return Environment.GetEnvironmentVariable("CODEQL_EXTRACTOR_CSHARP_OPTION_BUILDLESS_DEPENDENCY_DIR");
87+
}
7988
}
8089
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| dependencies/packages/newtonsoft.json/13.0.1/lib/netstandard2.0/Newtonsoft.Json.dll:0:0:0:0 | Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed |
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import csharp
2+
3+
from Assembly a
4+
where
5+
not a.getCompilation().getOutputAssembly() = a and
6+
a.getName().matches("%Newtonsoft%")
7+
select a
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class Program
2+
{
3+
static void Main(string[] args)
4+
{
5+
}
6+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"sdk": {
3+
"version": "9.0.304"
4+
}
5+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFrameworks>net9.0</TargetFrameworks>
6+
</PropertyGroup>
7+
8+
<Target Name="DeleteBinObjFolders" BeforeTargets="Clean">
9+
<RemoveDir Directories=".\bin" />
10+
<RemoveDir Directories=".\obj" />
11+
</Target>
12+
13+
<ItemGroup>
14+
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
15+
</ItemGroup>
16+
</Project>

0 commit comments

Comments
 (0)