From 1aac8fb643da46e64ea1a04cd074b7c7e4c51330 Mon Sep 17 00:00:00 2001 From: moozzyk Date: Wed, 20 Apr 2016 16:05:53 -0700 Subject: [PATCH] Fixing ProjectDependenciesCommandFactory to resolve tools if the package name is different from the dll name Addresses #2592 --- .../ToolWithOutputName/Program.cs | 12 ++++ .../ToolWithOutputName/project.json | 17 +++++ .../Program.cs | 12 ++++ .../project.json | 22 ++++++ .../Program.cs | 12 ++++ .../project.json | 27 +++++++ .../AppWithOutputAssemblyName/project.json | 3 +- .../dotnet-cli-build/TestPackageProjects.cs | 12 +++- .../ProjectDependenciesCommandResolver.cs | 20 ++++-- ...GivenAProjectDependenciesCommandFactory.cs | 43 ++++++++++-- test/dotnet.Tests/PackagedCommandTests.cs | 70 +++++++++++++++++-- test/dotnet.Tests/project.json | 2 + 12 files changed, 231 insertions(+), 21 deletions(-) create mode 100644 TestAssets/TestPackages/ToolWithOutputName/Program.cs create mode 100644 TestAssets/TestPackages/ToolWithOutputName/project.json create mode 100644 TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/Program.cs create mode 100644 TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/project.json create mode 100644 TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/Program.cs create mode 100644 TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/project.json diff --git a/TestAssets/TestPackages/ToolWithOutputName/Program.cs b/TestAssets/TestPackages/ToolWithOutputName/Program.cs new file mode 100644 index 000000000..bfb5997b1 --- /dev/null +++ b/TestAssets/TestPackages/ToolWithOutputName/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Tool with output name!"); + } + } +} diff --git a/TestAssets/TestPackages/ToolWithOutputName/project.json b/TestAssets/TestPackages/ToolWithOutputName/project.json new file mode 100644 index 000000000..e945eea0b --- /dev/null +++ b/TestAssets/TestPackages/ToolWithOutputName/project.json @@ -0,0 +1,17 @@ +{ + "version": "1.0.0", + "compilationOptions": { + "outputName": "dotnet-tool-with-output-name", + "emitEntryPoint": true + }, + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0-rc2-*" + } + } + } + } +} \ No newline at end of file diff --git a/TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/Program.cs b/TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/Program.cs new file mode 100644 index 000000000..861f84043 --- /dev/null +++ b/TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("App with a dependency on a tool whose package name is different from the dll name!"); + } + } +} diff --git a/TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/project.json b/TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/project.json new file mode 100644 index 000000000..f2d28ce97 --- /dev/null +++ b/TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/project.json @@ -0,0 +1,22 @@ +{ + "version": "1.0.0-*", + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "Microsoft.NETCore.App": { + "version": "1.0.0-rc2-*", + "type": "platform" + } + }, + "frameworks": { + "netcoreapp1.0": { } + }, + + "tools": { + "ToolWithOutputName": { + "version": "1.0.0", + "target": "package" + } + } +} diff --git a/TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/Program.cs b/TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/Program.cs new file mode 100644 index 000000000..29cf4486f --- /dev/null +++ b/TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Contains a dependency on a tool whose package name is different from the dll name."); + } + } +} diff --git a/TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/project.json b/TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/project.json new file mode 100644 index 000000000..e3e98f78b --- /dev/null +++ b/TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/project.json @@ -0,0 +1,27 @@ +{ + "compilationOptions": { + "emitEntryPoint": true + }, + "dependencies": { + "ToolWithOutputName": { + "version": "1.0.0", + "target": "package" + }, + "Microsoft.NETCore.App": { + "version": "1.0.0-rc2-*", + "type": "platform" + } + }, + "frameworks": { + "netcoreapp1.0": { } + }, + "tools": { + "dotnet-dependency-tool-invoker": { + "version": "1.0.0-*", + "imports": [ + "dnxcore50", + "portable-net45+win8" + ] + } + } +} diff --git a/TestAssets/TestProjects/AppWithOutputAssemblyName/project.json b/TestAssets/TestProjects/AppWithOutputAssemblyName/project.json index 46d388e27..a30d8d82d 100644 --- a/TestAssets/TestProjects/AppWithOutputAssemblyName/project.json +++ b/TestAssets/TestProjects/AppWithOutputAssemblyName/project.json @@ -1,8 +1,7 @@ { "compilationOptions": { "outputName": "MyApp", - "emitEntryPoint": true, - "preserveCompilationContext": true + "emitEntryPoint": true }, "dependencies": { "Microsoft.NETCore.App": "1.0.0-rc2-*" diff --git a/scripts/dotnet-cli-build/TestPackageProjects.cs b/scripts/dotnet-cli-build/TestPackageProjects.cs index fc8f17a49..ad228211f 100644 --- a/scripts/dotnet-cli-build/TestPackageProjects.cs +++ b/scripts/dotnet-cli-build/TestPackageProjects.cs @@ -61,7 +61,7 @@ namespace Microsoft.DotNet.Cli.Build Name = "dotnet-dependency-tool-invoker", IsTool = true, Path = "TestAssets/TestPackages/dotnet-dependency-tool-invoker", - IsApplicable = CurrentPlatform.IsWindows, + IsApplicable = true, VersionSuffix = s_testPackageBuildVersionSuffix, Clean = true, Frameworks = new [] { "netcoreapp1.0" } @@ -107,6 +107,16 @@ namespace Microsoft.DotNet.Cli.Build Frameworks = new [] { "netcoreapp1.0" } }, new TestPackageProject() + { + Name = "ToolWithOutputName", + IsTool = true, + Path = "TestAssets/TestPackages/ToolWithOutputName", + IsApplicable = true, + VersionSuffix = string.Empty, + Clean = true, + Frameworks = new [] { "netcoreapp1.0" } + }, + new TestPackageProject() { Name = "Microsoft.DotNet.Cli.Utils", IsTool = true, diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs index b1c356d26..9cd097fe2 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/ProjectDependenciesCommandResolver.cs @@ -11,7 +11,7 @@ namespace Microsoft.DotNet.Cli.Utils { public class ProjectDependenciesCommandResolver : ICommandResolver { - private static readonly CommandResolutionStrategy s_commandResolutionStrategy = + private static readonly CommandResolutionStrategy s_commandResolutionStrategy = CommandResolutionStrategy.ProjectDependenciesPackage; private readonly IEnvironmentProvider _environment; @@ -78,7 +78,7 @@ namespace Microsoft.DotNet.Cli.Utils var depsFilePath = projectContext.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeFiles.DepsJson; - var runtimeConfigPath = + var runtimeConfigPath = projectContext.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeFiles.RuntimeConfigJson; var toolLibrary = GetToolLibraryForContext(projectContext, commandName); @@ -97,12 +97,18 @@ namespace Microsoft.DotNet.Cli.Utils private LockFileTargetLibrary GetToolLibraryForContext( ProjectContext projectContext, string commandName) { - var toolLibrary = projectContext.LockFile.Targets + var toolLibraries = projectContext.LockFile.Targets .FirstOrDefault(t => t.TargetFramework.GetShortFolderName() .Equals(projectContext.TargetFramework.GetShortFolderName())) - ?.Libraries.FirstOrDefault(l => l.Name == commandName); + ?.Libraries.Where(l => l.Name == commandName || + l.RuntimeAssemblies.Any(r => Path.GetFileNameWithoutExtension(r.Path) == commandName)).ToList(); - return toolLibrary; + if (toolLibraries?.Count() > 1) + { + throw new InvalidOperationException($"Ambiguous command name: {commandName}"); + } + + return toolLibraries?.FirstOrDefault(); } private ProjectContext GetProjectContextFromDirectory(string directory, NuGetFramework framework) @@ -120,8 +126,8 @@ namespace Microsoft.DotNet.Cli.Utils } return ProjectContext.Create( - projectRootPath, - framework, + projectRootPath, + framework, PlatformServices.Default.Runtime.GetAllCandidateRuntimeIdentifiers()); } diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectDependenciesCommandFactory.cs b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectDependenciesCommandFactory.cs index 3d62d3e01..758cc599e 100644 --- a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectDependenciesCommandFactory.cs +++ b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenAProjectDependenciesCommandFactory.cs @@ -22,8 +22,8 @@ namespace Microsoft.DotNet.Cli.Utils.Tests { public class GivenAProjectDependenciesCommandFactory : TestBase { - private static readonly NuGetFramework s_desktopTestFramework = FrameworkConstants.CommonFrameworks.Net451; - + private static readonly NuGetFramework s_desktopTestFramework = FrameworkConstants.CommonFrameworks.Net451; + [WindowsOnlyFact] public void It_resolves_desktop_apps_defaulting_to_Debug_Configuration() { @@ -34,7 +34,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests .WithLockFiles(); var buildCommand = new BuildCommand( - Path.Combine(testInstance.TestRoot, "project.json"), + Path.Combine(testInstance.TestRoot, "project.json"), configuration: configuration) .ExecuteWithCapturedOutput() .Should() @@ -65,7 +65,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests .WithLockFiles(); var buildCommand = new BuildCommand( - Path.Combine(testInstance.TestRoot, "project.json"), + Path.Combine(testInstance.TestRoot, "project.json"), configuration: configuration) .ExecuteWithCapturedOutput() .Should() @@ -96,7 +96,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests .WithLockFiles(); var buildCommand = new BuildCommand( - Path.Combine(testInstance.TestRoot, "project.json"), + Path.Combine(testInstance.TestRoot, "project.json"), configuration: configuration) .ExecuteWithCapturedOutput() .Should() @@ -127,7 +127,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests .WithLockFiles(); var buildCommand = new BuildCommand( - Path.Combine(testInstance.TestRoot, "project.json"), + Path.Combine(testInstance.TestRoot, "project.json"), configuration: configuration) .ExecuteWithCapturedOutput() .Should() @@ -147,5 +147,36 @@ namespace Microsoft.DotNet.Cli.Utils.Tests command.CommandName.Should().Contain(Path.Combine(testInstance.TestRoot, "bin", configuration)); Path.GetFileName(command.CommandName).Should().Be("dotnet-desktop-and-portable.exe"); } + + [Fact] + public void It_resolves_tools_whose_package_name_is_different_than_dll_name() + { + var configuration = "Debug"; + + var testAssetManager = new TestAssetsManager(Path.Combine(RepoRoot, "TestAssets", "TestProjects")); + var testInstance = testAssetManager.CreateTestInstance("AppWithDirectDependencyWithOutputName") + .WithLockFiles(); + + var buildCommand = new BuildCommand( + Path.Combine(testInstance.TestRoot, "project.json"), + configuration: configuration) + .ExecuteWithCapturedOutput() + .Should() + .Pass(); + + var context = ProjectContext.Create(testInstance.TestRoot, FrameworkConstants.CommonFrameworks.NetCoreApp10); + + var factory = new ProjectDependenciesCommandFactory( + FrameworkConstants.CommonFrameworks.NetCoreApp10, + configuration, + null, + null, + testInstance.TestRoot); + + var command = factory.Create("dotnet-tool-with-output-name", null); + + command.CommandArgs.Should().Contain( + Path.Combine("ToolWithOutputName", "1.0.0", "lib", "netcoreapp1.0", "dotnet-tool-with-output-name.dll")); + } } } diff --git a/test/dotnet.Tests/PackagedCommandTests.cs b/test/dotnet.Tests/PackagedCommandTests.cs index fb425e342..45a95a388 100644 --- a/test/dotnet.Tests/PackagedCommandTests.cs +++ b/test/dotnet.Tests/PackagedCommandTests.cs @@ -44,6 +44,43 @@ namespace Microsoft.DotNet.Tests result.Should().Pass(); } + [Fact] + public void CanInvokeToolWhosePackageNameIsDifferentFromDllName() + { + var appDirectory = Path.Combine(_testProjectsRoot, "AppWithDependencyOnToolWithOutputName"); + + new BuildCommand(Path.Combine(appDirectory, "project.json")) + .Execute() + .Should() + .Pass(); + + CommandResult result = new GenericCommand("tool-with-output-name") { WorkingDirectory = appDirectory } + .ExecuteWithCapturedOutput(); + + result.Should().HaveStdOutContaining("Tool with output name!"); + result.Should().NotHaveStdErr(); + result.Should().Pass(); + } + + [Fact] + public void CanInvokeToolFromDirectDependenciesIfPackageNameDifferentFromToolName() + { + var appDirectory = Path.Combine(_testProjectsRoot, "AppWithDirectDependencyWithOutputName"); + const string framework = ".NETCoreApp,Version=v1.0"; + + new BuildCommand(Path.Combine(appDirectory, "project.json")) + .Execute() + .Should() + .Pass(); + + CommandResult result = new DependencyToolInvokerCommand { WorkingDirectory = appDirectory } + .ExecuteWithCapturedOutput("tool-with-output-name", framework, string.Empty); + + result.Should().HaveStdOutContaining("Tool with output name!"); + result.Should().NotHaveStdErr(); + result.Should().Pass(); + } + // need conditional theories so we can skip on non-Windows [Theory] [MemberData("DependencyToolArguments")] @@ -62,7 +99,7 @@ namespace Microsoft.DotNet.Tests .Pass(); CommandResult result = new DependencyToolInvokerCommand { WorkingDirectory = appDirectory } - .ExecuteWithCapturedOutput(framework, args); + .ExecuteWithCapturedOutput("desktop-and-portable", framework, args); result.Should().HaveStdOutContaining(framework); result.Should().HaveStdOutContaining(args); @@ -163,6 +200,29 @@ namespace Microsoft.DotNet.Tests } } + class GenericCommand : TestCommand + { + private readonly string _commandName; + + public GenericCommand(string commandName) + : base("dotnet") + { + _commandName = commandName; + } + + public override CommandResult Execute(string args = "") + { + args = $"{_commandName} {args}"; + return base.Execute(args); + } + + public override CommandResult ExecuteWithCapturedOutput(string args = "") + { + args = $"{_commandName} {args}"; + return base.ExecuteWithCapturedOutput(args); + } + } + class DependencyContextTestCommand : TestCommand { public DependencyContextTestCommand() @@ -190,15 +250,15 @@ namespace Microsoft.DotNet.Tests { } - public CommandResult Execute(string framework, string additionalArgs) + public CommandResult Execute(string commandName, string framework, string additionalArgs) { - var args = $"dependency-tool-invoker desktop-and-portable --framework {framework} {additionalArgs}"; + var args = $"dependency-tool-invoker {commandName} --framework {framework} {additionalArgs}"; return base.Execute(args); } - public CommandResult ExecuteWithCapturedOutput(string framework, string additionalArgs) + public CommandResult ExecuteWithCapturedOutput(string commandName, string framework, string additionalArgs) { - var args = $"dependency-tool-invoker desktop-and-portable --framework {framework} {additionalArgs}"; + var args = $"dependency-tool-invoker {commandName} --framework {framework} {additionalArgs}"; return base.ExecuteWithCapturedOutput(args); } } diff --git a/test/dotnet.Tests/project.json b/test/dotnet.Tests/project.json index 074d0ca9b..8ef6658c2 100644 --- a/test/dotnet.Tests/project.json +++ b/test/dotnet.Tests/project.json @@ -29,8 +29,10 @@ } }, "content": [ + "../../TestAssets/TestProjects/AppWithDependencyOnToolWithOutputName/**/*", "../../TestAssets/TestProjects/AppWithDirectAndToolDependency/**/*", "../../TestAssets/TestProjects/AppWithDirectDependency/**/*", + "../../TestAssets/TestProjects/AppWithDirectDependencyWithOutputName/**/*", "../../TestAssets/TestProjects/AppWithToolDependency/**/*", "../../TestAssets/TestProjects/DependencyContextFromTool/**/*", "../../TestAssets/DesktopTestProjects/AppWithDirectDependencyDesktopAndPortable/**/*"