Skip to content

Commit 2e8c949

Browse files
nohwndmmitche
andauthored
Quickly check if runtime is installed (#16580)
Co-authored-by: Matt Mitchell <mmitche@microsoft.com>
1 parent 97f5d8a commit 2e8c949

4 files changed

Lines changed: 63 additions & 3 deletions

File tree

eng/common/tools.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,8 @@ function InstallDotNet([string] $dotnetRoot,
295295

296296
$dotnetVersionLabel = "'sdk v$version'"
297297

298+
# For performance this check is duplicated in src/Microsoft.DotNet.Arcade.Sdk/src/InstallDotNetCore.cs
299+
# if you are making changes here, consider if you need to make changes there as well.
298300
if ($runtime -ne '' -and $runtime -ne 'sdk') {
299301
$runtimePath = $dotnetRoot
300302
$runtimePath = $runtimePath + "\shared"

eng/common/tools.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ function InstallDotNet {
184184
local version=$2
185185
local runtime=$4
186186

187+
# For performance this check is duplicated in src/Microsoft.DotNet.Arcade.Sdk/src/InstallDotNetCore.cs
188+
# if you are making changes here, consider if you need to make changes there as well.
187189
local dotnetVersionLabel="'$runtime v$version'"
188190
if [[ -n "${4:-}" ]] && [ "$4" != 'sdk' ]; then
189191
runtimePath="$root"

src/Microsoft.DotNet.Arcade.Sdk/src/InstallDotNetCore.cs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class InstallDotNetCore : AppDomainIsolatedTask
2525
public class InstallDotNetCore : Microsoft.Build.Utilities.Task
2626
{
2727
#endif
28-
private static readonly char[] s_keyTrimChars = [ '$', '(', ')' ];
28+
private static readonly char[] s_keyTrimChars = ['$', '(', ')'];
2929

3030
public string VersionsPropsPath { get; set; }
3131

@@ -34,10 +34,12 @@ public class InstallDotNetCore : Microsoft.Build.Utilities.Task
3434
[Required]
3535
public string GlobalJsonPath { get; set; }
3636
[Required]
37+
public string DotNetPath { get; set; }
38+
[Required]
3739
public string Platform { get; set; }
3840

3941
public string RuntimeSourceFeed { get; set; }
40-
42+
4143
public string RuntimeSourceFeedKey { get; set; }
4244

4345
public override bool Execute()
@@ -125,7 +127,9 @@ public override bool Execute()
125127

126128
if (version != null)
127129
{
128-
string arguments = $"-runtime \"{runtimeItem.Key}\" -version \"{version.ToNormalizedString()}\"";
130+
string normalizedVersion = version.ToNormalizedString();
131+
string runtime = runtimeItem.Key;
132+
string arguments = $"-runtime \"{runtime}\" -version \"{normalizedVersion}\"";
129133
if (!string.IsNullOrEmpty(architecture))
130134
{
131135
arguments += $" -architecture {architecture}";
@@ -142,6 +146,20 @@ public override bool Execute()
142146
arguments += $" -runtimeSourceFeedKey {RuntimeSourceFeedKey}";
143147
}
144148

149+
// Null architecture means that the script should infer it, we don't want to re-implement too much logic here,
150+
// so we skip the quick check.
151+
if (architecture != null)
152+
{
153+
// Quickly check if the runtime is already installed, skipping double process hop,
154+
// load of powershell, and load of tools.sh, or similar overhead for shell script.
155+
// Saving about 1 second per runtime.
156+
if (CheckRuntimeDotnetInstalled(DotNetPath, normalizedVersion, architecture, runtime))
157+
158+
{
159+
continue;
160+
}
161+
}
162+
145163
Log.LogMessage(MessageImportance.Low, $"Executing: {DotNetInstallScript} {arguments}");
146164
var process = Process.Start(new ProcessStartInfo()
147165
{
@@ -228,5 +246,42 @@ private IEnumerable<KeyValuePair<string, string>> GetItemsFromJsonElementArray(J
228246
}
229247
return items.ToArray();
230248
}
249+
250+
private static bool CheckRuntimeDotnetInstalled(
251+
string dotnetRoot,
252+
string version,
253+
string architecture,
254+
string runtime)
255+
{
256+
// For performance this check is duplicated from InstallDotnet in tools.sh and tools.ps1
257+
// if you are making changes here, consider if you need to make changes there as well.
258+
if (string.IsNullOrEmpty(runtime) && runtime == "sdk")
259+
{
260+
throw new ArgumentException($"{nameof(InstallDotNetCore)} cannot be used for .NET SDK installation.");
261+
}
262+
263+
if (!string.Equals(architecture, RuntimeInformation.OSArchitecture.ToString(), StringComparison.OrdinalIgnoreCase))
264+
{
265+
// This istallation is not native to this OS, it will be installed into a subfolder with the architecture name.
266+
// See eng/common/dotnet-install.sh and eng/common/dotnet-install.ps1
267+
dotnetRoot = Path.Combine(dotnetRoot, architecture.ToLowerInvariant());
268+
}
269+
270+
string runtimePath = runtime switch
271+
{
272+
"dotnet" => Path.Combine(dotnetRoot, "shared", "Microsoft.NETCore.App", version),
273+
"aspnetcore" => Path.Combine(dotnetRoot, "shared", "Microsoft.AspNetCore.App", version),
274+
"windowsdesktop" => Path.Combine(dotnetRoot, "shared", "Microsoft.WindowsDesktop.App", version),
275+
_ => Path.Combine(dotnetRoot, "shared", version)
276+
};
277+
278+
if (Directory.Exists(runtimePath))
279+
{
280+
Console.WriteLine($" Runtime toolset '{runtime}/{architecture} v{version}' already installed in directory '{runtimePath}'.");
281+
return true;
282+
}
283+
284+
return false;
285+
}
231286
}
232287
}

src/Microsoft.DotNet.Arcade.Sdk/tools/InstallDotNetCore.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<InstallDotNetCore
1717
VersionsPropsPath="$(RepositoryEngineeringDir)Versions.props"
1818
GlobalJsonPath="$(RepoRoot)global.json"
19+
DotNetPath ="$(RepoRoot).dotnet"
1920
DotNetInstallScript="$(_DotNetInstallScript)"
2021
Platform="$(Platform)"
2122
RuntimeSourceFeed="$(DotNetRuntimeSourceFeed)"

0 commit comments

Comments
 (0)