diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs index 7cd9a6113..a75472142 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs @@ -134,12 +134,35 @@ namespace Microsoft.DotNet.Cli.Utils ProjectToolsCommandResolverName, string.Join(Environment.NewLine, possiblePackageRoots.Select((p) => $"- {p}")))); - var toolPackageFramework = project.DotnetCliToolTargetFramework; + List toolFrameworksToCheck = new List(); + toolFrameworksToCheck.Add(project.DotnetCliToolTargetFramework); - var toolLockFile = GetToolLockFile( - toolLibraryRange, - toolPackageFramework, - possiblePackageRoots); + // NuGet restore in Visual Studio may restore for netcoreapp1.0. So if that happens, fall back to + // looking for a netcoreapp1.0 or netcoreapp1.1 tool restore. + if (project.DotnetCliToolTargetFramework.Framework == FrameworkConstants.FrameworkIdentifiers.NetCoreApp && + project.DotnetCliToolTargetFramework.Version >= new Version(2, 0, 0)) + { + toolFrameworksToCheck.Add(NuGetFramework.Parse("netcoreapp1.1")); + toolFrameworksToCheck.Add(NuGetFramework.Parse("netcoreapp1.0")); + } + + + LockFile toolLockFile = null; + NuGetFramework toolTargetFramework = null; ; + + foreach (var toolFramework in toolFrameworksToCheck) + { + toolLockFile = GetToolLockFile( + toolLibraryRange, + toolFramework, + possiblePackageRoots); + + if (toolLockFile != null) + { + toolTargetFramework = toolFramework; + break; + } + } if (toolLockFile == null) { @@ -152,7 +175,7 @@ namespace Microsoft.DotNet.Cli.Utils toolLockFile.Path)); var toolLibrary = toolLockFile.Targets - .FirstOrDefault(t => toolPackageFramework == t.TargetFramework) + .FirstOrDefault(t => toolTargetFramework == t.TargetFramework) ?.Libraries.FirstOrDefault( l => StringComparer.OrdinalIgnoreCase.Equals(l.Name, toolLibraryRange.Name)); if (toolLibrary == null) @@ -168,7 +191,7 @@ namespace Microsoft.DotNet.Cli.Utils var depsFilePath = GetToolDepsFilePath( toolLibraryRange, - toolPackageFramework, + toolTargetFramework, toolLockFile, depsFileRoot, project.ToolDepsJsonGeneratorProject); diff --git a/test/dotnet.Tests/PackagedCommandTests.cs b/test/dotnet.Tests/PackagedCommandTests.cs index bb75131d5..d5c83d97a 100644 --- a/test/dotnet.Tests/PackagedCommandTests.cs +++ b/test/dotnet.Tests/PackagedCommandTests.cs @@ -16,6 +16,7 @@ using Xunit.Abstractions; using Microsoft.Build.Construction; using System.Linq; using Microsoft.Build.Evaluation; +using System.Xml.Linq; namespace Microsoft.DotNet.Tests { @@ -161,10 +162,62 @@ namespace Microsoft.DotNet.Tests .Execute(toolPrefersCLIRuntime ? "portable-v1-prefercli" : "portable-v1"); result.Should().Pass() - .And.HaveStdOutContaining("I'm running on shared framework version 1.1.1!"); + .And.HaveStdOutContaining("I'm running on shared framework version 1.1.1!"); } + [RequiresSpecificFrameworkFact("netcoreapp1.1")] + public void IfAToolHasNotBeenRestoredForNetCoreApp2_0ItFallsBackToNetCoreApp1_x() + { + string toolName = "dotnet-portable-v1"; + + var toolFolder = Path.Combine(new RepoDirectoriesProvider().NugetPackages, + ".tools", + toolName); + + // Other tests may have restored the tool for netcoreapp2.0, so delete its tools folder + if (Directory.Exists(toolFolder)) + { + Directory.Delete(toolFolder, true); + } + + var testInstance = TestAssets.Get("AppWithToolDependency") + .CreateInstance() + .WithSourceFiles() + .WithNuGetConfig(new RepoDirectoriesProvider().TestPackages); + + testInstance = testInstance.WithProjectChanges(project => + { + var ns = project.Root.Name.Namespace; + + // Remove reference to tool that won't restore on 1.x + project.Descendants(ns + "DotNetCliToolReference") + .Where(tr => tr.Attribute("Include").Value == "dotnet-PreferCliRuntime") + .Remove(); + + var toolReference = project.Descendants(ns + "DotNetCliToolReference") + .Where(tr => tr.Attribute("Include").Value == "dotnet-portable") + .Single(); + + toolReference.Attribute("Include").Value = toolName; + + // Restore tools for .NET Core 1.1 + project.Root.Element(ns + "PropertyGroup") + .Add(new XElement(ns + "DotnetCliToolTargetFramework", "netcoreapp1.1")); + + }); + + testInstance = testInstance.WithRestoreFiles(); + + var result = + new DotnetCommand(DotnetUnderTest.WithBackwardsCompatibleRuntimes) + .WithWorkingDirectory(testInstance.Root) + .Execute("portable-v1"); + + result.Should().Pass() + .And.HaveStdOutContaining("I'm running on shared framework version 1.1.1!"); + } + [Fact] public void CanInvokeToolWhosePackageNameIsDifferentFromDllName() {