C#: Fetch .NET in dependency manager instead of autobuilder

This commit is contained in:
Tom Hvitved
2024-02-29 10:33:24 +01:00
parent c6426d8858
commit 62382fc5a2
31 changed files with 306 additions and 373 deletions

View File

@@ -50,11 +50,8 @@ namespace Semmle.Autobuild.CSharp
attempt = new BuildCommandRule(DotNetRule.WithDotNet).Analyse(this, false) & CheckExtractorRun(true);
break;
case CSharpBuildStrategy.Buildless:
attempt = DotNetRule.WithDotNet(this, ensureDotNetAvailable: true, (dotNetPath, env) =>
{
// No need to check that the extractor has been executed in buildless mode
return new StandaloneBuildRule(dotNetPath).Analyse(this, false);
});
// No need to check that the extractor has been executed in buildless mode
attempt = new StandaloneBuildRule().Analyse(this, false);
break;
case CSharpBuildStrategy.MSBuild:
attempt = new MsBuildRule().Analyse(this, false) & CheckExtractorRun(true);
@@ -84,7 +81,7 @@ namespace Semmle.Autobuild.CSharp
return 0;
if (warnOnFailure)
Log(Severity.Error, "No C# code detected during build.");
Logger.LogError("No C# code detected during build.");
return 1;
});

View File

@@ -1,8 +0,0 @@
namespace Semmle.Autobuild.CSharp
{
internal static class Constants
{
// The version number should be kept in sync with the version .NET version used for building the application.
public const string LatestDotNetSdkVersion = "8.0.101";
}
}

View File

@@ -5,7 +5,7 @@ using System.Linq;
using Semmle.Util;
using Semmle.Util.Logging;
using Semmle.Autobuild.Shared;
using Newtonsoft.Json.Linq;
using Semmle.Extraction.CSharp.DependencyFetching;
namespace Semmle.Autobuild.CSharp
{
@@ -39,11 +39,11 @@ namespace Semmle.Autobuild.CSharp
if (notDotNetProject is not null)
{
builder.Log(Severity.Info, "Not using .NET Core because of incompatible project {0}", notDotNetProject);
builder.Logger.Log(Severity.Info, "Not using .NET Core because of incompatible project {0}", notDotNetProject);
return BuildScript.Failure;
}
builder.Log(Severity.Info, "Attempting to build using .NET Core");
builder.Logger.LogInfo("Attempting to build using .NET Core");
}
return WithDotNet(builder, ensureDotNetAvailable: false, (dotNetPath, environment) =>
@@ -81,29 +81,22 @@ namespace Semmle.Autobuild.CSharp
/// </summary>
public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builder, bool ensureDotNetAvailable, Func<string?, IDictionary<string, string>?, BuildScript> f)
{
var installDir = builder.Actions.PathCombine(FileUtils.GetTemporaryWorkingDirectory(builder.Actions.GetEnvironmentVariable, builder.Options.Language.UpperCaseName, out var _), ".dotnet");
var installScript = DownloadDotNet(builder, installDir, ensureDotNetAvailable);
return BuildScript.Bind(installScript, installed =>
var temp = FileUtils.GetTemporaryWorkingDirectory(builder.Actions.GetEnvironmentVariable, builder.Options.Language.UpperCaseName, out var shouldCleanUp);
return DotNet.WithDotNet(builder.Actions, builder.Logger, builder.Paths.Select(x => x.Item1), temp, shouldCleanUp, ensureDotNetAvailable, builder.Options.DotNetVersion, installDir =>
{
var env = new Dictionary<string, string>
{
{ "DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true" },
{ "MSBUILDDISABLENODEREUSE", "1" }
};
if (installed == 0)
if (installDir is not null)
{
// The installation succeeded, so use the newly installed .NET Core
// The installation succeeded, so use the newly installed .NET
var path = builder.Actions.GetEnvironmentVariable("PATH");
var delim = builder.Actions.IsWindows() ? ";" : ":";
env.Add("DOTNET_MULTILEVEL_LOOKUP", "false"); // prevent look up of other .NET Core SDKs
env.Add("DOTNET_MULTILEVEL_LOOKUP", "false"); // prevent look up of other .NET SDKs
env.Add("PATH", installDir + delim + path);
}
else
{
// The .NET SDK was not installed, either because the installation failed or because it was already installed.
installDir = null;
}
return f(installDir, env);
});
}
@@ -119,146 +112,6 @@ namespace Semmle.Autobuild.CSharp
public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builder, Func<IDictionary<string, string>?, BuildScript> f)
=> WithDotNet(builder, ensureDotNetAvailable: false, (_, env) => f(env));
/// <summary>
/// Returns a script for downloading relevant versions of the
/// .NET Core SDK. The SDK(s) will be installed at <code>installDir</code>
/// (provided that the script succeeds).
/// </summary>
private static BuildScript DownloadDotNet(IAutobuilder<AutobuildOptionsShared> builder, string installDir, bool ensureDotNetAvailable)
{
if (!string.IsNullOrEmpty(builder.Options.DotNetVersion))
// Specific version supplied in configuration: always use that
return DownloadDotNetVersion(builder, installDir, builder.Options.DotNetVersion);
// Download versions mentioned in `global.json` files
// See https://docs.microsoft.com/en-us/dotnet/core/tools/global-json
var installScript = BuildScript.Success;
var validGlobalJson = false;
foreach (var path in builder.Paths.Select(p => p.Item1).Where(p => p.EndsWith("global.json", StringComparison.Ordinal)))
{
string version;
try
{
var o = JObject.Parse(File.ReadAllText(path));
version = (string)(o?["sdk"]?["version"]!);
}
catch // lgtm[cs/catch-of-all-exceptions]
{
// not a valid global.json file
continue;
}
installScript &= DownloadDotNetVersion(builder, installDir, version);
validGlobalJson = true;
}
if (validGlobalJson)
{
return installScript;
}
if (ensureDotNetAvailable)
{
return DownloadDotNetVersion(builder, installDir, Constants.LatestDotNetSdkVersion, needExactVersion: false);
}
return BuildScript.Failure;
}
/// <summary>
/// Returns a script for downloading a specific .NET Core SDK version, if the
/// version is not already installed.
///
/// See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script.
/// </summary>
private static BuildScript DownloadDotNetVersion(IAutobuilder<AutobuildOptionsShared> builder, string path, string version, bool needExactVersion = true)
{
return BuildScript.Bind(GetInstalledSdksScript(builder.Actions), (sdks, sdksRet) =>
{
if (needExactVersion && sdksRet == 0 && sdks.Count == 1 && sdks[0].StartsWith(version + " ", StringComparison.Ordinal))
{
// The requested SDK is already installed (and no other SDKs are installed), so
// no need to reinstall
return BuildScript.Failure;
}
else if (!needExactVersion && sdksRet == 0 && sdks.Count > 0)
{
// there's at least one SDK installed, so no need to reinstall
return BuildScript.Failure;
}
else if (!needExactVersion && sdksRet != 0)
{
builder.Log(Severity.Info, "No .NET Core SDK found.");
}
builder.Log(Severity.Info, "Attempting to download .NET Core {0}", version);
if (builder.Actions.IsWindows())
{
var psCommand = $"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; &([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://dot.net/v1/dotnet-install.ps1'))) -Version {version} -InstallDir {path}";
BuildScript GetInstall(string pwsh) =>
new CommandBuilder(builder.Actions).
RunCommand(pwsh).
Argument("-NoProfile").
Argument("-ExecutionPolicy").
Argument("unrestricted").
Argument("-Command").
Argument("\"" + psCommand + "\"").
Script;
return GetInstall("pwsh") | GetInstall("powershell");
}
else
{
var dotnetInstallPath = builder.Actions.PathCombine(FileUtils.GetTemporaryWorkingDirectory(
builder.Actions.GetEnvironmentVariable,
builder.Options.Language.UpperCaseName,
out var shouldCleanUp), ".dotnet", "dotnet-install.sh");
var downloadDotNetInstallSh = BuildScript.DownloadFile(
"https://dot.net/v1/dotnet-install.sh",
dotnetInstallPath,
e => builder.Log(Severity.Warning, $"Failed to download 'dotnet-install.sh': {e.Message}"));
var chmod = new CommandBuilder(builder.Actions).
RunCommand("chmod").
Argument("u+x").
Argument(dotnetInstallPath);
var install = new CommandBuilder(builder.Actions).
RunCommand(dotnetInstallPath).
Argument("--channel").
Argument("release").
Argument("--version").
Argument(version).
Argument("--install-dir").
Argument(path);
var buildScript = downloadDotNetInstallSh & chmod.Script & install.Script;
if (shouldCleanUp)
{
var removeScript = new CommandBuilder(builder.Actions).
RunCommand("rm").
Argument(dotnetInstallPath);
buildScript &= removeScript.Script;
}
return buildScript;
}
});
}
private static BuildScript GetInstalledSdksScript(IBuildActions actions)
{
var listSdks = new CommandBuilder(actions, silent: true).
RunCommand("dotnet").
Argument("--list-sdks");
return listSdks.Script;
}
private static string DotNetCommand(IBuildActions actions, string? dotNetPath) =>
dotNetPath is not null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet";

View File

@@ -20,6 +20,7 @@
<ItemGroup>
<ProjectReference Include="..\..\extractor\Semmle.Util\Semmle.Util.csproj" />
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp\Semmle.Extraction.CSharp.csproj" />
<ProjectReference Include="..\..\extractor\Semmle.Extraction.CSharp.DependencyFetching\Semmle.Extraction.CSharp.DependencyFetching.csproj" />
<ProjectReference Include="..\Semmle.Autobuild.Shared\Semmle.Autobuild.Shared.csproj" />
</ItemGroup>
</Project>

View File

@@ -8,13 +8,6 @@ namespace Semmle.Autobuild.CSharp
/// </summary>
internal class StandaloneBuildRule : IBuildRule<CSharpAutobuildOptions>
{
private readonly string? dotNetPath;
internal StandaloneBuildRule(string? dotNetPath)
{
this.dotNetPath = dotNetPath;
}
public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool auto)
{
if (builder.CodeQLExtractorLangRoot is null
@@ -27,12 +20,6 @@ namespace Semmle.Autobuild.CSharp
var cmd = new CommandBuilder(builder.Actions);
cmd.RunCommand(standalone);
if (!string.IsNullOrEmpty(this.dotNetPath))
{
cmd.Argument("--dotnet");
cmd.QuoteArgument(this.dotNetPath);
}
return cmd.Script;
}
}