diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs b/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs index d66082e79310..3452689a8c77 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/LockFileExtensions.cs @@ -13,25 +13,39 @@ namespace Microsoft.NET.Build.Tasks { internal static class LockFileExtensions { - public static LockFileTarget GetTargetAndThrowIfNotFound(this LockFile lockFile, string frameworkAlias, string runtime) + public static LockFileTarget GetTargetAndReturnNullIfNotFound(this LockFile lockFile, string frameworkAlias, string runtimeIdentifier) { - LockFileTarget lockFileTarget = lockFile.GetTarget(frameworkAlias, runtime); + LockFileTarget lockFileTarget = lockFile.GetTarget(frameworkAlias, runtimeIdentifier); + + if (lockFileTarget == null && + lockFile.PackageSpec.TargetFrameworks.All(tfi => string.IsNullOrEmpty(tfi.TargetAlias))) + { + var nuGetFramework = NuGetUtils.ParseFrameworkName(frameworkAlias); + lockFileTarget = lockFile.GetTarget(nuGetFramework, runtimeIdentifier); + } + + return lockFileTarget; + } + + public static LockFileTarget GetTargetAndThrowIfNotFound(this LockFile lockFile, string frameworkAlias, string runtimeIdentifier) + { + LockFileTarget lockFileTarget = lockFile.GetTargetAndReturnNullIfNotFound(frameworkAlias, runtimeIdentifier); if (lockFileTarget == null) { string frameworkString = frameworkAlias; - string targetMoniker = string.IsNullOrEmpty(runtime) ? + string targetMoniker = string.IsNullOrEmpty(runtimeIdentifier) ? frameworkString : - $"{frameworkString}/{runtime}"; + $"{frameworkString}/{runtimeIdentifier}"; string message; - if (string.IsNullOrEmpty(runtime)) + if (string.IsNullOrEmpty(runtimeIdentifier)) { message = string.Format(Strings.AssetsFileMissingTarget, lockFile.Path, targetMoniker, frameworkString); } else { - message = string.Format(Strings.AssetsFileMissingRuntimeIdentifier, lockFile.Path, targetMoniker, frameworkString, runtime); + message = string.Format(Strings.AssetsFileMissingRuntimeIdentifier, lockFile.Path, targetMoniker, frameworkString, runtimeIdentifier); } throw new BuildErrorException(message); diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs index d65b3a470ce8..840897e4bb54 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ResolvePackageAssets.cs @@ -663,8 +663,8 @@ public CacheWriter(ResolvePackageAssets task) CanWriteToCacheFile = true; if (task.DesignTimeBuild) { - _compileTimeTarget = _lockFile.GetTarget(_targetFramework, runtimeIdentifier: null); - _runtimeTarget = _lockFile.GetTarget(_targetFramework, _task.RuntimeIdentifier); + _compileTimeTarget = _lockFile.GetTargetAndReturnNullIfNotFound(_targetFramework, runtimeIdentifier: null); + _runtimeTarget = _lockFile.GetTargetAndReturnNullIfNotFound(_targetFramework, _task.RuntimeIdentifier); if (_compileTimeTarget == null) { _compileTimeTarget = new LockFileTarget(); @@ -678,7 +678,7 @@ public CacheWriter(ResolvePackageAssets task) } else { - _compileTimeTarget = _lockFile.GetTargetAndThrowIfNotFound(_targetFramework, runtime: null); + _compileTimeTarget = _lockFile.GetTargetAndThrowIfNotFound(_targetFramework, runtimeIdentifier: null); _runtimeTarget = _lockFile.GetTargetAndThrowIfNotFound(_targetFramework, _task.RuntimeIdentifier); } @@ -1065,7 +1065,7 @@ private void WriteApphostsForShimRuntimeIdentifiers() LockFileTarget runtimeTarget; if (_task.DesignTimeBuild) { - runtimeTarget = _lockFile.GetTarget(_targetFramework, runtimeIdentifier) ?? new LockFileTarget(); + runtimeTarget = _lockFile.GetTargetAndReturnNullIfNotFound(_targetFramework, runtimeIdentifier) ?? new LockFileTarget(); } else { @@ -1095,7 +1095,7 @@ private bool CanResolveApphostFromFrameworkReference() } else { - var targetFramework = _lockFile.GetTarget(_targetFramework, null).TargetFramework; + var targetFramework = _lockFile.GetTargetAndThrowIfNotFound(_targetFramework, null).TargetFramework; if (targetFramework.Version.Major >= 3 && targetFramework.Framework.Equals(".NETCoreApp", StringComparison.OrdinalIgnoreCase)) diff --git a/src/Tests/Microsoft.NET.Restore.Tests/RestoreWithOlderNuGet.cs b/src/Tests/Microsoft.NET.Restore.Tests/RestoreWithOlderNuGet.cs new file mode 100644 index 000000000000..d2ef677b8e17 --- /dev/null +++ b/src/Tests/Microsoft.NET.Restore.Tests/RestoreWithOlderNuGet.cs @@ -0,0 +1,50 @@ +// 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.NET.TestFramework; +using Microsoft.NET.TestFramework.Assertions; +using Microsoft.NET.TestFramework.Commands; +using Microsoft.NET.TestFramework.ProjectConstruction; +using NuGet.Common; +using NuGet.Packaging; +using NuGet.Packaging.Core; +using System.IO; +using System.Threading; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.NET.Restore.Tests +{ + public class RestoreWithOlderNuGet : SdkTest + { + public RestoreWithOlderNuGet(ITestOutputHelper log) : base(log) + { + } + + [Fact] + public void ItCanBuildProjectRestoredWithNuGet5_7() + { + var testProject = new TestProject() + { + TargetFrameworks = "netcoreapp3.1", + IsSdkProject = true + }; + testProject.PackageReferences.Add(new TestPackageReference("Humanizer.Core", "2.8.26")); + + var testAsset = _testAssetsManager.CreateTestProject(testProject); + + var restoreCommand = new NuGetExeRestoreCommand(Log, testAsset.Path, testProject.Name); + restoreCommand.NuGetExeVersion = "5.7.0"; + restoreCommand.Execute() + .Should() + .Pass(); + + new BuildCommand(testAsset) + .ExecuteWithoutRestore() + .Should() + .Pass(); + } + } +} diff --git a/src/Tests/Microsoft.NET.TestFramework/Commands/NuGetExeRestoreCommand.cs b/src/Tests/Microsoft.NET.TestFramework/Commands/NuGetExeRestoreCommand.cs index 91cf3df7e608..13ad36333763 100644 --- a/src/Tests/Microsoft.NET.TestFramework/Commands/NuGetExeRestoreCommand.cs +++ b/src/Tests/Microsoft.NET.TestFramework/Commands/NuGetExeRestoreCommand.cs @@ -18,6 +18,8 @@ public class NuGetExeRestoreCommand : TestCommand public string ProjectFile { get; } + public string NuGetExeVersion { get; set; } + public string FullPathProjectFile => Path.Combine(ProjectRootPath, ProjectFile); public NuGetExeRestoreCommand(ITestOutputHelper log, string projectRootPath, string relativePathToProject = null) : base(log) @@ -43,19 +45,36 @@ protected override SdkCommandSpec CreateCommand(IEnumerable args) { throw new InvalidOperationException("Path to nuget.exe not set"); } - else if (!File.Exists(TestContext.Current.NuGetExePath)) + + var nugetExePath = TestContext.Current.NuGetExePath; + if (!string.IsNullOrEmpty(NuGetExeVersion)) { - // https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + nugetExePath = Path.Combine(Path.GetDirectoryName(nugetExePath), NuGetExeVersion, "nuget.exe"); + } + + if (!File.Exists(nugetExePath)) + { + string directory = Path.GetDirectoryName(nugetExePath); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + string url = string.IsNullOrEmpty(NuGetExeVersion) ? + "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" : + $"https://dist.nuget.org/win-x86-commandline/v{NuGetExeVersion}/nuget.exe"; var client = new System.Net.WebClient(); - client.DownloadFile("https://dist.nuget.org/win-x86-commandline/latest/nuget.exe", TestContext.Current.NuGetExePath); + client.DownloadFile(url, nugetExePath); } var ret = new SdkCommandSpec() { - FileName = TestContext.Current.NuGetExePath, + FileName = nugetExePath, Arguments = newArgs }; + TestContext.Current.AddTestEnvironmentVariables(ret); + return ret; } }