diff --git a/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/AppWithDepOnTool.csproj b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/AppWithDepOnTool.csproj
new file mode 100644
index 000000000..2185f85a6
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/AppWithDepOnTool.csproj
@@ -0,0 +1,21 @@
+
+
+
+ Exe
+ netcoreapp1.0
+ random-name
+
+
+
+
+
+
+
+
+
+
+ 1.0.0
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/NuGet.Config b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/NuGet.Config
new file mode 100644
index 000000000..97af9d3d0
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/NuGet.Config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/Program.cs b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/Program.cs
new file mode 100644
index 000000000..846370cce
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/AppWithDepOnTool/Program.cs
@@ -0,0 +1,8 @@
+using System;
+
+class Program
+{
+ static void Main(string[] args)
+ {
+ }
+}
diff --git a/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/ToolWithRandomPackageName/Program.cs b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/ToolWithRandomPackageName/Program.cs
new file mode 100644
index 000000000..a95e5a932
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/ToolWithRandomPackageName/Program.cs
@@ -0,0 +1,9 @@
+using System;
+
+class Program
+{
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Hello World from tool!");
+ }
+}
diff --git a/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/ToolWithRandomPackageName/ToolWithRandomPackageName.csproj b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/ToolWithRandomPackageName/ToolWithRandomPackageName.csproj
new file mode 100644
index 000000000..f7037e0c6
--- /dev/null
+++ b/TestAssets/NonRestoredTestProjects/ToolWithRandomPackageName/ToolWithRandomPackageName/ToolWithRandomPackageName.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ netcoreapp1.0
+ random-name
+ $(GeneratedPackageId)
+ dotnet-randompackage
+
+
+
+
+
+
+ true
+ lib\$(TargetFramework)
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IProject.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IProject.cs
index d0d43dc57..89d22bbbf 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IProject.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IProject.cs
@@ -10,6 +10,8 @@ namespace Microsoft.DotNet.Cli.Utils
{
LockFile GetLockFile();
+ bool TryGetLockFile(out LockFile lockFile);
+
IEnumerable GetTools();
string DepsJsonPath { get; }
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs
index a653821f6..4b6cda0e4 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/MSBuildProject.cs
@@ -129,6 +129,29 @@ namespace Microsoft.DotNet.Cli.Utils
.Result;
}
+ public bool TryGetLockFile(out LockFile lockFile)
+ {
+ lockFile = null;
+
+ var lockFilePath = GetLockFilePathFromProjectLockFileProperty() ??
+ GetLockFilePathFromIntermediateBaseOutputPath();
+
+ if (lockFilePath == null)
+ {
+ return false;
+ }
+
+ if (!File.Exists(lockFilePath))
+ {
+ return false;
+ }
+
+ lockFile = new LockFileFormat()
+ .ReadWithLock(lockFilePath)
+ .Result;
+ return true;
+ }
+
private string GetLockFilePathFromProjectLockFileProperty()
{
return _project
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs
index bda9a4250..b4edd7583 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectToolsCommandResolver.cs
@@ -127,16 +127,19 @@ namespace Microsoft.DotNet.Cli.Utils
ProjectToolsCommandResolverName,
toolLibraryRange.Name));
- var nuGetPathContext = NuGetPathContext.Create(project.ProjectRoot);
-
- var nugetPackagesRoot = nuGetPathContext.UserPackageFolder;
-
+ var possiblePackageRoots = GetPossiblePackageRoots(project).ToList();
Reporter.Verbose.WriteLine(string.Format(
LocalizableStrings.NuGetPackagesRoot,
ProjectToolsCommandResolverName,
- nugetPackagesRoot));
+ string.Join(Environment.NewLine, possiblePackageRoots.Select((p) => $"- {p}"))));
- var toolLockFile = GetToolLockFile(toolLibraryRange, nugetPackagesRoot);
+ string nugetPackagesRoot;
+ var toolLockFile = GetToolLockFile(toolLibraryRange, possiblePackageRoots, out nugetPackagesRoot);
+
+ if (toolLockFile == null)
+ {
+ return null;
+ }
Reporter.Verbose.WriteLine(string.Format(
LocalizableStrings.FoundToolLockFile,
@@ -189,19 +192,33 @@ namespace Microsoft.DotNet.Cli.Utils
return commandSpec;
}
- private LockFile GetToolLockFile(
- SingleProjectInfo toolLibrary,
- string nugetPackagesRoot)
+ private IEnumerable GetPossiblePackageRoots(IProject project)
{
+ if (project.TryGetLockFile(out LockFile lockFile))
+ {
+ foreach (var packageFolder in lockFile.PackageFolders)
+ {
+ yield return packageFolder.Path;
+ }
+ }
+
+ var nuGetPathContext = NuGetPathContext.Create(project.ProjectRoot);
+ yield return nuGetPathContext.UserPackageFolder;
+ }
+
+ private bool TryGetToolLockFile(
+ SingleProjectInfo toolLibrary,
+ string nugetPackagesRoot,
+ out LockFile lockFile)
+ {
+ lockFile = null;
var lockFilePath = GetToolLockFilePath(toolLibrary, nugetPackagesRoot);
if (!File.Exists(lockFilePath))
{
- return null;
+ return false;
}
- LockFile lockFile = null;
-
try
{
lockFile = new LockFileFormat()
@@ -213,7 +230,22 @@ namespace Microsoft.DotNet.Cli.Utils
throw ex;
}
- return lockFile;
+ return true;
+ }
+
+ private LockFile GetToolLockFile(SingleProjectInfo toolLibrary, IEnumerable possibleNugetPackagesRoot, out string nugetPackagesRoot)
+ {
+ foreach (var packagesRoot in possibleNugetPackagesRoot)
+ {
+ if (TryGetToolLockFile(toolLibrary, packagesRoot, out LockFile lockFile))
+ {
+ nugetPackagesRoot = packagesRoot;
+ return lockFile;
+ }
+ }
+
+ nugetPackagesRoot = null;
+ return null;
}
private string GetToolLockFilePath(
diff --git a/test/dotnet.Tests/MSBuild.exe b/test/dotnet.Tests/MSBuild.exe
new file mode 100644
index 000000000..2b4d0f999
--- /dev/null
+++ b/test/dotnet.Tests/MSBuild.exe
@@ -0,0 +1 @@
+https://github.com/Microsoft/msbuild/issues/927
\ No newline at end of file
diff --git a/test/dotnet.Tests/MSBuild.exe.config b/test/dotnet.Tests/MSBuild.exe.config
new file mode 100644
index 000000000..2b4d0f999
--- /dev/null
+++ b/test/dotnet.Tests/MSBuild.exe.config
@@ -0,0 +1 @@
+https://github.com/Microsoft/msbuild/issues/927
\ No newline at end of file
diff --git a/test/dotnet.Tests/PackagedCommandTests.cs b/test/dotnet.Tests/PackagedCommandTests.cs
index 0906063d2..441eba5be 100644
--- a/test/dotnet.Tests/PackagedCommandTests.cs
+++ b/test/dotnet.Tests/PackagedCommandTests.cs
@@ -13,6 +13,9 @@ using Microsoft.DotNet.Tools.Test.Utilities;
using Microsoft.DotNet.InternalAbstractions;
using Xunit;
using Xunit.Abstractions;
+using Microsoft.Build.Construction;
+using System.Linq;
+using Microsoft.Build.Evaluation;
namespace Microsoft.DotNet.Tests
{
@@ -138,6 +141,52 @@ namespace Microsoft.DotNet.Tests
.And.HaveStdErrContaining("Version for package `dotnet-nonexistingtool` could not be resolved.");
}
+ [Fact]
+ public void ItRunsToolRestoredToSpecificPackageDir()
+ {
+ var testInstance = TestAssets.Get("NonRestoredTestProjects", "ToolWithRandomPackageName")
+ .CreateInstance()
+ .WithSourceFiles();
+
+ var appWithDepOnToolDir = testInstance.Root.Sub("AppWithDepOnTool");
+ var toolWithRandPkgNameDir = testInstance.Root.Sub("ToolWithRandomPackageName");
+ var pkgsDir = testInstance.Root.CreateSubdirectory("pkgs");
+
+ string randomPackageName = Guid.NewGuid().ToString();
+
+ // TODO: This is a workround for https://github.com/dotnet/cli/issues/5020
+ SetGeneratedPackageName(appWithDepOnToolDir.GetFile("AppWithDepOnTool.csproj"),
+ randomPackageName);
+
+ SetGeneratedPackageName(toolWithRandPkgNameDir.GetFile("ToolWithRandomPackageName.csproj"),
+ randomPackageName);
+
+ new RestoreCommand()
+ .WithWorkingDirectory(toolWithRandPkgNameDir)
+ .ExecuteWithCapturedOutput()
+ .Should().Pass()
+ .And.NotHaveStdErr();
+
+ new PackCommand()
+ .WithWorkingDirectory(toolWithRandPkgNameDir)
+ .ExecuteWithCapturedOutput($"-o \"{pkgsDir.FullName}\"")
+ .Should().Pass()
+ .And.NotHaveStdErr();
+
+ new RestoreCommand()
+ .WithWorkingDirectory(appWithDepOnToolDir)
+ .ExecuteWithCapturedOutput($"--packages \"{pkgsDir.FullName}\"")
+ .Should().Pass()
+ .And.NotHaveStdErr();
+
+ new TestCommand("dotnet")
+ .WithWorkingDirectory(appWithDepOnToolDir)
+ .ExecuteWithCapturedOutput("randompackage")
+ .Should().Pass()
+ .And.HaveStdOutContaining("Hello World from tool!")
+ .And.NotHaveStdErr();
+ }
+
// need conditional theories so we can skip on non-Windows
//[Theory(Skip="https://github.com/dotnet/cli/issues/4514")]
//[MemberData("DependencyToolArguments")]
@@ -294,6 +343,14 @@ namespace Microsoft.DotNet.Tests
stopWatch.ElapsedMilliseconds.Should().BeGreaterThan(1000, "Because dotnet should respect the NuGet lock");
}
+ private void SetGeneratedPackageName(FileInfo project, string packageName)
+ {
+ const string propertyName = "GeneratedPackageId";
+ var p = ProjectRootElement.Open(project.FullName, new ProjectCollection(), true);
+ p.AddProperty(propertyName, packageName);
+ p.Save();
+ }
+
class HelloCommand : TestCommand
{
public HelloCommand()