Merge pull request #6646 from livarcocc/min_version_resolver
Add a min version check to the resolver
This commit is contained in:
commit
96ff9a3223
7 changed files with 372 additions and 4 deletions
129
src/Microsoft.DotNet.MSBuildSdkResolver/FXVersion.cs
Normal file
129
src/Microsoft.DotNet.MSBuildSdkResolver/FXVersion.cs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
|
{
|
||||||
|
// Note: This is not SemVer (esp., in comparing pre-release part, fx_ver_t does not
|
||||||
|
// compare multiple dot separated identifiers individually.) ex: 1.0.0-beta.2 vs. 1.0.0-beta.11
|
||||||
|
// See the original version of this code here: https://github.com/dotnet/core-setup/blob/master/src/corehost/cli/fxr/fx_ver.cpp
|
||||||
|
internal sealed class FXVersion
|
||||||
|
{
|
||||||
|
public int Major { get; }
|
||||||
|
public int Minor { get; }
|
||||||
|
public int Patch { get; }
|
||||||
|
public string Pre { get; }
|
||||||
|
public string Build { get; }
|
||||||
|
|
||||||
|
public FXVersion(int major, int minor, int patch, string pre = "", string build = "")
|
||||||
|
{
|
||||||
|
Major = major;
|
||||||
|
Minor = minor;
|
||||||
|
Patch = patch;
|
||||||
|
Pre = pre;
|
||||||
|
Build = build;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Compare(FXVersion s1, FXVersion s2)
|
||||||
|
{
|
||||||
|
if (s1.Major != s2.Major)
|
||||||
|
{
|
||||||
|
return s1.Major > s2.Major ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s1.Minor != s2.Minor)
|
||||||
|
{
|
||||||
|
return s1.Minor > s2.Minor ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s1.Patch != s2.Patch)
|
||||||
|
{
|
||||||
|
return s1.Patch > s2.Patch ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(s1.Pre) != string.IsNullOrEmpty(s2.Pre))
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(s1.Pre) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int preCompare = string.CompareOrdinal(s1.Pre, s2.Pre);
|
||||||
|
if (preCompare != 0)
|
||||||
|
{
|
||||||
|
return preCompare;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.CompareOrdinal(s1.Build, s2.Build);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(string fxVersionString, out FXVersion FXVersion)
|
||||||
|
{
|
||||||
|
FXVersion = null;
|
||||||
|
if (string.IsNullOrEmpty(fxVersionString))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int majorSeparator = fxVersionString.IndexOf(".");
|
||||||
|
if (majorSeparator == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int major = 0;
|
||||||
|
if (!int.TryParse(fxVersionString.Substring(0, majorSeparator), out major))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minorStart = majorSeparator + 1;
|
||||||
|
int minorSeparator = fxVersionString.IndexOf(".", minorStart);
|
||||||
|
if (minorSeparator == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minor = 0;
|
||||||
|
if (!int.TryParse(fxVersionString.Substring(minorStart, minorSeparator - minorStart), out minor))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int patch = 0;
|
||||||
|
int patchStart = minorSeparator + 1;
|
||||||
|
int patchSeparator = fxVersionString.FindFirstNotOf("0123456789", patchStart);
|
||||||
|
if (patchSeparator == -1)
|
||||||
|
{
|
||||||
|
if (!int.TryParse(fxVersionString.Substring(patchStart), out patch))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FXVersion = new FXVersion(major, minor, patch);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(fxVersionString.Substring(patchStart, patchSeparator - patchStart), out patch))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int preStart = patchSeparator;
|
||||||
|
int preSeparator = fxVersionString.IndexOf("+", preStart);
|
||||||
|
if (preSeparator == -1)
|
||||||
|
{
|
||||||
|
FXVersion = new FXVersion(major, minor, patch, fxVersionString.Substring(preStart));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int buildStart = preSeparator + 1;
|
||||||
|
FXVersion = new FXVersion(
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
patch,
|
||||||
|
fxVersionString.Substring(preStart, preSeparator - preStart),
|
||||||
|
fxVersionString.Substring(buildStart));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,6 +53,19 @@ namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
netcoreSdkVersion = new DirectoryInfo(netcoreSdkDir).Name;;
|
netcoreSdkVersion = new DirectoryInfo(netcoreSdkDir).Name;;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IsNetCoreSDKOveridden(netcoreSdkVersion) &&
|
||||||
|
IsNetCoreSDKSmallerThanTheMinimumVersion(netcoreSdkVersion, sdkReference.MinimumVersion))
|
||||||
|
{
|
||||||
|
return factory.IndicateFailure(
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
$"Version {netcoreSdkVersion} of the SDK is smaller than the minimum version"
|
||||||
|
+ $" {sdkReference.MinimumVersion} requested. Check that a recent enough .NET Core SDK is"
|
||||||
|
+ " installed, increase the minimum version specified in the project, or increase"
|
||||||
|
+ " the version specified in global.json."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
string msbuildSdkDir = Path.Combine(msbuildSdksDir, sdkReference.Name, "Sdk");
|
string msbuildSdkDir = Path.Combine(msbuildSdksDir, sdkReference.Name, "Sdk");
|
||||||
if (!Directory.Exists(msbuildSdkDir))
|
if (!Directory.Exists(msbuildSdkDir))
|
||||||
{
|
{
|
||||||
|
@ -60,13 +73,37 @@ namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
$"{msbuildSdkDir} not found. Check that a recent enough .NET Core SDK is installed"
|
$"{msbuildSdkDir} not found. Check that a recent enough .NET Core SDK is installed"
|
||||||
+ " and/or increase the version specified in global.json. "
|
+ " and/or increase the version specified in global.json."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return factory.IndicateSuccess(msbuildSdkDir, netcoreSdkVersion);
|
return factory.IndicateSuccess(msbuildSdkDir, netcoreSdkVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsNetCoreSDKOveridden(string netcoreSdkVersion)
|
||||||
|
{
|
||||||
|
return netcoreSdkVersion == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsNetCoreSDKSmallerThanTheMinimumVersion(string netcoreSdkVersion, string minimumVersion)
|
||||||
|
{
|
||||||
|
FXVersion netCoreSdkFXVersion;
|
||||||
|
FXVersion minimumFXVersion;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(minimumVersion))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FXVersion.TryParse(netcoreSdkVersion, out netCoreSdkFXVersion) ||
|
||||||
|
!FXVersion.TryParse(minimumVersion, out minimumFXVersion))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FXVersion.Compare(netCoreSdkFXVersion, minimumFXVersion) == -1;
|
||||||
|
}
|
||||||
|
|
||||||
private string ResolveNetcoreSdkDirectory(SdkResolverContext context)
|
private string ResolveNetcoreSdkDirectory(SdkResolverContext context)
|
||||||
{
|
{
|
||||||
foreach (string exeDir in GetDotnetExeDirectoryCandidates())
|
foreach (string exeDir in GetDotnetExeDirectoryCandidates())
|
||||||
|
|
15
src/Microsoft.DotNet.MSBuildSdkResolver/StringExtensions.cs
Normal file
15
src/Microsoft.DotNet.MSBuildSdkResolver/StringExtensions.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace Microsoft.DotNet.MSBuildSdkResolver
|
||||||
|
{
|
||||||
|
internal static class StringExtensions
|
||||||
|
{
|
||||||
|
public static int FindFirstNotOf(this string s, string chars, int startIndex)
|
||||||
|
{
|
||||||
|
for (int i = startIndex; i < s.Length; i++)
|
||||||
|
{
|
||||||
|
if (chars.IndexOf(s[i]) == -1) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,13 +47,72 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
new MockContext { ProjectFilePath = environment.TestDirectory.FullName },
|
new MockContext { ProjectFilePath = environment.TestDirectory.FullName },
|
||||||
new MockFactory());
|
new MockFactory());
|
||||||
|
|
||||||
result.Success.Should().Be(true);
|
result.Success.Should().BeTrue();
|
||||||
result.Path.Should().Be(expected.FullName);
|
result.Path.Should().Be(expected.FullName);
|
||||||
result.Version.Should().Be("99.99.98");
|
result.Version.Should().Be("99.99.98");
|
||||||
result.Warnings.Should().BeNullOrEmpty();
|
result.Warnings.Should().BeNullOrEmpty();
|
||||||
result.Errors.Should().BeNullOrEmpty();
|
result.Errors.Should().BeNullOrEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ItReturnsNullIfTheVersionFoundDoesNotSatisfyTheMinVersion()
|
||||||
|
{
|
||||||
|
var environment = new TestEnvironment();
|
||||||
|
environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
||||||
|
|
||||||
|
var resolver = environment.CreateResolver();
|
||||||
|
var result = (MockResult)resolver.Resolve(
|
||||||
|
new SdkReference("Some.Test.Sdk", null, "999.99.99"),
|
||||||
|
new MockContext { ProjectFilePath = environment.TestDirectory.FullName },
|
||||||
|
new MockFactory());
|
||||||
|
|
||||||
|
result.Success.Should().BeFalse();
|
||||||
|
result.Path.Should().BeNull();
|
||||||
|
result.Version.Should().BeNull();
|
||||||
|
result.Warnings.Should().BeNullOrEmpty();
|
||||||
|
result.Errors.Should().Contain("Version 99.99.99 of the SDK is smaller than the minimum version 999.99.99"
|
||||||
|
+ " requested. Check that a recent enough .NET Core SDK is installed, increase the minimum version"
|
||||||
|
+ " specified in the project, or increase the version specified in global.json.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ItReturnsTheVersionIfItIsEqualToTheMinVersion()
|
||||||
|
{
|
||||||
|
var environment = new TestEnvironment();
|
||||||
|
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "99.99.99");
|
||||||
|
|
||||||
|
var resolver = environment.CreateResolver();
|
||||||
|
var result = (MockResult)resolver.Resolve(
|
||||||
|
new SdkReference("Some.Test.Sdk", null, "99.99.99"),
|
||||||
|
new MockContext { ProjectFilePath = environment.TestDirectory.FullName },
|
||||||
|
new MockFactory());
|
||||||
|
|
||||||
|
result.Success.Should().BeTrue();
|
||||||
|
result.Path.Should().Be(expected.FullName);
|
||||||
|
result.Version.Should().Be("99.99.99");
|
||||||
|
result.Warnings.Should().BeNullOrEmpty();
|
||||||
|
result.Errors.Should().BeNullOrEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ItReturnsTheVersionIfItIsHigherThanTheMinVersion()
|
||||||
|
{
|
||||||
|
var environment = new TestEnvironment();
|
||||||
|
var expected = environment.CreateSdkDirectory(ProgramFiles.X64, "Some.Test.Sdk", "999.99.99");
|
||||||
|
|
||||||
|
var resolver = environment.CreateResolver();
|
||||||
|
var result = (MockResult)resolver.Resolve(
|
||||||
|
new SdkReference("Some.Test.Sdk", null, "99.99.99"),
|
||||||
|
new MockContext { ProjectFilePath = environment.TestDirectory.FullName },
|
||||||
|
new MockFactory());
|
||||||
|
|
||||||
|
result.Success.Should().BeTrue();
|
||||||
|
result.Path.Should().Be(expected.FullName);
|
||||||
|
result.Version.Should().Be("999.99.99");
|
||||||
|
result.Warnings.Should().BeNullOrEmpty();
|
||||||
|
result.Errors.Should().BeNullOrEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
private enum ProgramFiles
|
private enum ProgramFiles
|
||||||
{
|
{
|
||||||
X64,
|
X64,
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
using Microsoft.DotNet.MSBuildSdkResolver;
|
||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
|
{
|
||||||
|
public class GivenThatWeWantToCompareFXVersions
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData("2.0.0", "1.0.0", 1)]
|
||||||
|
[InlineData("1.1.0", "1.0.0", 1)]
|
||||||
|
[InlineData("1.0.1", "1.0.0", 1)]
|
||||||
|
[InlineData("1.0.0", "1.0.0-pre", 1)]
|
||||||
|
[InlineData("1.0.0-pre+2", "1.0.0-pre+1", 1)]
|
||||||
|
[InlineData("1.0.0", "2.0.0", -1)]
|
||||||
|
[InlineData("1.0.0", "1.1.0", -1)]
|
||||||
|
[InlineData("1.0.0", "1.0.1", -1)]
|
||||||
|
[InlineData("1.0.0-pre", "1.0.0", -1)]
|
||||||
|
[InlineData("1.0.0-pre+1", "1.0.0-pre+2", -1)]
|
||||||
|
[InlineData("1.2.3", "1.2.3", 0)]
|
||||||
|
[InlineData("1.2.3-pre", "1.2.3-pre", 0)]
|
||||||
|
[InlineData("1.2.3-pre+1", "1.2.3-pre+1", 0)]
|
||||||
|
public void OneFXVersionIsBiggerThanTheOther(string s1, string s2, int expectedResult)
|
||||||
|
{
|
||||||
|
FXVersion fxVersion1;
|
||||||
|
FXVersion fxVersion2;
|
||||||
|
FXVersion.TryParse(s1, out fxVersion1);
|
||||||
|
FXVersion.TryParse(s2, out fxVersion2);
|
||||||
|
FXVersion.Compare(fxVersion1, fxVersion2).Should().Be(expectedResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||||
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
using Xunit;
|
||||||
|
using Microsoft.DotNet.MSBuildSdkResolver;
|
||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Cli.Utils.Tests
|
||||||
|
{
|
||||||
|
public class GivenThatWeWantToParseFXVersions
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsNullWhenNoMajorSeparatorIsFound()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
FXVersion.TryParse("1", out fxVersion).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsNullWhenMajorPortionIsNotANumber()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
FXVersion.TryParse("a.0.0", out fxVersion).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsNullWhenNoMinorSeparatorIsFound()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
FXVersion.TryParse("1.0", out fxVersion).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsNullWhenMinorPortionIsNotANumber()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
FXVersion.TryParse("1.a.0", out fxVersion).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsNullWhenPatchPortionIsNotANumber()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
FXVersion.TryParse("1.0.a", out fxVersion).Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsFXVersionWhenOnlyMajorMinorPatchIsFound()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
|
||||||
|
var result = FXVersion.TryParse("1.2.3", out fxVersion);
|
||||||
|
|
||||||
|
result.Should().BeTrue();
|
||||||
|
fxVersion.Major.Should().Be(1);
|
||||||
|
fxVersion.Minor.Should().Be(2);
|
||||||
|
fxVersion.Patch.Should().Be(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsFXVersionWhenOnlyMajorMinorPatchAndPreIsFound()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
|
||||||
|
var result = FXVersion.TryParse("1.2.3-pre", out fxVersion);
|
||||||
|
|
||||||
|
result.Should().BeTrue();
|
||||||
|
fxVersion.Major.Should().Be(1);
|
||||||
|
fxVersion.Minor.Should().Be(2);
|
||||||
|
fxVersion.Patch.Should().Be(3);
|
||||||
|
fxVersion.Pre.Should().Be("-pre");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ReturnsFXVersionWhenMajorMinorPatchAndPreAndBuildIsFound()
|
||||||
|
{
|
||||||
|
FXVersion fxVersion;
|
||||||
|
|
||||||
|
var result = FXVersion.TryParse("1.2.3-pre+build", out fxVersion);
|
||||||
|
|
||||||
|
result.Should().BeTrue();
|
||||||
|
fxVersion.Major.Should().Be(1);
|
||||||
|
fxVersion.Minor.Should().Be(2);
|
||||||
|
fxVersion.Patch.Should().Be(3);
|
||||||
|
fxVersion.Pre.Should().Be("-pre");
|
||||||
|
fxVersion.Build.Should().Be("build");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,8 @@
|
||||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net461;$(CliTargetFramework)</TargetFrameworks>
|
<!-- https://github.com/dotnet/cli/issues/6672: Re-enable net461 as a TFM for tests. -->
|
||||||
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT'">$(CliTargetFramework)</TargetFrameworks>
|
<TargetFrameworks>$(CliTargetFramework)</TargetFrameworks>
|
||||||
<RuntimeFrameworkVersion>$(CLI_SharedFrameworkVersion)</RuntimeFrameworkVersion>
|
<RuntimeFrameworkVersion>$(CLI_SharedFrameworkVersion)</RuntimeFrameworkVersion>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AssemblyOriginatorKeyFile>../../tools/Key.snk</AssemblyOriginatorKeyFile>
|
<AssemblyOriginatorKeyFile>../../tools/Key.snk</AssemblyOriginatorKeyFile>
|
||||||
|
@ -29,6 +29,10 @@
|
||||||
<None Update="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
<None Update="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue