From 55c00a7e45e6bbeceb48f345e5cc2e4b3f55de2f Mon Sep 17 00:00:00 2001 From: Livar Cunha Date: Thu, 25 Aug 2016 16:01:32 -0700 Subject: [PATCH] Adding a resolution chain to the command resolution chain that works based on a directory, more specifically, the publish directory. --- src/Microsoft.DotNet.Cli.Utils/Command.cs | 10 +- .../CommandResolverArguments.cs | 8 +- .../DefaultCommandResolverPolicy.cs | 19 +++- .../IPackagedCommandSpecFactory.cs | 5 - .../IPublishedPathCommandSpecFactory.cs | 17 ++++ .../OutputPathCommandResolver.cs | 4 +- .../PublishPathCommandSpecFactory.cs | 96 +++++++++++++++++++ .../PublishedPathCommandResolver.cs | 73 ++++++++++++++ .../CommandResolver.cs | 6 +- .../PublishedPathCommandFactory.cs | 29 ++++++ src/dotnet-test-console/AssemblyTestRunner.cs | 8 +- .../GivenThatWeWantToRunTestsInTheConsole.cs | 6 +- test/dotnet-test.Tests/project.json | 3 + 13 files changed, 256 insertions(+), 28 deletions(-) create mode 100644 src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPublishedPathCommandSpecFactory.cs create mode 100644 src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishPathCommandSpecFactory.cs create mode 100644 src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishedPathCommandResolver.cs create mode 100644 src/Microsoft.DotNet.Cli.Utils/PublishedPathCommandFactory.cs diff --git a/src/Microsoft.DotNet.Cli.Utils/Command.cs b/src/Microsoft.DotNet.Cli.Utils/Command.cs index 631c508db..083bd5139 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Command.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Command.cs @@ -56,22 +56,20 @@ namespace Microsoft.DotNet.Cli.Utils /// array will be present in the corresponding argument array /// in the command's process. /// - /// - /// - /// - /// public static Command Create( string commandName, IEnumerable args, NuGetFramework framework = null, string configuration = Constants.DefaultConfiguration, - string outputPath = null) + string outputPath = null, + string applicationName = null) { var commandSpec = CommandResolver.TryResolveCommandSpec(commandName, args, framework, configuration: configuration, - outputPath: outputPath); + outputPath: outputPath, + applicationName: applicationName); if (commandSpec == null) { diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs index e43b377b5..dca62db0a 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.DotNet.ProjectModel; -using Microsoft.DotNet.ProjectModel.Graph; +using System.Collections.Generic; using NuGet.Frameworks; namespace Microsoft.DotNet.Cli.Utils @@ -26,5 +22,7 @@ namespace Microsoft.DotNet.Cli.Utils public string BuildBasePath { get; set; } public string DepsJsonFile { get; set; } + + public string ApplicationName { get; set; } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs index fbd093e6a..2eed9b0f6 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs @@ -1,3 +1,4 @@ +using Microsoft.DotNet.Cli.Utils.CommandResolution; using Microsoft.DotNet.PlatformAbstractions; namespace Microsoft.DotNet.Cli.Utils @@ -8,6 +9,7 @@ namespace Microsoft.DotNet.Cli.Utils { var environment = new EnvironmentProvider(); var packagedCommandSpecFactory = new PackagedCommandSpecFactory(); + var publishedPathCommandSpecFactory = new PublishPathCommandSpecFactory(); var platformCommandSpecFactory = default(IPlatformCommandSpecFactory); if (RuntimeEnvironment.OperatingSystemPlatform == Platform.Windows) @@ -19,13 +21,18 @@ namespace Microsoft.DotNet.Cli.Utils platformCommandSpecFactory = new GenericPlatformCommandSpecFactory(); } - return CreateDefaultCommandResolver(environment, packagedCommandSpecFactory, platformCommandSpecFactory); + return CreateDefaultCommandResolver( + environment, + packagedCommandSpecFactory, + platformCommandSpecFactory, + publishedPathCommandSpecFactory); } public static CompositeCommandResolver CreateDefaultCommandResolver( IEnvironmentProvider environment, IPackagedCommandSpecFactory packagedCommandSpecFactory, - IPlatformCommandSpecFactory platformCommandSpecFactory) + IPlatformCommandSpecFactory platformCommandSpecFactory, + IPublishedPathCommandSpecFactory publishedPathCommandSpecFactory) { var compositeCommandResolver = new CompositeCommandResolver(); @@ -33,8 +40,12 @@ namespace Microsoft.DotNet.Cli.Utils compositeCommandResolver.AddCommandResolver(new RootedCommandResolver()); compositeCommandResolver.AddCommandResolver(new ProjectToolsCommandResolver(packagedCommandSpecFactory)); compositeCommandResolver.AddCommandResolver(new AppBaseDllCommandResolver()); - compositeCommandResolver.AddCommandResolver(new AppBaseCommandResolver(environment, platformCommandSpecFactory)); - compositeCommandResolver.AddCommandResolver(new PathCommandResolver(environment, platformCommandSpecFactory)); + compositeCommandResolver.AddCommandResolver( + new AppBaseCommandResolver(environment, platformCommandSpecFactory)); + compositeCommandResolver.AddCommandResolver( + new PathCommandResolver(environment, platformCommandSpecFactory)); + compositeCommandResolver.AddCommandResolver( + new PublishedPathCommandResolver(environment, publishedPathCommandSpecFactory)); return compositeCommandResolver; } diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs index 3c5316456..24e82fa6c 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs @@ -1,10 +1,5 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Graph; -using Microsoft.DotNet.ProjectModel.Compilation; namespace Microsoft.DotNet.Cli.Utils { diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPublishedPathCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPublishedPathCommandSpecFactory.cs new file mode 100644 index 000000000..f42cee7de --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPublishedPathCommandSpecFactory.cs @@ -0,0 +1,17 @@ +// 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 System.Collections.Generic; + +namespace Microsoft.DotNet.Cli.Utils.CommandResolution +{ + public interface IPublishedPathCommandSpecFactory + { + CommandSpec CreateCommandSpecFromPublishFolder( + string commandPath, + IEnumerable commandArguments, + CommandResolutionStrategy commandResolutionStrategy, + string depsFilePath, + string runtimeConfigPath); + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs index 231de29c2..036cbada8 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs @@ -51,7 +51,9 @@ namespace Microsoft.DotNet.Cli.Utils return null; } - var buildOutputPath = projectContext.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeFiles.BasePath; + var buildOutputPath = + projectContext.GetOutputPaths(configuration, buildBasePath, outputPath).CompilationOutputPath + + "publish"; if (! Directory.Exists(buildOutputPath)) { diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishPathCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishPathCommandSpecFactory.cs new file mode 100644 index 000000000..2008404cf --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishPathCommandSpecFactory.cs @@ -0,0 +1,96 @@ +// 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 System; +using System.Collections.Generic; +using System.IO; +using Microsoft.DotNet.ProjectModel; + +namespace Microsoft.DotNet.Cli.Utils.CommandResolution +{ + public class PublishPathCommandSpecFactory : IPublishedPathCommandSpecFactory + { + public CommandSpec CreateCommandSpecFromPublishFolder( + string commandPath, + IEnumerable commandArguments, + CommandResolutionStrategy commandResolutionStrategy, + string depsFilePath, + string runtimeConfigPath) + { + return CreateCommandSpecWrappingWithMuxerIfDll( + commandPath, + commandArguments, + depsFilePath, + commandResolutionStrategy, + runtimeConfigPath); + } + + private CommandSpec CreateCommandSpecWrappingWithMuxerIfDll( + string commandPath, + IEnumerable commandArguments, + string depsFilePath, + CommandResolutionStrategy commandResolutionStrategy, + string runtimeConfigPath) + { + var commandExtension = Path.GetExtension(commandPath); + + if (commandExtension == FileNameSuffixes.DotNet.DynamicLib) + { + return CreatePackageCommandSpecUsingMuxer( + commandPath, + commandArguments, + depsFilePath, + commandResolutionStrategy, + runtimeConfigPath); + } + + return CreateCommandSpec(commandPath, commandArguments, commandResolutionStrategy); + } + private CommandSpec CreatePackageCommandSpecUsingMuxer( + string commandPath, + IEnumerable commandArguments, + string depsFilePath, + CommandResolutionStrategy commandResolutionStrategy, + string runtimeConfigPath) + { + var arguments = new List(); + + var muxer = new Muxer(); + + var host = muxer.MuxerPath; + if (host == null) + { + throw new Exception("Unable to locate dotnet multiplexer"); + } + + arguments.Add("exec"); + + if (runtimeConfigPath != null) + { + arguments.Add("--runtimeconfig"); + arguments.Add(runtimeConfigPath); + } + + if (depsFilePath != null) + { + arguments.Add("--depsfile"); + arguments.Add(depsFilePath); + } + + arguments.Add(commandPath); + arguments.AddRange(commandArguments); + + return CreateCommandSpec(host, arguments, commandResolutionStrategy); + } + + private CommandSpec CreateCommandSpec( + string commandPath, + IEnumerable commandArguments, + CommandResolutionStrategy commandResolutionStrategy) + { + var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(commandArguments); + + return new CommandSpec(commandPath, escapedArgs, commandResolutionStrategy); + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishedPathCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishedPathCommandResolver.cs new file mode 100644 index 000000000..f9763ba9e --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishedPathCommandResolver.cs @@ -0,0 +1,73 @@ +// 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 System.IO; +using Microsoft.DotNet.Cli.Utils.CommandResolution; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class PublishedPathCommandResolver : ICommandResolver + { + private readonly IEnvironmentProvider _environment; + private readonly IPublishedPathCommandSpecFactory _commandSpecFactory; + + public PublishedPathCommandResolver( + IEnvironmentProvider environment, + IPublishedPathCommandSpecFactory commandSpecFactory) + { + _environment = environment; + _commandSpecFactory = commandSpecFactory; + } + + public CommandSpec Resolve(CommandResolverArguments commandResolverArguments) + { + var publishDirectory = commandResolverArguments.OutputPath; + var commandName = commandResolverArguments.CommandName; + var applicationName = commandResolverArguments.ApplicationName; + + if (publishDirectory == null || commandName == null || applicationName == null) + { + return null; + } + + var commandPath = ResolveCommandPath(publishDirectory, commandName); + + if (commandPath == null) + { + return null; + } + + var depsFilePath = Path.Combine(publishDirectory, $"{applicationName}.deps.json"); + if (!File.Exists(depsFilePath)) + { + Reporter.Verbose.WriteLine($"PublishedPathCommandResolver: {depsFilePath} does not exist"); + return null; + } + + var runtimeConfigPath = Path.Combine(publishDirectory, $"{applicationName}.runtimeconfig.json"); + if (!File.Exists(runtimeConfigPath)) + { + Reporter.Verbose.WriteLine($"projectdependenciescommandresolver: {runtimeConfigPath} does not exist"); + return null; + } + + return _commandSpecFactory.CreateCommandSpecFromPublishFolder( + commandPath, + commandResolverArguments.CommandArguments.OrEmptyIfNull(), + CommandResolutionStrategy.OutputPath, + depsFilePath, + runtimeConfigPath); + } + + private string ResolveCommandPath(string publishDirectory, string commandName) + { + if (!Directory.Exists(publishDirectory)) + { + Reporter.Verbose.WriteLine($"publishedpathresolver: {publishDirectory} does not exist"); + return null; + } + + return _environment.GetCommandPathFromRootPath(publishDirectory, commandName, ".dll"); + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs index 35f2f3cd5..d929c8cad 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs @@ -12,7 +12,8 @@ namespace Microsoft.DotNet.Cli.Utils IEnumerable args, NuGetFramework framework = null, string configuration = Constants.DefaultConfiguration, - string outputPath = null) + string outputPath = null, + string applicationName = null) { var commandResolverArgs = new CommandResolverArguments { @@ -21,7 +22,8 @@ namespace Microsoft.DotNet.Cli.Utils Framework = framework, ProjectDirectory = Directory.GetCurrentDirectory(), Configuration = configuration, - OutputPath = outputPath + OutputPath = outputPath, + ApplicationName = applicationName }; var defaultCommandResolver = DefaultCommandResolverPolicy.Create(); diff --git a/src/Microsoft.DotNet.Cli.Utils/PublishedPathCommandFactory.cs b/src/Microsoft.DotNet.Cli.Utils/PublishedPathCommandFactory.cs new file mode 100644 index 000000000..24fac7d35 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/PublishedPathCommandFactory.cs @@ -0,0 +1,29 @@ +// 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 System.Collections.Generic; +using NuGet.Frameworks; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class PublishedPathCommandFactory : ICommandFactory + { + private readonly string _publishDirectory; + private readonly string _applicationName; + + public PublishedPathCommandFactory(string publishDirectory, string applicationName) + { + _publishDirectory = publishDirectory; + _applicationName = applicationName; + } + + public ICommand Create( + string commandName, + IEnumerable args, + NuGetFramework framework = null, + string configuration = Constants.DefaultConfiguration) + { + return Command.Create(commandName, args, framework, configuration, _publishDirectory, _applicationName); + } + } +} diff --git a/src/dotnet-test-console/AssemblyTestRunner.cs b/src/dotnet-test-console/AssemblyTestRunner.cs index 62c0fdb57..fb25062b5 100644 --- a/src/dotnet-test-console/AssemblyTestRunner.cs +++ b/src/dotnet-test-console/AssemblyTestRunner.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.IO; using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Tools.Test @@ -17,8 +18,11 @@ namespace Microsoft.DotNet.Tools.Test public int RunTests(DotnetTestParams dotnetTestParams) { - var commandFactory = - new CommandFactory(); + var assembly = new FileInfo(dotnetTestParams.ProjectOrAssemblyPath); + var publishDirectory = assembly.Directory.FullName; + var applicationName = Path.GetFileNameWithoutExtension(dotnetTestParams.ProjectOrAssemblyPath); + + var commandFactory = new PublishedPathCommandFactory(publishDirectory, applicationName); var assemblyUnderTest = dotnetTestParams.ProjectOrAssemblyPath; diff --git a/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs b/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs index fb0f0f3e6..f34a44f6e 100644 --- a/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs +++ b/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs @@ -100,11 +100,11 @@ namespace Microsoft.Dotnet.Tools.Test.Tests [Fact] public void It_runs_tests_for_an_assembly_passed_as_param() { - var buildCommand = new BuildCommand(_projectFilePath); - var result = buildCommand.Execute(); + var publishCommand = new PublishCommand(_projectFilePath); + var result = publishCommand.Execute(); result.Should().Pass(); - var assemblyUnderTestPath = Path.Combine(_defaultOutputPath, buildCommand.GetPortableOutputName()); + var assemblyUnderTestPath = Path.Combine(publishCommand.GetOutputDirectory(true).FullName, publishCommand.GetPortableOutputName()); var testCommand = new DotnetTestCommand(); result = testCommand.Execute($"{assemblyUnderTestPath}"); diff --git a/test/dotnet-test.Tests/project.json b/test/dotnet-test.Tests/project.json index 873f6a070..569e67db7 100644 --- a/test/dotnet-test.Tests/project.json +++ b/test/dotnet-test.Tests/project.json @@ -15,6 +15,9 @@ "Microsoft.DotNet.ProjectModel": { "target": "project" }, + "Microsoft.DotNet.InternalAbstractions": { + "target": "project" + }, "System.Net.NameResolution": "4.0.0", "System.Net.Sockets": "4.1.0", "System.Runtime.Serialization.Primitives": "4.1.1",