diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs index c1d670bbcd4a..ad04134e28ee 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveFrameworkReferences.cs @@ -29,6 +29,8 @@ public class ResolveFrameworkReferences : TaskBase public string RuntimeIdentifier { get; set; } + public string[] RuntimeIdentifiers { get; set; } + public string RuntimeFrameworkVersion { get; set; } public bool TargetLatestRuntimePatch { get; set; } @@ -64,9 +66,11 @@ protected override void ExecuteCore() return; } + var normalizedTargetFrameworkVersion = NormalizeVersion(new Version(TargetFrameworkVersion)); + var knownFrameworkReferencesForTargetFramework = KnownFrameworkReferences.Select(item => new KnownFrameworkReference(item)) .Where(kfr => kfr.TargetFramework.Framework.Equals(TargetFrameworkIdentifier, StringComparison.OrdinalIgnoreCase) && - NormalizeVersion(kfr.TargetFramework.Version) == NormalizeVersion(new Version(TargetFrameworkVersion))) + NormalizeVersion(kfr.TargetFramework.Version) == normalizedTargetFrameworkVersion) .ToList(); var frameworkReferenceMap = FrameworkReferences.ToDictionary(fr => fr.ItemSpec); @@ -77,7 +81,7 @@ protected override void ExecuteCore() List runtimePacks = new List(); List unavailableRuntimePacks = new List(); - bool reportedUnrecognizedRuntimeIdentifier = false; + HashSet unrecognizedRuntimeIdentifiers = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var knownFrameworkReference in knownFrameworkReferencesForTargetFramework) { @@ -98,6 +102,8 @@ protected override void ExecuteCore() targetingPackVersion = knownFrameworkReference.TargetingPackVersion; } targetingPack.SetMetadata(MetadataKeys.PackageVersion, targetingPackVersion); + targetingPack.SetMetadata("TargetingPackFormat", knownFrameworkReference.TargetingPackFormat); + targetingPack.SetMetadata("TargetFramework", knownFrameworkReference.TargetFramework.GetShortFolderName()); string targetingPackPath = null; if (!string.IsNullOrEmpty(TargetingPackRoot)) @@ -126,64 +132,44 @@ protected override void ExecuteCore() var runtimeFrameworkVersion = GetRuntimeFrameworkVersion(frameworkReference, knownFrameworkReference); + bool processedPrimaryRuntimeIdentifier = false; + if (SelfContained && !string.IsNullOrEmpty(RuntimeIdentifier) && !string.IsNullOrEmpty(knownFrameworkReference.RuntimePackNamePatterns)) { - foreach (var runtimePackNamePattern in knownFrameworkReference.RuntimePackNamePatterns.Split(';')) - { - string runtimePackRuntimeIdentifier = NuGetUtils.GetBestMatchingRid( - new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath), - RuntimeIdentifier, - knownFrameworkReference.RuntimePackRuntimeIdentifiers.Split(';'), - out bool wasInGraph); + ProcessRuntimeIdentifier(RuntimeIdentifier, knownFrameworkReference, runtimeFrameworkVersion, + unrecognizedRuntimeIdentifiers, unavailableRuntimePacks, runtimePacks, packagesToDownload); - if (runtimePackRuntimeIdentifier == null) + processedPrimaryRuntimeIdentifier = true; + } + + if (RuntimeIdentifiers != null) + { + foreach (var runtimeIdentifier in RuntimeIdentifiers) + { + if (processedPrimaryRuntimeIdentifier && runtimeIdentifier == this.RuntimeIdentifier) { - if (wasInGraph) - { - // Report this as an error later, if necessary. This is because we try to download - // all available runtime packs in case there is a transitive reference to a shared - // framework we don't directly reference. But we don't want to immediately error out - // here if a runtime pack that we might not need to reference isn't available for the - // targeted RID (e.g. Microsoft.WindowsDesktop.App for a linux RID). - var unavailableRuntimePack = new TaskItem(knownFrameworkReference.Name); - unavailableRuntimePack.SetMetadata(MetadataKeys.RuntimeIdentifier, RuntimeIdentifier); - unavailableRuntimePacks.Add(unavailableRuntimePack); - } - else if (!reportedUnrecognizedRuntimeIdentifier) - { - // NETSDK1083: The specified RuntimeIdentifier '{0}' is not recognized. - Log.LogError(Strings.RuntimeIdentifierNotRecognized, RuntimeIdentifier); - reportedUnrecognizedRuntimeIdentifier = true; - } + // We've already processed this RID + continue; } - else - { - string runtimePackName = runtimePackNamePattern.Replace("**RID**", runtimePackRuntimeIdentifier); - TaskItem runtimePackItem = new TaskItem(runtimePackName); - runtimePackItem.SetMetadata(MetadataKeys.PackageName, runtimePackName); - runtimePackItem.SetMetadata(MetadataKeys.PackageVersion, runtimeFrameworkVersion); - runtimePackItem.SetMetadata(MetadataKeys.FrameworkName, knownFrameworkReference.Name); - runtimePackItem.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimePackRuntimeIdentifier); - - runtimePacks.Add(runtimePackItem); - - TaskItem packageToDownload = new TaskItem(runtimePackName); - packageToDownload.SetMetadata(MetadataKeys.Version, runtimeFrameworkVersion); - - packagesToDownload.Add(packageToDownload); - } + // Pass in null for the runtimePacks list, as for these runtime identifiers we only want to + // download the runtime packs, but not use the assets from them + ProcessRuntimeIdentifier(runtimeIdentifier, knownFrameworkReference, runtimeFrameworkVersion, + unrecognizedRuntimeIdentifiers, unavailableRuntimePacks, runtimePacks: null, packagesToDownload); } } - TaskItem runtimeFramework = new TaskItem(knownFrameworkReference.RuntimeFrameworkName); + if (!string.IsNullOrEmpty(knownFrameworkReference.RuntimeFrameworkName)) + { + TaskItem runtimeFramework = new TaskItem(knownFrameworkReference.RuntimeFrameworkName); - runtimeFramework.SetMetadata(MetadataKeys.Version, runtimeFrameworkVersion); - runtimeFramework.SetMetadata(MetadataKeys.FrameworkName, knownFrameworkReference.Name); + runtimeFramework.SetMetadata(MetadataKeys.Version, runtimeFrameworkVersion); + runtimeFramework.SetMetadata(MetadataKeys.FrameworkName, knownFrameworkReference.Name); - runtimeFrameworks.Add(runtimeFramework); + runtimeFrameworks.Add(runtimeFramework); + } } if (packagesToDownload.Any()) @@ -212,6 +198,64 @@ protected override void ExecuteCore() } } + private void ProcessRuntimeIdentifier(string runtimeIdentifier, KnownFrameworkReference knownFrameworkReference, + string runtimeFrameworkVersion, HashSet unrecognizedRuntimeIdentifiers, + List unavailableRuntimePacks, List runtimePacks, List packagesToDownload) + { + var runtimeGraph = new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath); + var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = knownFrameworkReference.RuntimePackRuntimeIdentifiers.Split(';'); + + string runtimePackRuntimeIdentifier = NuGetUtils.GetBestMatchingRid( + runtimeGraph, + runtimeIdentifier, + knownFrameworkReferenceRuntimePackRuntimeIdentifiers, + out bool wasInGraph); + + if (runtimePackRuntimeIdentifier == null) + { + if (wasInGraph) + { + // Report this as an error later, if necessary. This is because we try to download + // all available runtime packs in case there is a transitive reference to a shared + // framework we don't directly reference. But we don't want to immediately error out + // here if a runtime pack that we might not need to reference isn't available for the + // targeted RID (e.g. Microsoft.WindowsDesktop.App for a linux RID). + var unavailableRuntimePack = new TaskItem(knownFrameworkReference.Name); + unavailableRuntimePack.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimeIdentifier); + unavailableRuntimePacks.Add(unavailableRuntimePack); + } + else if (!unrecognizedRuntimeIdentifiers.Contains(runtimeIdentifier)) + { + // NETSDK1083: The specified RuntimeIdentifier '{0}' is not recognized. + Log.LogError(Strings.RuntimeIdentifierNotRecognized, runtimeIdentifier); + unrecognizedRuntimeIdentifiers.Add(runtimeIdentifier); + } + } + else + { + foreach (var runtimePackNamePattern in knownFrameworkReference.RuntimePackNamePatterns.Split(';')) + { + string runtimePackName = runtimePackNamePattern.Replace("**RID**", runtimePackRuntimeIdentifier); + + if (runtimePacks != null) + { + TaskItem runtimePackItem = new TaskItem(runtimePackName); + runtimePackItem.SetMetadata(MetadataKeys.PackageName, runtimePackName); + runtimePackItem.SetMetadata(MetadataKeys.PackageVersion, runtimeFrameworkVersion); + runtimePackItem.SetMetadata(MetadataKeys.FrameworkName, knownFrameworkReference.Name); + runtimePackItem.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimePackRuntimeIdentifier); + + runtimePacks.Add(runtimePackItem); + } + + TaskItem packageToDownload = new TaskItem(runtimePackName); + packageToDownload.SetMetadata(MetadataKeys.Version, runtimeFrameworkVersion); + + packagesToDownload.Add(packageToDownload); + } + } + } + private string GetRuntimeFrameworkVersion(ITaskItem frameworkReference, KnownFrameworkReference knownFrameworkReference) { // Precedence order for selecting runtime framework version @@ -297,6 +341,7 @@ public KnownFrameworkReference(ITaskItem item) // The ID of the targeting pack NuGet package to reference public string TargetingPackName => _item.GetMetadata("TargetingPackName"); public string TargetingPackVersion => _item.GetMetadata("TargetingPackVersion"); + public string TargetingPackFormat => _item.GetMetadata("TargetingPackFormat"); public string RuntimePackNamePatterns => _item.GetMetadata("RuntimePackNamePatterns"); diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs index fba7c63431e2..ce35932363d3 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveRuntimePackAssets.cs @@ -45,6 +45,16 @@ protected override void ExecuteCore() } string runtimePackRoot = runtimePack.GetMetadata(MetadataKeys.PackageDirectory); + + if (string.IsNullOrEmpty(runtimePackRoot) || !Directory.Exists(runtimePackRoot)) + { + // If we do the work in https://github.com/dotnet/cli/issues/10528, + // then we should add a new error message here indicating that the runtime pack hasn't + // been downloaded, and that restore should be run with that runtime identifier. + Log.LogError(Strings.NoRuntimePackAvailable, runtimePack.ItemSpec, + runtimePack.GetMetadata(MetadataKeys.RuntimeIdentifier)); + } + string runtimeIdentifier = runtimePack.GetMetadata(MetadataKeys.RuntimeIdentifier); // These hard-coded paths are temporary until we have "real" runtime packs, which will likely have a flattened diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveTargetingPackAssets.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveTargetingPackAssets.cs index 65b2b24d25cd..e84d8d74e9a6 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolveTargetingPackAssets.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolveTargetingPackAssets.cs @@ -57,42 +57,65 @@ protected override void ExecuteCore() } else { - foreach (var dll in Directory.GetFiles(Path.Combine(targetingPackRoot, "ref", "netcoreapp3.0"), "*.dll")) - { - var reference = new TaskItem(dll); - - reference.SetMetadata(MetadataKeys.ExternallyResolved, "true"); - reference.SetMetadata(MetadataKeys.Private, "false"); - - // TODO: Once we work out what metadata we should use here to display these references grouped under the targeting pack - // in solution explorer, set that metadata here.These metadata values are based on what PCLs were using. - // https://github.com/dotnet/sdk/issues/2802 - reference.SetMetadata("WinMDFile", "false"); - reference.SetMetadata("ReferenceGroupingDisplayName", targetingPack.ItemSpec); - reference.SetMetadata("ReferenceGrouping", targetingPack.ItemSpec); - reference.SetMetadata("ResolvedFrom", "TargetingPack"); - reference.SetMetadata("IsSystemReference", "true"); - - referencesToAdd.Add(reference); - } + string targetingPackFormat = targetingPack.GetMetadata("TargetingPackFormat"); - var platformManifestPath = Path.Combine(targetingPackRoot, "build", "netcoreapp3.0", - targetingPack.GetMetadata(MetadataKeys.PackageName) + ".PlatformManifest.txt"); - - if (File.Exists(platformManifestPath)) + if (targetingPackFormat.Equals("NETStandardLegacy", StringComparison.OrdinalIgnoreCase)) { - platformManifests.Add(new TaskItem(platformManifestPath)); + AddNetStandardTargetingPackAssets(targetingPack, targetingPackRoot, referencesToAdd); } - - if (targetingPack.ItemSpec.Equals("Microsoft.NETCore.App", StringComparison.OrdinalIgnoreCase)) + else { - // Hardcode this for now. Load this from the targeting pack once we have "real" targeting packs - // https://github.com/dotnet/cli/issues/10581 - PackageConflictPreferredPackages = "Microsoft.NETCore.App;runtime.linux-x64.Microsoft.NETCore.App;runtime.linux-x64.Microsoft.NETCore.App;runtime.linux-musl-x64.Microsoft.NETCore.App;runtime.linux-musl-x64.Microsoft.NETCore.App;runtime.rhel.6-x64.Microsoft.NETCore.App;runtime.rhel.6-x64.Microsoft.NETCore.App;runtime.osx-x64.Microsoft.NETCore.App;runtime.osx-x64.Microsoft.NETCore.App;runtime.freebsd-x64.Microsoft.NETCore.App;runtime.freebsd-x64.Microsoft.NETCore.App;runtime.win-x86.Microsoft.NETCore.App;runtime.win-x86.Microsoft.NETCore.App;runtime.win-arm.Microsoft.NETCore.App;runtime.win-arm.Microsoft.NETCore.App;runtime.win-arm64.Microsoft.NETCore.App;runtime.win-arm64.Microsoft.NETCore.App;runtime.linux-arm.Microsoft.NETCore.App;runtime.linux-arm.Microsoft.NETCore.App;runtime.linux-arm64.Microsoft.NETCore.App;runtime.linux-arm64.Microsoft.NETCore.App;runtime.tizen.4.0.0-armel.Microsoft.NETCore.App;runtime.tizen.4.0.0-armel.Microsoft.NETCore.App;runtime.tizen.5.0.0-armel.Microsoft.NETCore.App;runtime.tizen.5.0.0-armel.Microsoft.NETCore.App;runtime.win-x64.Microsoft.NETCore.App;runtime.win-x64.Microsoft.NETCore.App"; + string targetingPackTargetFramework = targetingPack.GetMetadata("TargetFramework"); + if (string.IsNullOrEmpty(targetingPackTargetFramework)) + { + targetingPackTargetFramework = "netcoreapp3.0"; + } + + string targetingPackDataPath = Path.Combine(targetingPackRoot, "data"); + string[] possibleDllPaths = new[] + { + Path.Combine(targetingPackRoot, "ref", targetingPackTargetFramework), + targetingPackDataPath + }; + + string[] possibleManifestPaths = new[] + { + Path.Combine(targetingPackRoot, "build", targetingPackTargetFramework, + targetingPack.GetMetadata(MetadataKeys.PackageName) + ".PlatformManifest.txt"), + Path.Combine(targetingPackDataPath, "PlatformManifest.txt"), + Path.Combine(targetingPackDataPath, + targetingPack.GetMetadata(MetadataKeys.PackageName) + ".PlatformManifest.txt"), + }; + + string targetingPackDllPath = possibleDllPaths.First(path => + Directory.Exists(path) && + Directory.GetFiles(path, "*.dll").Any()); + + string platformManifestPath = possibleManifestPaths.FirstOrDefault(File.Exists); + + foreach (var dll in Directory.GetFiles(targetingPackDllPath, "*.dll")) + { + var reference = CreateReferenceItem(dll, targetingPack); + + referencesToAdd.Add(reference); + } + + if (platformManifestPath != null) + { + platformManifests.Add(new TaskItem(platformManifestPath)); + } + + if (targetingPack.ItemSpec.Equals("Microsoft.NETCore.App", StringComparison.OrdinalIgnoreCase)) + { + // Hardcode this for now. Load this from the targeting pack once we have "real" targeting packs + // https://github.com/dotnet/cli/issues/10581 + PackageConflictPreferredPackages = "Microsoft.NETCore.App;runtime.linux-x64.Microsoft.NETCore.App;runtime.linux-x64.Microsoft.NETCore.App;runtime.linux-musl-x64.Microsoft.NETCore.App;runtime.linux-musl-x64.Microsoft.NETCore.App;runtime.rhel.6-x64.Microsoft.NETCore.App;runtime.rhel.6-x64.Microsoft.NETCore.App;runtime.osx-x64.Microsoft.NETCore.App;runtime.osx-x64.Microsoft.NETCore.App;runtime.freebsd-x64.Microsoft.NETCore.App;runtime.freebsd-x64.Microsoft.NETCore.App;runtime.win-x86.Microsoft.NETCore.App;runtime.win-x86.Microsoft.NETCore.App;runtime.win-arm.Microsoft.NETCore.App;runtime.win-arm.Microsoft.NETCore.App;runtime.win-arm64.Microsoft.NETCore.App;runtime.win-arm64.Microsoft.NETCore.App;runtime.linux-arm.Microsoft.NETCore.App;runtime.linux-arm.Microsoft.NETCore.App;runtime.linux-arm64.Microsoft.NETCore.App;runtime.linux-arm64.Microsoft.NETCore.App;runtime.tizen.4.0.0-armel.Microsoft.NETCore.App;runtime.tizen.4.0.0-armel.Microsoft.NETCore.App;runtime.tizen.5.0.0-armel.Microsoft.NETCore.App;runtime.tizen.5.0.0-armel.Microsoft.NETCore.App;runtime.win-x64.Microsoft.NETCore.App;runtime.win-x64.Microsoft.NETCore.App"; + } } } } + // Remove RuntimeFramework items for shared frameworks which weren't referenced HashSet frameworkReferenceNames = new HashSet(FrameworkReferences.Select(fr => fr.ItemSpec), StringComparer.OrdinalIgnoreCase); RuntimeFrameworksToRemove = RuntimeFrameworks.Where(rf => !frameworkReferenceNames.Contains(rf.GetMetadata(MetadataKeys.FrameworkName))) .ToArray(); @@ -101,5 +124,45 @@ protected override void ExecuteCore() PlatformManifests = platformManifests.ToArray(); PackageConflictOverrides = packageConflictOverrides.ToArray(); } + + private void AddNetStandardTargetingPackAssets(ITaskItem targetingPack, string targetingPackRoot, List referencesToAdd) + { + string targetingPackTargetFramework = targetingPack.GetMetadata("TargetFramework"); + string targetingPackAssetPath = Path.Combine(targetingPackRoot, "build", targetingPackTargetFramework, "ref"); + + foreach (var dll in Directory.GetFiles(targetingPackAssetPath, "*.dll")) + { + var reference = CreateReferenceItem(dll, targetingPack); + + if (!Path.GetFileName(dll).Equals("netstandard.dll", StringComparison.OrdinalIgnoreCase)) + { + reference.SetMetadata("Facade", "true"); + } + + referencesToAdd.Add(reference); + } + } + + private TaskItem CreateReferenceItem(string dll, ITaskItem targetingPack) + { + var reference = new TaskItem(dll); + + reference.SetMetadata(MetadataKeys.ExternallyResolved, "true"); + reference.SetMetadata(MetadataKeys.Private, "false"); + reference.SetMetadata("Visible", "false"); + reference.SetMetadata(MetadataKeys.NuGetPackageId, targetingPack.GetMetadata(MetadataKeys.PackageName)); + reference.SetMetadata(MetadataKeys.NuGetPackageVersion, targetingPack.GetMetadata(MetadataKeys.PackageVersion)); + + // TODO: Once we work out what metadata we should use here to display these references grouped under the targeting pack + // in solution explorer, set that metadata here.These metadata values are based on what PCLs were using. + // https://github.com/dotnet/sdk/issues/2802 + reference.SetMetadata("WinMDFile", "false"); + reference.SetMetadata("ReferenceGroupingDisplayName", targetingPack.ItemSpec); + reference.SetMetadata("ReferenceGrouping", targetingPack.ItemSpec); + reference.SetMetadata("ResolvedFrom", "TargetingPack"); + reference.SetMetadata("IsSystemReference", "true"); + + return reference; + } } } diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props index 46492cdb18ab..4f9e61770307 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props @@ -17,6 +17,31 @@ Copyright (c) .NET Foundation. All rights reserved. + + + + + + + + + false @@ -36,7 +61,7 @@ Copyright (c) .NET Foundation. All rights reserved. - + @@ -45,6 +70,9 @@ Copyright (c) .NET Foundation. All rights reserved. PrivateAssets="All" Publish="true" /> + + + diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets index a8a29fd90438..8ffa75bdf067 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.targets @@ -43,7 +43,7 @@ Copyright (c) .NET Foundation. All rights reserved. - + + 2.1 k.StartsWith("runtime.") && k.EndsWith(".Microsoft.NETCore.App")) .Single(); @@ -314,7 +355,7 @@ public void RuntimeFrameworkVersionCanBeSpecifiedViaProperty() var resolvedVersions = GetResolvedVersions(testProject); resolvedVersions.RuntimeFramework["Microsoft.NETCore.App"].Should().Be(runtimeFrameworkVersion); - resolvedVersions.PackageDownload["Microsoft.NETCore.App"].Should().Be(targetingPackVersion); + resolvedVersions.PackageDownload["Microsoft.NETCore.App.Ref"].Should().Be(targetingPackVersion); string runtimePackName = resolvedVersions.PackageDownload.Keys .Where(k => k.StartsWith("runtime.") && k.EndsWith(".Microsoft.NETCore.App")) .Single(); @@ -350,7 +391,7 @@ public void TargetLatestPatchCanBeSpecifiedOnFrameworkReference(bool attributeVa string expectedRuntimeFrameworkVersion = attributeValue ? "3.0.0-latestversion" : "3.0.0-defaultversion"; resolvedVersions.RuntimeFramework["Microsoft.NETCore.App"].Should().Be(expectedRuntimeFrameworkVersion); - resolvedVersions.PackageDownload["Microsoft.NETCore.App"].Should().Be(targetingPackVersion); + resolvedVersions.PackageDownload["Microsoft.NETCore.App.Ref"].Should().Be(targetingPackVersion); string runtimePackName = resolvedVersions.PackageDownload.Keys .Where(k => k.StartsWith("runtime.") && k.EndsWith(".Microsoft.NETCore.App")) .Single(); @@ -376,7 +417,7 @@ public void TargetLatestPatchCanBeSpecifiedViaProperty(bool propertyValue) string expectedRuntimeFrameworkVersion = propertyValue ? "3.0.0-latestversion" : "3.0.0-defaultversion"; resolvedVersions.RuntimeFramework["Microsoft.NETCore.App"].Should().Be(expectedRuntimeFrameworkVersion); - resolvedVersions.PackageDownload["Microsoft.NETCore.App"].Should().Be(targetingPackVersion); + resolvedVersions.PackageDownload["Microsoft.NETCore.App.Ref"].Should().Be(targetingPackVersion); string runtimePackName = resolvedVersions.PackageDownload.Keys .Where(k => k.StartsWith("runtime.") && k.EndsWith(".Microsoft.NETCore.App")) .Single(); @@ -407,7 +448,7 @@ public void TargetingPackVersionCanBeSpecifiedOnFrameworkReference() string expectedRuntimeFrameworkVersion = "3.0.0-latestversion"; resolvedVersions.RuntimeFramework["Microsoft.NETCore.App"].Should().Be(expectedRuntimeFrameworkVersion); - resolvedVersions.PackageDownload["Microsoft.NETCore.App"].Should().Be(targetingPackVersion); + resolvedVersions.PackageDownload["Microsoft.NETCore.App.Ref"].Should().Be(targetingPackVersion); string runtimePackName = resolvedVersions.PackageDownload.Keys .Where(k => k.StartsWith("runtime.") && k.EndsWith(".Microsoft.NETCore.App")) .Single(); @@ -427,6 +468,7 @@ private ResolvedVersionInfo GetResolvedVersions(TestProject testProject, testProject.IsSdkProject = true; testProject.IsExe = true; testProject.AdditionalProperties["DisableImplicitFrameworkReferences"] = "true"; + testProject.AdditionalProperties["UseRefTargetingPacks"] = "true"; testProject.RuntimeIdentifier = EnvironmentInfo.GetCompatibleRid(testProject.TargetFrameworks); var testAsset = _testAssetsManager.CreateTestProject(testProject, callingMethod, identifier) diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeManifestSupportedFrameworks.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeManifestSupportedFrameworks.cs index 712825d1b24d..6ab8b9455ef7 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeManifestSupportedFrameworks.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeManifestSupportedFrameworks.cs @@ -28,7 +28,7 @@ public void TheMaximumVersionsAreSupported(string targetFrameworkIdentifier) var project = new TestProject { Name = "packagethatwillgomissing", - TargetFrameworks = targetFrameworkIdentifier == ".NETCoreApp" ? "netcoreapp2.0" : "netstandard2.0", + TargetFrameworks = targetFrameworkIdentifier == ".NETCoreApp" ? "netcoreapp3.0" : "netstandard2.1", IsSdkProject = true, }; @@ -63,7 +63,7 @@ public void TheMaximumVersionsAreSupported(string targetFrameworkIdentifier) string expectedTFM = $"{targetFrameworkIdentifier},Version=v{maximumVersion}"; supportedFrameworks.Should().Contain(expectedTFM, - because: $"Microsoft.NET.SupportedTargetFrameworks.targets should include an entry for {expectedTFM}"); + because: $"Microsoft.NET.SupportedTargetFrameworks.props should include an entry for {expectedTFM}"); } } } diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs index 02e7e6f15e41..a580a940fcd5 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildALibrary.cs @@ -516,7 +516,7 @@ private void TestInvalidTargetFramework(string testName, string targetFramework, [Theory] [InlineData("netcoreapp3.1")] - [InlineData("netstandard2.1")] + [InlineData("netstandard2.2")] public void It_fails_to_build_if_targeting_a_higher_framework_than_is_supported(string targetFramework) { var testProject = new TestProject() diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetStandard2Library.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetStandard2Library.cs index 9bde678fb07a..3bac7df1fbf0 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetStandard2Library.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildANetStandard2Library.cs @@ -24,17 +24,19 @@ public GivenThatWeWantToBuildANetStandard2Library(ITestOutputHelper log) : base( { } - [Fact] - public void It_builds_a_netstandard2_library_successfully() + [Theory] + [InlineData("netstandard2.0")] + [InlineData("netstandard2.1")] + public void It_builds_a_netstandard2_library_successfully(string targetFramework) { TestProject project = new TestProject() { Name = "NetStandard2Library", - TargetFrameworks = "netstandard2.0", + TargetFrameworks = targetFramework, IsSdkProject = true }; - var testAsset = _testAssetsManager.CreateTestProject(project) + var testAsset = _testAssetsManager.CreateTestProject(project, identifier: targetFramework) .Restore(Log, project.Name); string projectFolder = Path.Combine(testAsset.Path, project.Name); diff --git a/src/Tests/Microsoft.NET.Publish.Tests/RuntimeIdentifiersTests.cs b/src/Tests/Microsoft.NET.Publish.Tests/RuntimeIdentifiersTests.cs new file mode 100644 index 000000000000..198d0b5c6e7b --- /dev/null +++ b/src/Tests/Microsoft.NET.Publish.Tests/RuntimeIdentifiersTests.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using FluentAssertions; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.NET.TestFramework; +using Microsoft.NET.TestFramework.Assertions; +using Microsoft.NET.TestFramework.Commands; +using Microsoft.NET.TestFramework.ProjectConstruction; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.NET.Publish.Tests +{ + public class RuntimeIdentifiersTests : SdkTest + { + public RuntimeIdentifiersTests(ITestOutputHelper log) : base(log) + { + } + + // Run on core MSBuild only as using a local packages folder hits long path issues on full MSBuild + [CoreMSBuildOnlyFact] + public void BuildWithRuntimeIdentifier() + { + var testProject = new TestProject() + { + Name = "BuildWithRuntimeIdentifier", + TargetFrameworks = "netcoreapp3.0", + IsSdkProject = true, + IsExe = true + }; + + var compatibleRid = EnvironmentInfo.GetCompatibleRid(testProject.TargetFrameworks); + + var runtimeIdentifiers = new[] + { + "win-x64", + "linux-x64", + compatibleRid + }; + + testProject.AdditionalProperties["RuntimeIdentifiers"] = string.Join(';', runtimeIdentifiers); + + // Use a test-specific packages folder + testProject.AdditionalProperties["RestorePackagesPath"] = @"$(MSBuildProjectDirectory)\packages"; + + var testAsset = _testAssetsManager.CreateTestProject(testProject); + + var restoreCommand = new RestoreCommand(Log, testAsset.Path, testProject.Name); + + restoreCommand + .Execute() + .Should() + .Pass(); + + foreach (var runtimeIdentifier in runtimeIdentifiers) + { + var buildCommand = new BuildCommand(Log, testAsset.Path, testProject.Name); + + buildCommand + .Execute($"/p:RuntimeIdentifier={runtimeIdentifier}") + .Should() + .Pass(); + + if (runtimeIdentifier == compatibleRid) + { + var outputDirectory = buildCommand.GetOutputDirectory(testProject.TargetFrameworks, runtimeIdentifier: runtimeIdentifier); + var selfContainedExecutable = $"{testProject.Name}{Constants.ExeSuffix}"; + string selfContainedExecutableFullPath = Path.Combine(outputDirectory.FullName, selfContainedExecutable); + + Command.Create(selfContainedExecutableFullPath, new string[] { }) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Hello World!"); + } + } + } + + // Run on core MSBuild only as using a local packages folder hits long path issues on full MSBuild + [CoreMSBuildOnlyTheory] + [InlineData(false)] + // "No build" scenario doesn't currently work: https://github.com/dotnet/sdk/issues/2956 + //[InlineData(true)] + public void PublishWithRuntimeIdentifier(bool publishNoBuild) + { + var testProject = new TestProject() + { + Name = "PublishWithRuntimeIdentifier", + TargetFrameworks = "netcoreapp3.0", + IsSdkProject = true, + IsExe = true + }; + + var compatibleRid = EnvironmentInfo.GetCompatibleRid(testProject.TargetFrameworks); + + var runtimeIdentifiers = new[] + { + "win-x64", + "linux-x64", + compatibleRid + }; + + testProject.AdditionalProperties["RuntimeIdentifiers"] = string.Join(';', runtimeIdentifiers); + + // Use a test-specific packages folder + testProject.AdditionalProperties["RestorePackagesPath"] = @"$(MSBuildProjectDirectory)\packages"; + + var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: publishNoBuild ? "nobuild" : string.Empty); + + var buildCommand = new BuildCommand(Log, testAsset.Path, testProject.Name); + + buildCommand + .Execute("/restore") + .Should() + .Pass(); + + foreach (var runtimeIdentifier in runtimeIdentifiers) + { + var publishArgs = new List() + { + $"/p:RuntimeIdentifier={runtimeIdentifier}" + }; + if (publishNoBuild) + { + publishArgs.Add("/p:NoBuild=true"); + } + + var publishCommand = new PublishCommand(Log, Path.Combine(testAsset.Path, testProject.Name)); + publishCommand.Execute(publishArgs.ToArray()) + .Should() + .Pass(); + + if (runtimeIdentifier == compatibleRid) + { + var outputDirectory = publishCommand.GetOutputDirectory(testProject.TargetFrameworks, runtimeIdentifier: runtimeIdentifier); + var selfContainedExecutable = $"{testProject.Name}{Constants.ExeSuffix}"; + string selfContainedExecutableFullPath = Path.Combine(outputDirectory.FullName, selfContainedExecutable); + + Command.Create(selfContainedExecutableFullPath, new string[] { }) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Hello World!"); + + } + } + } + + [Fact] + public void DuplicateRuntimeIdentifiers() + { + var testProject = new TestProject() + { + Name = "DuplicateRuntimeIdentifiers", + TargetFrameworks = "netcoreapp3.0", + IsSdkProject = true, + IsExe = true + }; + + var compatibleRid = EnvironmentInfo.GetCompatibleRid(testProject.TargetFrameworks); + + testProject.AdditionalProperties["RuntimeIdentifiers"] = compatibleRid + ";" + compatibleRid; + testProject.RuntimeIdentifier = compatibleRid; + + var testAsset = _testAssetsManager.CreateTestProject(testProject) + .Restore(Log, testProject.Name); + + var buildCommand = new BuildCommand(Log, testAsset.Path, testProject.Name); + + buildCommand + .Execute() + .Should() + .Pass(); + + + + + } + } +}