From 2f01bb4fad2e6796f531d3a7ed424779d8ea6a6d Mon Sep 17 00:00:00 2001 From: William Li Date: Fri, 6 Apr 2018 17:39:58 -0700 Subject: [PATCH] Add TryGetMostFitRuntimeIdentifier (#8997) --- .../FrameworkDependencyFile.cs | 73 +++++++++ .../GivenAFrameworkDependencyFile.cs | 147 ++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 test/Microsoft.DotNet.Cli.Utils.Tests/GivenAFrameworkDependencyFile.cs diff --git a/src/Microsoft.DotNet.Cli.Utils/FrameworkDependencyFile.cs b/src/Microsoft.DotNet.Cli.Utils/FrameworkDependencyFile.cs index 202c07e9c..b91f35fa0 100644 --- a/src/Microsoft.DotNet.Cli.Utils/FrameworkDependencyFile.cs +++ b/src/Microsoft.DotNet.Cli.Utils/FrameworkDependencyFile.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.DotNet.PlatformAbstractions; @@ -45,6 +46,78 @@ namespace Microsoft.DotNet.Cli.Utils ?.Version; } + public bool TryGetMostFitRuntimeIdentifier( + string alternativeCurrentRuntimeIdentifier, + string[] candidateRuntimeIdentifiers, + out string mostFitRuntimeIdentifier) + { + return TryGetMostFitRuntimeIdentifier( + RuntimeEnvironment.GetRuntimeIdentifier(), + alternativeCurrentRuntimeIdentifier, + DependencyContext.RuntimeGraph, + candidateRuntimeIdentifiers, + out mostFitRuntimeIdentifier); + } + + internal static bool TryGetMostFitRuntimeIdentifier( + string currentRuntimeIdentifier, + string alternativeCurrentRuntimeIdentifier, + IReadOnlyList runtimeGraph, + string[] candidateRuntimeIdentifiers, + out string mostFitRuntimeIdentifier) + { + mostFitRuntimeIdentifier = null; + RuntimeFallbacks[] runtimeFallbacksCandidates; + + if (!string.IsNullOrEmpty(currentRuntimeIdentifier)) + { + runtimeFallbacksCandidates = + runtimeGraph + .Where(g => string.Equals(g.Runtime, currentRuntimeIdentifier, StringComparison.OrdinalIgnoreCase)) + .ToArray(); + } + else + { + runtimeFallbacksCandidates = Array.Empty(); + } + + if (runtimeFallbacksCandidates.Length == 0 && !string.IsNullOrEmpty(alternativeCurrentRuntimeIdentifier)) + { + runtimeFallbacksCandidates = + runtimeGraph + .Where(g => string.Equals(g.Runtime, alternativeCurrentRuntimeIdentifier, StringComparison.OrdinalIgnoreCase)) + .ToArray(); + } + + if (runtimeFallbacksCandidates.Length == 0) + { + return false; + } + + RuntimeFallbacks runtimeFallbacks = runtimeFallbacksCandidates[0]; + + var runtimeFallbacksIncludesRuntime = new List(); + runtimeFallbacksIncludesRuntime.Add(runtimeFallbacks.Runtime); + runtimeFallbacksIncludesRuntime.AddRange(runtimeFallbacks.Fallbacks); + + + var candidateMap = candidateRuntimeIdentifiers + .Distinct(comparer: StringComparer.OrdinalIgnoreCase) + .ToDictionary(x => x, StringComparer.OrdinalIgnoreCase); + + foreach (var fallback in runtimeFallbacksIncludesRuntime) + { + if (candidateMap.TryGetValue(fallback, out string match)) + { + mostFitRuntimeIdentifier = match; + + return true; + } + } + + return false; + } + private DependencyContext CreateDependencyContext() { using (Stream depsFileStream = File.OpenRead(_depsFilePath)) diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAFrameworkDependencyFile.cs b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAFrameworkDependencyFile.cs new file mode 100644 index 000000000..a13996560 --- /dev/null +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAFrameworkDependencyFile.cs @@ -0,0 +1,147 @@ +// 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 System.Collections.Generic; +using FluentAssertions; +using Microsoft.DotNet.Tools.Test.Utilities; +using Microsoft.Extensions.DependencyModel; +using Xunit; + +namespace Microsoft.DotNet.Cli.Utils.Tests +{ + public class GivenAFrameworkDependencyFile + { + private readonly IReadOnlyList _testRuntimeGraph; + + public GivenAFrameworkDependencyFile() + { + _testRuntimeGraph = new List + { + new RuntimeFallbacks("win-x64", new [] { "win", "any", "base" }), + new RuntimeFallbacks("win8", new [] { "win7", "win", "any", "base" }), + new RuntimeFallbacks("win7", new [] { "win", "any", "base" }), + new RuntimeFallbacks("win", new [] { "any", "base" }), + }; + } + + [Fact] + public void WhenPassSeveralCompatibleRuntimeIdentifiersItOutMostFitRid() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "win7", + alternativeCurrentRuntimeIdentifier : "win", + runtimeGraph : _testRuntimeGraph, + candidateRuntimeIdentifiers : new [] { "win", "any" }, + mostFitRuntimeIdentifier : out string mostFitRid) + .Should().BeTrue(); + + mostFitRid.Should().Be("win"); + } + + [Fact] + public void WhenPassSeveralCompatibleRuntimeIdentifiersItOutMostFitRid2() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "win", + alternativeCurrentRuntimeIdentifier: null, + runtimeGraph: _testRuntimeGraph, + candidateRuntimeIdentifiers: new[] { "win", "any" }, + mostFitRuntimeIdentifier: out string mostFitRid) + .Should().BeTrue(); + + mostFitRid.Should().Be("win"); + } + + [Fact] + public void WhenPassSeveralCompatibleRuntimeIdentifiersAndCurrentRuntimeIdentifierIsNullReturnsFalse() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: null, + alternativeCurrentRuntimeIdentifier: null, + runtimeGraph: _testRuntimeGraph, + candidateRuntimeIdentifiers: new[] { "win", "any" }, + mostFitRuntimeIdentifier: out string mostFitRid) + .Should().BeFalse(); + } + + [Fact] + public void WhenPassSeveralCompatibleRuntimeIdentifiersItOutMostFitRidWithCasingPreserved() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "win7", + alternativeCurrentRuntimeIdentifier : null, + runtimeGraph : _testRuntimeGraph, + candidateRuntimeIdentifiers : new [] { "Win", "any" }, + mostFitRuntimeIdentifier : out string mostFitRid) + .Should().BeTrue(); + + mostFitRid.Should().Be("Win"); + } + + [Fact] + public void WhenPassSeveralCompatibleRuntimeIdentifiersWithDuplicationItOutMostFitRid() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "win7", + alternativeCurrentRuntimeIdentifier : null, + runtimeGraph : _testRuntimeGraph, + candidateRuntimeIdentifiers : new [] { "win", "win", "any" }, + mostFitRuntimeIdentifier : out string mostFitRid) + .Should().BeTrue(); + + mostFitRid.Should().Be("win"); + } + + [Fact] + public void WhenPassSeveralCompatibleRuntimeIdentifiersAndDuplicationItOutMostFitRidWithCasingPreservedTheFirstIsFavoriated() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "win7", + alternativeCurrentRuntimeIdentifier: null, + runtimeGraph: _testRuntimeGraph, + candidateRuntimeIdentifiers: new[] { "Win", "win", "win", "any" }, + mostFitRuntimeIdentifier: out string mostFitRid) + .Should().BeTrue(); + + mostFitRid.Should().Be("Win"); + } + + [Fact] + public void WhenPassSeveralNonCompatibleRuntimeIdentifiersItReturnsFalse() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "win7", + alternativeCurrentRuntimeIdentifier : null, + runtimeGraph : _testRuntimeGraph, + candidateRuntimeIdentifiers : new [] { "centos", "debian" }, + mostFitRuntimeIdentifier : out string mostFitRid) + .Should().BeFalse(); + } + + [Fact] + public void WhenCurrentRuntimeIdentifierIsNotSupportedItUsesAlternative() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "win-vnext", + alternativeCurrentRuntimeIdentifier: "win8", + runtimeGraph: _testRuntimeGraph, + candidateRuntimeIdentifiers: new[] { "win", "any" }, + mostFitRuntimeIdentifier: out string mostFitRid) + .Should().BeTrue(); + + mostFitRid.Should().Be("win"); + } + + [Fact] + public void WhenCurrentRuntimeIdentifierIsNotSupportedSoIsTheAlternativeItReturnsFalse() + { + FrameworkDependencyFile.TryGetMostFitRuntimeIdentifier( + currentRuntimeIdentifier: "osx10.13-x64", + alternativeCurrentRuntimeIdentifier: "osx-x64", + runtimeGraph: _testRuntimeGraph, + candidateRuntimeIdentifiers: new[] { "win", "any" }, + mostFitRuntimeIdentifier: out string mostFitRid) + .Should().BeFalse(); + } + } +}