Skip to content

Commit 5fe0c78

Browse files
authored
Change .NET SDK Validator to account for backwards compatibility (#2645)
1 parent adf8e6d commit 5fe0c78

File tree

1 file changed

+66
-51
lines changed

1 file changed

+66
-51
lines changed

src/BenchmarkDotNet/Validators/DotNetSdkVersionValidator.cs

Lines changed: 66 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,28 @@ public static IEnumerable<ValidationError> ValidateCoreSdks(string? customDotNet
2121
{
2222
yield return cliPathError;
2323
}
24-
else if (TryGetSdkVersion(benchmark, out string requiredSdkVersion))
24+
else if (TryGetSdkVersion(benchmark, out Version requiredSdkVersion))
2525
{
2626
var installedSdks = GetInstalledDotNetSdks(customDotNetCliPath);
27-
if (!installedSdks.Any(sdk => sdk.StartsWith(requiredSdkVersion)))
27+
if (!installedSdks.Any(sdk => sdk >= requiredSdkVersion))
2828
{
29-
yield return new ValidationError(true, $"The required .NET Core SDK version {requiredSdkVersion} for runtime moniker {benchmark.Job.Environment.Runtime.RuntimeMoniker} is not installed.", benchmark);
29+
yield return new ValidationError(true, $"The required .NET Core SDK version {requiredSdkVersion} or higher for runtime moniker {benchmark.Job.Environment.Runtime.RuntimeMoniker} is not installed.", benchmark);
3030
}
3131
}
3232
}
3333

3434
public static IEnumerable<ValidationError> ValidateFrameworkSdks(BenchmarkCase benchmark)
3535
{
36-
if (!TryGetSdkVersion(benchmark, out string requiredSdkVersionString))
36+
if (!TryGetSdkVersion(benchmark, out Version requiredSdkVersion))
3737
{
3838
yield break;
3939
}
4040

41-
if (!Version.TryParse(requiredSdkVersionString, out var requiredSdkVersion))
42-
{
43-
yield return new ValidationError(true, $"Invalid .NET Framework SDK version format: {requiredSdkVersionString}", benchmark);
44-
yield break;
45-
}
46-
4741
var installedVersionString = cachedFrameworkSdks.Value.FirstOrDefault();
4842

4943
if (installedVersionString == null || Version.TryParse(installedVersionString, out var installedVersion) && installedVersion < requiredSdkVersion)
5044
{
51-
yield return new ValidationError(true, $"The required .NET Framework SDK version {requiredSdkVersionString} or higher is not installed.", benchmark);
45+
yield return new ValidationError(true, $"The required .NET Framework SDK version {requiredSdkVersion} or higher is not installed.", benchmark);
5246
}
5347
}
5448

@@ -77,9 +71,9 @@ public static bool IsCliPathInvalid(string customDotNetCliPath, BenchmarkCase be
7771
return false;
7872
}
7973

80-
private static bool TryGetSdkVersion(BenchmarkCase benchmark, out string sdkVersion)
74+
private static bool TryGetSdkVersion(BenchmarkCase benchmark, out Version sdkVersion)
8175
{
82-
sdkVersion = string.Empty;
76+
sdkVersion = default;
8377
if (benchmark?.Job?.Environment?.Runtime?.RuntimeMoniker != null)
8478
{
8579
sdkVersion = GetSdkVersionFromMoniker(benchmark.Job.Environment.Runtime.RuntimeMoniker);
@@ -88,7 +82,7 @@ private static bool TryGetSdkVersion(BenchmarkCase benchmark, out string sdkVers
8882
return false;
8983
}
9084

91-
private static IEnumerable<string> GetInstalledDotNetSdks(string? customDotNetCliPath)
85+
private static IEnumerable<Version> GetInstalledDotNetSdks(string? customDotNetCliPath)
9286
{
9387
string dotnetExecutable = string.IsNullOrEmpty(customDotNetCliPath) ? "dotnet" : customDotNetCliPath;
9488
var startInfo = new ProcessStartInfo(dotnetExecutable, "--list-sdks")
@@ -104,7 +98,7 @@ private static IEnumerable<string> GetInstalledDotNetSdks(string? customDotNetCl
10498
{
10599
if (process == null)
106100
{
107-
return Enumerable.Empty<string>();
101+
return Enumerable.Empty<Version>();
108102
}
109103

110104
process.WaitForExit();
@@ -113,17 +107,38 @@ private static IEnumerable<string> GetInstalledDotNetSdks(string? customDotNetCl
113107
{
114108
var output = process.StandardOutput.ReadToEnd();
115109
var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
116-
return lines.Select(line => line.Split(' ')[0]); // The SDK version is the first part of each line.
110+
111+
var versions = new List<Version>(lines.Count());
112+
foreach (var line in lines)
113+
{
114+
// Each line will start with the SDK version followed by the SDK path. Since we only support
115+
// targeting SDK versions by the major version, we'll just look at extracting the major and
116+
// minor versions. This is done by looking for the first two dots in the line.
117+
var firstDot = line.IndexOf('.');
118+
if (firstDot < 0)
119+
continue;
120+
121+
var secondDot = line.IndexOf('.', firstDot + 1);
122+
if (secondDot < 0)
123+
continue;
124+
125+
if (Version.TryParse(line.Substring(0, secondDot), out var version))
126+
{
127+
versions.Add(version);
128+
}
129+
}
130+
131+
return versions;
117132
}
118133
else
119134
{
120-
return Enumerable.Empty<string>();
135+
return Enumerable.Empty<Version>();
121136
}
122137
}
123138
}
124139
catch (Win32Exception) // dotnet CLI is not installed or not found in the path.
125140
{
126-
return Enumerable.Empty<string>();
141+
return Enumerable.Empty<Version>();
127142
}
128143
}
129144

@@ -193,42 +208,42 @@ private static string CheckFor45PlusVersion(int releaseKey)
193208
return "";
194209
}
195210

196-
private static string GetSdkVersionFromMoniker(RuntimeMoniker runtimeMoniker)
211+
private static Version GetSdkVersionFromMoniker(RuntimeMoniker runtimeMoniker)
197212
{
198213
return runtimeMoniker switch
199214
{
200-
RuntimeMoniker.Net461 => "4.6.1",
201-
RuntimeMoniker.Net462 => "4.6.2",
202-
RuntimeMoniker.Net47 => "4.7",
203-
RuntimeMoniker.Net471 => "4.7.1",
204-
RuntimeMoniker.Net472 => "4.7.2",
205-
RuntimeMoniker.Net48 => "4.8",
206-
RuntimeMoniker.Net481 => "4.8.1",
207-
RuntimeMoniker.NetCoreApp31 => "3.1",
208-
RuntimeMoniker.Net50 => "5.0",
209-
RuntimeMoniker.Net60 => "6.0",
210-
RuntimeMoniker.Net70 => "7.0",
211-
RuntimeMoniker.Net80 => "8.0",
212-
RuntimeMoniker.Net90 => "9.0",
213-
RuntimeMoniker.NativeAot60 => "6.0",
214-
RuntimeMoniker.NativeAot70 => "7.0",
215-
RuntimeMoniker.NativeAot80 => "8.0",
216-
RuntimeMoniker.NativeAot90 => "9.0",
217-
RuntimeMoniker.Mono60 => "6.0",
218-
RuntimeMoniker.Mono70 => "7.0",
219-
RuntimeMoniker.Mono80 => "8.0",
220-
RuntimeMoniker.Mono90 => "9.0",
221-
RuntimeMoniker.Wasm => Portability.RuntimeInformation.IsNetCore && CoreRuntime.TryGetVersion(out var version) ? $"{version.Major}.{version.Minor}" : "5.0",
222-
RuntimeMoniker.WasmNet50 => "5.0",
223-
RuntimeMoniker.WasmNet60 => "6.0",
224-
RuntimeMoniker.WasmNet70 => "7.0",
225-
RuntimeMoniker.WasmNet80 => "8.0",
226-
RuntimeMoniker.WasmNet90 => "9.0",
227-
RuntimeMoniker.MonoAOTLLVM => Portability.RuntimeInformation.IsNetCore && CoreRuntime.TryGetVersion(out var version) ? $"{version.Major}.{version.Minor}" : "6.0",
228-
RuntimeMoniker.MonoAOTLLVMNet60 => "6.0",
229-
RuntimeMoniker.MonoAOTLLVMNet70 => "7.0",
230-
RuntimeMoniker.MonoAOTLLVMNet80 => "8.0",
231-
RuntimeMoniker.MonoAOTLLVMNet90 => "9.0",
215+
RuntimeMoniker.Net461 => new Version(4, 6, 1),
216+
RuntimeMoniker.Net462 => new Version(4, 6, 2),
217+
RuntimeMoniker.Net47 => new Version(4, 7),
218+
RuntimeMoniker.Net471 => new Version(4, 7, 1),
219+
RuntimeMoniker.Net472 => new Version(4, 7, 2),
220+
RuntimeMoniker.Net48 => new Version(4, 8),
221+
RuntimeMoniker.Net481 => new Version(4, 8, 1),
222+
RuntimeMoniker.NetCoreApp31 => new Version(3, 1),
223+
RuntimeMoniker.Net50 => new Version(5, 0),
224+
RuntimeMoniker.Net60 => new Version(6, 0),
225+
RuntimeMoniker.Net70 => new Version(7, 0),
226+
RuntimeMoniker.Net80 => new Version(8, 0),
227+
RuntimeMoniker.Net90 => new Version(9, 0),
228+
RuntimeMoniker.NativeAot60 => new Version(6, 0),
229+
RuntimeMoniker.NativeAot70 => new Version(7, 0),
230+
RuntimeMoniker.NativeAot80 => new Version(8, 0),
231+
RuntimeMoniker.NativeAot90 => new Version(9, 0),
232+
RuntimeMoniker.Mono60 => new Version(6, 0),
233+
RuntimeMoniker.Mono70 => new Version(7, 0),
234+
RuntimeMoniker.Mono80 => new Version(8, 0),
235+
RuntimeMoniker.Mono90 => new Version(9, 0),
236+
RuntimeMoniker.Wasm => Portability.RuntimeInformation.IsNetCore && CoreRuntime.TryGetVersion(out var version) ? version : new Version(5, 0),
237+
RuntimeMoniker.WasmNet50 => new Version(5, 0),
238+
RuntimeMoniker.WasmNet60 => new Version(6, 0),
239+
RuntimeMoniker.WasmNet70 => new Version(7, 0),
240+
RuntimeMoniker.WasmNet80 => new Version(8, 0),
241+
RuntimeMoniker.WasmNet90 => new Version(9, 0),
242+
RuntimeMoniker.MonoAOTLLVM => Portability.RuntimeInformation.IsNetCore && CoreRuntime.TryGetVersion(out var version) ? version : new Version(6, 0),
243+
RuntimeMoniker.MonoAOTLLVMNet60 => new Version(6, 0),
244+
RuntimeMoniker.MonoAOTLLVMNet70 => new Version(7, 0),
245+
RuntimeMoniker.MonoAOTLLVMNet80 => new Version(8, 0),
246+
RuntimeMoniker.MonoAOTLLVMNet90 => new Version(9, 0),
232247
_ => throw new NotImplementedException($"SDK version check not implemented for {runtimeMoniker}")
233248
};
234249
}

0 commit comments

Comments
 (0)