C#: Download latest dotnet SDK when missing

This commit is contained in:
Tamas Vajk
2024-02-22 12:07:15 +01:00
parent 9ecac04709
commit 976c627d52
3 changed files with 60 additions and 37 deletions

View File

@@ -50,10 +50,10 @@ namespace Semmle.Autobuild.CSharp
attempt = new BuildCommandRule(DotNetRule.WithDotNet).Analyse(this, false) & CheckExtractorRun(true);
break;
case CSharpBuildStrategy.Buildless:
attempt = DotNetRule.WithDotNet(this, (dotNetPath, env) =>
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);
return new StandaloneBuildRule(dotNetPath, env).Analyse(this, false);
});
break;
case CSharpBuildStrategy.MSBuild:

View File

@@ -46,7 +46,7 @@ namespace Semmle.Autobuild.CSharp
builder.Log(Severity.Info, "Attempting to build using .NET Core");
}
return WithDotNet(builder, (dotNetPath, environment) =>
return WithDotNet(builder, ensureDotNetAvailable: false, (dotNetPath, environment) =>
{
var ret = GetInfoCommand(builder.Actions, dotNetPath, environment);
foreach (var projectOrSolution in builder.ProjectsOrSolutionsToBuild)
@@ -79,10 +79,10 @@ namespace Semmle.Autobuild.CSharp
/// variables needed by the installed .NET Core (<code>null</code> when no variables
/// are needed).
/// </summary>
public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builder, Func<string?, IDictionary<string, string>?, BuildScript> f)
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);
var installScript = DownloadDotNet(builder, installDir, ensureDotNetAvailable);
return BuildScript.Bind(installScript, installed =>
{
Dictionary<string, string>? env;
@@ -100,8 +100,12 @@ namespace Semmle.Autobuild.CSharp
}
else
{
// The .NET SDK was not installed, either because the installation failed or because it was already installed.
installDir = null;
env = null;
env = new Dictionary<string, string> {
{ "DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true" },
{ "MSBUILDDISABLENODEREUSE", "1" }
};
}
return f(installDir, env);
@@ -117,14 +121,14 @@ namespace Semmle.Autobuild.CSharp
/// are needed).
/// </summary>
public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builder, Func<IDictionary<string, string>?, BuildScript> f)
=> WithDotNet(builder, (_1, env) => f(env));
=> 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)
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
@@ -152,7 +156,28 @@ namespace Semmle.Autobuild.CSharp
validGlobalJson = true;
}
return validGlobalJson ? installScript : BuildScript.Failure;
if (validGlobalJson)
{
return installScript;
}
if (ensureDotNetAvailable)
{
return BuildScript.Bind(GetInfoScript(builder.Actions), (infoLines, infoRet) =>
{
if (infoRet == 0)
{
return BuildScript.Failure;
}
const string latestDotNetSdkVersion = "8.0.101";
builder.Log(Severity.Info, $"No .NET Core SDK found. Attempting to install version {latestDotNetSdkVersion}.");
return DownloadDotNetVersion(builder, installDir, latestDotNetSdkVersion);
});
}
return BuildScript.Failure;
}
/// <summary>
@@ -238,6 +263,14 @@ namespace Semmle.Autobuild.CSharp
return listSdks.Script;
}
private static BuildScript GetInfoScript(IBuildActions actions)
{
var info = new CommandBuilder(actions, silent: true).
RunCommand("dotnet").
Argument("--info");
return info.Script;
}
private static string DotNetCommand(IBuildActions actions, string? dotNetPath) =>
dotNetPath is not null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet";

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System.Collections.Generic;
using Semmle.Autobuild.Shared;
namespace Semmle.Autobuild.CSharp
@@ -9,44 +9,34 @@ namespace Semmle.Autobuild.CSharp
internal class StandaloneBuildRule : IBuildRule<CSharpAutobuildOptions>
{
private readonly string? dotNetPath;
private readonly IDictionary<string, string>? env;
internal StandaloneBuildRule(string? dotNetPath)
internal StandaloneBuildRule(string? dotNetPath, IDictionary<string, string>? env)
{
this.dotNetPath = dotNetPath;
this.env = env;
}
public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool auto)
{
BuildScript GetCommand()
{
string standalone;
if (builder.CodeQLExtractorLangRoot is not null && builder.CodeQlPlatform is not null)
{
standalone = builder.Actions.PathCombine(builder.CodeQLExtractorLangRoot, "tools", builder.CodeQlPlatform, "Semmle.Extraction.CSharp.Standalone");
}
else
{
return BuildScript.Failure;
}
var cmd = new CommandBuilder(builder.Actions);
cmd.RunCommand(standalone);
if (!string.IsNullOrEmpty(this.dotNetPath))
{
cmd.Argument("--dotnet");
cmd.QuoteArgument(this.dotNetPath);
}
return cmd.Script;
}
if (!builder.Options.Buildless)
if (!builder.Options.Buildless
|| builder.CodeQLExtractorLangRoot is null
|| builder.CodeQlPlatform is null)
{
return BuildScript.Failure;
}
return GetCommand();
var standalone = builder.Actions.PathCombine(builder.CodeQLExtractorLangRoot, "tools", builder.CodeQlPlatform, "Semmle.Extraction.CSharp.Standalone");
var cmd = new CommandBuilder(builder.Actions, environment: this.env);
cmd.RunCommand(standalone);
if (!string.IsNullOrEmpty(this.dotNetPath))
{
cmd.Argument("--dotnet");
cmd.QuoteArgument(this.dotNetPath);
}
return cmd.Script;
}
}
}