Skip to content

Commit 976c627

Browse files
committed
C#: Download latest dotnet SDK when missing
1 parent 9ecac04 commit 976c627

File tree

3 files changed

+58
-35
lines changed

3 files changed

+58
-35
lines changed

csharp/autobuilder/Semmle.Autobuild.CSharp/CSharpAutobuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ public override BuildScript GetBuildScript()
5050
attempt = new BuildCommandRule(DotNetRule.WithDotNet).Analyse(this, false) & CheckExtractorRun(true);
5151
break;
5252
case CSharpBuildStrategy.Buildless:
53-
attempt = DotNetRule.WithDotNet(this, (dotNetPath, env) =>
53+
attempt = DotNetRule.WithDotNet(this, ensureDotNetAvailable: true, (dotNetPath, env) =>
5454
{
5555
// No need to check that the extractor has been executed in buildless mode
56-
return new StandaloneBuildRule(dotNetPath).Analyse(this, false);
56+
return new StandaloneBuildRule(dotNetPath, env).Analyse(this, false);
5757
});
5858
break;
5959
case CSharpBuildStrategy.MSBuild:

csharp/autobuilder/Semmle.Autobuild.CSharp/DotNetRule.cs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool au
4646
builder.Log(Severity.Info, "Attempting to build using .NET Core");
4747
}
4848

49-
return WithDotNet(builder, (dotNetPath, environment) =>
49+
return WithDotNet(builder, ensureDotNetAvailable: false, (dotNetPath, environment) =>
5050
{
5151
var ret = GetInfoCommand(builder.Actions, dotNetPath, environment);
5252
foreach (var projectOrSolution in builder.ProjectsOrSolutionsToBuild)
@@ -79,10 +79,10 @@ public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool au
7979
/// variables needed by the installed .NET Core (<code>null</code> when no variables
8080
/// are needed).
8181
/// </summary>
82-
public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builder, Func<string?, IDictionary<string, string>?, BuildScript> f)
82+
public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builder, bool ensureDotNetAvailable, Func<string?, IDictionary<string, string>?, BuildScript> f)
8383
{
8484
var installDir = builder.Actions.PathCombine(FileUtils.GetTemporaryWorkingDirectory(builder.Actions.GetEnvironmentVariable, builder.Options.Language.UpperCaseName, out var _), ".dotnet");
85-
var installScript = DownloadDotNet(builder, installDir);
85+
var installScript = DownloadDotNet(builder, installDir, ensureDotNetAvailable);
8686
return BuildScript.Bind(installScript, installed =>
8787
{
8888
Dictionary<string, string>? env;
@@ -100,8 +100,12 @@ public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builde
100100
}
101101
else
102102
{
103+
// The .NET SDK was not installed, either because the installation failed or because it was already installed.
103104
installDir = null;
104-
env = null;
105+
env = new Dictionary<string, string> {
106+
{ "DOTNET_SKIP_FIRST_TIME_EXPERIENCE", "true" },
107+
{ "MSBUILDDISABLENODEREUSE", "1" }
108+
};
105109
}
106110

107111
return f(installDir, env);
@@ -117,14 +121,14 @@ public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builde
117121
/// are needed).
118122
/// </summary>
119123
public static BuildScript WithDotNet(IAutobuilder<AutobuildOptionsShared> builder, Func<IDictionary<string, string>?, BuildScript> f)
120-
=> WithDotNet(builder, (_1, env) => f(env));
124+
=> WithDotNet(builder, ensureDotNetAvailable: false, (_, env) => f(env));
121125

122126
/// <summary>
123127
/// Returns a script for downloading relevant versions of the
124128
/// .NET Core SDK. The SDK(s) will be installed at <code>installDir</code>
125129
/// (provided that the script succeeds).
126130
/// </summary>
127-
private static BuildScript DownloadDotNet(IAutobuilder<AutobuildOptionsShared> builder, string installDir)
131+
private static BuildScript DownloadDotNet(IAutobuilder<AutobuildOptionsShared> builder, string installDir, bool ensureDotNetAvailable)
128132
{
129133
if (!string.IsNullOrEmpty(builder.Options.DotNetVersion))
130134
// Specific version supplied in configuration: always use that
@@ -152,7 +156,28 @@ private static BuildScript DownloadDotNet(IAutobuilder<AutobuildOptionsShared> b
152156
validGlobalJson = true;
153157
}
154158

155-
return validGlobalJson ? installScript : BuildScript.Failure;
159+
if (validGlobalJson)
160+
{
161+
return installScript;
162+
}
163+
164+
if (ensureDotNetAvailable)
165+
{
166+
return BuildScript.Bind(GetInfoScript(builder.Actions), (infoLines, infoRet) =>
167+
{
168+
if (infoRet == 0)
169+
{
170+
return BuildScript.Failure;
171+
}
172+
173+
const string latestDotNetSdkVersion = "8.0.101";
174+
builder.Log(Severity.Info, $"No .NET Core SDK found. Attempting to install version {latestDotNetSdkVersion}.");
175+
return DownloadDotNetVersion(builder, installDir, latestDotNetSdkVersion);
176+
});
177+
178+
}
179+
180+
return BuildScript.Failure;
156181
}
157182

158183
/// <summary>
@@ -238,6 +263,14 @@ private static BuildScript GetInstalledSdksScript(IBuildActions actions)
238263
return listSdks.Script;
239264
}
240265

266+
private static BuildScript GetInfoScript(IBuildActions actions)
267+
{
268+
var info = new CommandBuilder(actions, silent: true).
269+
RunCommand("dotnet").
270+
Argument("--info");
271+
return info.Script;
272+
}
273+
241274
private static string DotNetCommand(IBuildActions actions, string? dotNetPath) =>
242275
dotNetPath is not null ? actions.PathCombine(dotNetPath, "dotnet") : "dotnet";
243276

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Linq;
1+
using System.Collections.Generic;
22
using Semmle.Autobuild.Shared;
33

44
namespace Semmle.Autobuild.CSharp
@@ -9,44 +9,34 @@ namespace Semmle.Autobuild.CSharp
99
internal class StandaloneBuildRule : IBuildRule<CSharpAutobuildOptions>
1010
{
1111
private readonly string? dotNetPath;
12+
private readonly IDictionary<string, string>? env;
1213

13-
internal StandaloneBuildRule(string? dotNetPath)
14+
internal StandaloneBuildRule(string? dotNetPath, IDictionary<string, string>? env)
1415
{
1516
this.dotNetPath = dotNetPath;
17+
this.env = env;
1618
}
1719

1820
public BuildScript Analyse(IAutobuilder<CSharpAutobuildOptions> builder, bool auto)
1921
{
20-
BuildScript GetCommand()
22+
if (!builder.Options.Buildless
23+
|| builder.CodeQLExtractorLangRoot is null
24+
|| builder.CodeQlPlatform is null)
2125
{
22-
string standalone;
23-
if (builder.CodeQLExtractorLangRoot is not null && builder.CodeQlPlatform is not null)
24-
{
25-
standalone = builder.Actions.PathCombine(builder.CodeQLExtractorLangRoot, "tools", builder.CodeQlPlatform, "Semmle.Extraction.CSharp.Standalone");
26-
}
27-
else
28-
{
29-
return BuildScript.Failure;
30-
}
31-
32-
var cmd = new CommandBuilder(builder.Actions);
33-
cmd.RunCommand(standalone);
34-
35-
if (!string.IsNullOrEmpty(this.dotNetPath))
36-
{
37-
cmd.Argument("--dotnet");
38-
cmd.QuoteArgument(this.dotNetPath);
39-
}
40-
41-
return cmd.Script;
26+
return BuildScript.Failure;
4227
}
4328

44-
if (!builder.Options.Buildless)
29+
var standalone = builder.Actions.PathCombine(builder.CodeQLExtractorLangRoot, "tools", builder.CodeQlPlatform, "Semmle.Extraction.CSharp.Standalone");
30+
var cmd = new CommandBuilder(builder.Actions, environment: this.env);
31+
cmd.RunCommand(standalone);
32+
33+
if (!string.IsNullOrEmpty(this.dotNetPath))
4534
{
46-
return BuildScript.Failure;
35+
cmd.Argument("--dotnet");
36+
cmd.QuoteArgument(this.dotNetPath);
4737
}
4838

49-
return GetCommand();
39+
return cmd.Script;
5040
}
5141
}
5242
}

0 commit comments

Comments
 (0)