diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolveFrameworkReferencesTask.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolveFrameworkReferencesTask.cs new file mode 100644 index 000000000000..e1089e5070f9 --- /dev/null +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/GivenAResolveFrameworkReferencesTask.cs @@ -0,0 +1,88 @@ +// 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 FluentAssertions; +using Microsoft.Build.Framework; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Xunit; + +namespace Microsoft.NET.Build.Tasks.UnitTests +{ + public class GivenAResolveFrameworkReferences + { + [Fact] + public void It_resolves_with_multiple_runtime_packs() + { + var task = new ResolveFrameworkReferences + { + FrameworkReferences = new[] + { + new MockTaskItem("Microsoft.NETCore.App", new Dictionary()), + new MockTaskItem("Microsoft.Android", new Dictionary()), + }, + + ResolvedTargetingPacks = new[] + { + new MockTaskItem("Microsoft.NETCore.App", + new Dictionary() + { + {"NuGetPackageId", "Microsoft.NETCore.App.Ref"}, + {"NuGetPackageVersion", "6.0.2"}, + {"Path", "empty"}, + }), + new MockTaskItem("Microsoft.Android", + new Dictionary() + { + {"NuGetPackageId", "Microsoft.Android.Ref.32"}, + {"NuGetPackageVersion", "32.0.300"}, + {"Path", "empty"}, + {"Profile", "Android"}, + }), + }, + + ResolvedRuntimePacks = new[] + { + new MockTaskItem("Microsoft.NETCore.App.Runtime.Mono.android-arm", + new Dictionary() + { + {"FrameworkName", "Microsoft.NetCore.App"}, + {"NuGetPackageId", "Microsoft.NETCore.App.Runtime.Mono.android-arm"}, + {"NuGetPackageVersion", "6.0.4"}, + {"PackageDirectory", "empty"}, + }), + new MockTaskItem("Microsoft.Android.Runtime.32", + new Dictionary() + { + {"FrameworkName", "Microsoft.Android"}, + {"NuGetPackageId", "Microsoft.Android.Runtime.32"}, + {"NuGetPackageVersion", "32.0.300"}, + {"PackageDirectory", "empty"}, + }), + new MockTaskItem("Microsoft.Android.Runtime.32.android-arm", + new Dictionary() + { + {"FrameworkName", "Microsoft.Android"}, + {"NuGetPackageId", "Microsoft.Android.Runtime.32.android-arm"}, + {"NuGetPackageVersion", "32.0.300"}, + {"PackageDirectory", "empty"}, + }), + }, + }; + + task.Execute().Should().BeTrue(); + task.ResolvedFrameworkReferences.Length.Should().Be(2); + task.ResolvedFrameworkReferences[0].GetMetadata("RuntimePackPath").Should().Be("empty"); + task.ResolvedFrameworkReferences[0].GetMetadata("RuntimePackName").Should().Be("Microsoft.NETCore.App.Runtime.Mono.android-arm"); + task.ResolvedFrameworkReferences[0].GetMetadata("RuntimePackVersion").Should().Be("6.0.4"); + task.ResolvedFrameworkReferences[1].GetMetadata("RuntimePackPath").Should().Be("empty;empty"); + task.ResolvedFrameworkReferences[1].GetMetadata("RuntimePackName").Should().Be("Microsoft.Android.Runtime.32;Microsoft.Android.Runtime.32.android-arm"); + task.ResolvedFrameworkReferences[1].GetMetadata("RuntimePackVersion").Should().Be("32.0.300;32.0.300"); + } + } + +} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/ProcessFrameworkReferencesTests.cs b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/ProcessFrameworkReferencesTests.cs index bd05d14a325c..f261f3306594 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/ProcessFrameworkReferencesTests.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks.UnitTests/ProcessFrameworkReferencesTests.cs @@ -317,5 +317,56 @@ public void Given_reference_to_NETCoreApp_It_should_not_resolve_runtime_pack() task.RuntimePacks[0].ItemSpec.Should().Be("Microsoft.Windows.SDK.NET.Ref", "it should not resolve runtime pack for Microsoft.NETCore.App"); } + + [Fact] + public void It_resolves_FrameworkReference_with_multiple_runtime_patterns() + { + const string minimalRuntimeGraphPathContent = + "{\"runtimes\":{\"android\":{\"#import\":[\"linux\"]},\"linux\":{\"#import\":[]},\"android-arm\":{\"#import\":[\"android\"]},\"android-arm64\":{\"#import\":[\"android\"]}}}"; + var runtimeGraphPathPath = Path.GetTempFileName(); + File.WriteAllText(runtimeGraphPathPath, minimalRuntimeGraphPathContent); + + var task = new ProcessFrameworkReferences + { + BuildEngine = new MockNeverCacheBuildEngine4(), + EnableTargetingPackDownload = true, + TargetFrameworkIdentifier = ".NETCoreApp", + TargetFrameworkVersion = "6.0", + TargetPlatformIdentifier = "Android", + RuntimeGraphPath = runtimeGraphPathPath, + RuntimeIdentifiers = new[] + { + "android-arm", "android-arm64" + }, + + FrameworkReferences = new[] + { + new MockTaskItem("Microsoft.Android", new Dictionary()), + }, + + KnownFrameworkReferences = new[] + { + new MockTaskItem("Microsoft.Android", + new Dictionary() + { + {"TargetFramework", "net6.0"}, + {"RuntimeFrameworkName", "Microsoft.Android"}, + {"LatestRuntimeFrameworkVersion", "32.0.300"}, + {"TargetingPackName", "Microsoft.Android.Ref.32"}, + {"TargetingPackVersion", "32.0.300"}, + {"RuntimePackNamePatterns", "Microsoft.Android.Runtime.32;Microsoft.Android.Runtime.32.**RID**"}, + {"RuntimePackRuntimeIdentifiers", "android-arm;android-arm64;android-x86;android-x64"}, + {"Profile", "Android"}, + }), + }, + }; + + task.Execute().Should().BeTrue(); + task.PackagesToDownload.Length.Should().Be(4); + task.PackagesToDownload.Should().Contain(p => p.ItemSpec == "Microsoft.Android.Ref.32"); + task.PackagesToDownload.Should().Contain(p => p.ItemSpec == "Microsoft.Android.Runtime.32"); + task.PackagesToDownload.Should().Contain(p => p.ItemSpec == "Microsoft.Android.Runtime.32.android-arm"); + task.PackagesToDownload.Should().Contain(p => p.ItemSpec == "Microsoft.Android.Runtime.32.android-arm64"); + } } } diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs index 4cdaaba4d6fd..e1c342f1280f 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs @@ -26,7 +26,6 @@ protected override void ExecuteCore() } var resolvedTargetingPacks = ResolvedTargetingPacks.ToDictionary(tp => tp.ItemSpec, StringComparer.OrdinalIgnoreCase); - var resolvedRuntimePacks = ResolvedRuntimePacks.ToDictionary(rp => rp.GetMetadata(MetadataKeys.FrameworkName), StringComparer.OrdinalIgnoreCase); var resolvedFrameworkReferences = new List(FrameworkReferences.Length); @@ -48,13 +47,14 @@ protected override void ExecuteCore() resolvedFrameworkReference.SetMetadata("TargetingPackVersion", targetingPack.GetMetadata(MetadataKeys.NuGetPackageVersion)); resolvedFrameworkReference.SetMetadata("Profile", targetingPack.GetMetadata("Profile")); - ITaskItem runtimePack; - if (resolvedRuntimePacks.TryGetValue(frameworkReference.ItemSpec, out runtimePack)) + // Allow more than one runtime pack to be associated with this FrameworkReference + var matchingRuntimePacks = ResolvedRuntimePacks.Where(rp => rp.GetMetadata(MetadataKeys.FrameworkName).Equals(frameworkReference.ItemSpec, StringComparison.OrdinalIgnoreCase)); + if (matchingRuntimePacks.Any()) { - resolvedFrameworkReference.SetMetadata("RuntimePackPath", runtimePack.GetMetadata(MetadataKeys.PackageDirectory)); - resolvedFrameworkReference.SetMetadata("RuntimePackName", runtimePack.GetMetadata(MetadataKeys.NuGetPackageId)); - resolvedFrameworkReference.SetMetadata("RuntimePackVersion", runtimePack.GetMetadata(MetadataKeys.NuGetPackageVersion)); - } + resolvedFrameworkReference.SetMetadata("RuntimePackPath", string.Join (";", matchingRuntimePacks.Select (mrp => mrp.GetMetadata(MetadataKeys.PackageDirectory)))); + resolvedFrameworkReference.SetMetadata("RuntimePackName", string.Join (";", matchingRuntimePacks.Select (mrp => mrp.GetMetadata(MetadataKeys.NuGetPackageId)))); + resolvedFrameworkReference.SetMetadata("RuntimePackVersion", string.Join (";", matchingRuntimePacks.Select (mrp => mrp.GetMetadata(MetadataKeys.NuGetPackageVersion)))); + } resolvedFrameworkReferences.Add(resolvedFrameworkReference); }