diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 3eaadc0d2..c18e98378 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -166,6 +166,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet.Tests", "test\dotnet EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-build.Tests", "test\dotnet-build.Tests\dotnet-build.Tests.csproj", "{BBB5A4C8-CD2D-4A6A-9159-0FEAF84B745E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-help.Tests", "test\dotnet-help.Tests\dotnet-help.Tests.csproj", "{8AA88E83-6A98-4AD6-86EB-2ED4F6EDA17F}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-migrate.Tests", "test\dotnet-migrate.Tests\dotnet-migrate.Tests.csproj", "{726D2CB9-80E5-4496-9C86-910AC452C45E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-msbuild.Tests", "test\dotnet-msbuild.Tests\dotnet-msbuild.Tests.csproj", "{EF745C56-0350-4C42-AA22-86D592E1D8D5}" diff --git a/build/DependencyVersions.props b/build/DependencyVersions.props index b0dddb67f..3e7e45278 100644 --- a/build/DependencyVersions.props +++ b/build/DependencyVersions.props @@ -16,8 +16,8 @@ 1.0.0-beta2-20170410-189 1.0.3 1.0.3 - 0.1.0-alpha-140 - + 0.1.0-alpha-142 + diff --git a/src/dotnet/Parser.cs b/src/dotnet/Parser.cs index acfbfe9c6..5f9ec884d 100644 --- a/src/dotnet/Parser.cs +++ b/src/dotnet/Parser.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Tools.Help; using static System.Environment; using static Microsoft.DotNet.Cli.CommandLine.LocalizableStrings; using LocalizableStrings = Microsoft.DotNet.Tools.Run.LocalizableStrings; @@ -47,6 +48,7 @@ namespace Microsoft.DotNet.Cli ListCommandParser.List(), NuGetCommandParser.NuGet(), StoreCommandParser.Store(), + HelpCommandParser.Help(), Create.Command("msbuild", ""), Create.Command("vstest", ""), CompleteCommandParser.Complete(), diff --git a/src/dotnet/commands/dotnet-help/HelpCommand.cs b/src/dotnet/commands/dotnet-help/HelpCommand.cs index 9bff37221..799ba9314 100644 --- a/src/dotnet/commands/dotnet-help/HelpCommand.cs +++ b/src/dotnet/commands/dotnet-help/HelpCommand.cs @@ -1,68 +1,66 @@ // 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.Diagnostics; -using System.Reflection; +using System.Linq; using System.Runtime.InteropServices; +using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Cli; -using static HelpUsageText; +using Command = Microsoft.DotNet.Cli.CommandLine.Command; +using Parser = Microsoft.DotNet.Cli.Parser; namespace Microsoft.DotNet.Tools.Help { public class HelpCommand { + private readonly AppliedOption _appliedOption; + + public HelpCommand(AppliedOption appliedOption) + { + _appliedOption = appliedOption; + } + public static int Run(string[] args) { - CommandLineApplication app = new CommandLineApplication(throwOnUnexpectedArg: false); - app.Name = "dotnet help"; - app.FullName = LocalizableStrings.AppFullName; - app.Description = LocalizableStrings.AppDescription; + DebugHelper.HandleDebugSwitch(ref args); - CommandArgument commandNameArgument = app.Argument($"<{LocalizableStrings.CommandArgumentName}>", LocalizableStrings.CommandArgumentDescription); + var parser = Parser.Instance; + var result = parser.ParseFrom("dotnet help", args); + var helpAppliedOption = result["dotnet"]["help"]; - app.OnExecute(() => + result.ShowHelpIfRequested(); + + HelpCommand cmd; + try { - BuiltInCommandMetadata builtIn; - if (BuiltInCommandsCatalog.Commands.TryGetValue(commandNameArgument.Value, out builtIn)) - { - var process = ConfigureProcess(builtIn.DocLink); - process.Start(); - process.WaitForExit(); - } - else - { - Reporter.Error.WriteLine(String.Format(LocalizableStrings.CommandDoesNotExist, commandNameArgument.Value)); - Reporter.Output.WriteLine(UsageText); - return 1; - } - return 0; - }); - - if (args.Length == 0) + cmd = new HelpCommand(helpAppliedOption); + } + catch (CommandCreationException e) { - PrintHelp(); - return 0; + return e.ExitCode; + } + + if (helpAppliedOption.Arguments.Any()) + { + return cmd.Execute(); } else { - return app.Execute(args); + PrintHelp(); + return 0; } } public static void PrintHelp() { PrintVersionHeader(); - Reporter.Output.WriteLine(UsageText); + Reporter.Output.WriteLine(HelpUsageText.UsageText); } public static void PrintVersionHeader() { - var versionString = string.IsNullOrEmpty(Product.Version) ? - string.Empty : - $" ({Product.Version})"; + var versionString = string.IsNullOrEmpty(Product.Version) ? string.Empty : $" ({Product.Version})"; Reporter.Output.WriteLine(Product.LongName + versionString); } @@ -93,11 +91,34 @@ namespace Microsoft.DotNet.Tools.Help Arguments = docUrl }; } - + return new Process { StartInfo = psInfo }; } + + public int Execute() + { + if (BuiltInCommandsCatalog.Commands.TryGetValue( + _appliedOption.Arguments.Single(), + out BuiltInCommandMetadata builtIn)) + { + var process = ConfigureProcess(builtIn.DocLink); + process.Start(); + process.WaitForExit(); + return 0; + } + else + { + Reporter.Error.WriteLine( + string.Format( + LocalizableStrings.CommandDoesNotExist, + _appliedOption.Arguments.Single())); + Reporter.Output.WriteLine(HelpUsageText.UsageText); + return 1; + } + } } } + diff --git a/src/dotnet/commands/dotnet-help/HelpCommandParser.cs b/src/dotnet/commands/dotnet-help/HelpCommandParser.cs new file mode 100644 index 000000000..ccab6bd21 --- /dev/null +++ b/src/dotnet/commands/dotnet-help/HelpCommandParser.cs @@ -0,0 +1,21 @@ +using Microsoft.DotNet.Cli; +using Microsoft.DotNet.Cli.CommandLine; + +namespace Microsoft.DotNet.Tools.Help +{ + internal static class HelpCommandParser + { + public static Command Help() + { + return Create.Command( + "help", + LocalizableStrings.AppFullName, + Accept.ZeroOrOneArgument() + .With( + LocalizableStrings.CommandArgumentDescription, + LocalizableStrings.CommandArgumentName), + CommonOptions.HelpOption()); + } + } +} + diff --git a/src/dotnet/commands/dotnet-help/HelpUsageText.cs b/src/dotnet/commands/dotnet-help/HelpUsageText.cs index f1f2f39a5..30605ec11 100644 --- a/src/dotnet/commands/dotnet-help/HelpUsageText.cs +++ b/src/dotnet/commands/dotnet-help/HelpUsageText.cs @@ -3,7 +3,7 @@ using Microsoft.DotNet.Tools.Help; internal static class HelpUsageText { public static readonly string UsageText = - $@"{LocalizableStrings.Usage}: dotnet [host-options] [command] [arguments] [common-options] +$@"{LocalizableStrings.Usage}: dotnet [host-options] [command] [arguments] [common-options] {LocalizableStrings.Arguments}: [command] {LocalizableStrings.CommandDefinition} @@ -13,7 +13,7 @@ internal static class HelpUsageText {LocalizableStrings.CommonOptions}: -v|--verbose {LocalizableStrings.VerboseDefinition} - -h|--help {LocalizableStrings.HelpDefinition} + -h|--help {LocalizableStrings.HelpDefinition} {LocalizableStrings.HostOptions}: -d|--diagnostics {LocalizableStrings.DiagnosticsDefinition} @@ -41,4 +41,5 @@ Project modification commands: nuget {LocalizableStrings.NugetDefinition} msbuild {LocalizableStrings.MsBuildDefinition} vstest {LocalizableStrings.VsTestDefinition}"; -} \ No newline at end of file +} + diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/HelpCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/HelpCommand.cs index ce3948e61..222d92368 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/HelpCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/HelpCommand.cs @@ -9,8 +9,17 @@ namespace Microsoft.DotNet.Tools.Test.Utilities { public override CommandResult Execute(string args = "") { - args = $"help {args}"; - return base.Execute(args); + return base.Execute(AppendHelp(args)); + } + + public override CommandResult ExecuteWithCapturedOutput(string args = "") + { + return base.ExecuteWithCapturedOutput(AppendHelp(args)); + } + + private string AppendHelp(string args) + { + return args = $"help {args}"; } } } diff --git a/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs b/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs index 09cae73ab..dbeb144bb 100644 --- a/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs +++ b/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetCommand.cs @@ -25,7 +25,7 @@ Arguments: Common options: -v|--verbose Enable verbose output - -h|--help Show help + -h|--help Show help Host options (passed before the command): -d|--diagnostics Enable diagnostic output @@ -67,12 +67,21 @@ Advanced Commands: cmd.StdOut.Should().ContainVisuallySameFragment(HelpText); } + [Fact] + public void WhenHelpCommandIsPassedToDotnetItPrintsUsage() + { + var cmd = new HelpCommand() + .ExecuteWithCapturedOutput(); + cmd.Should().Pass(); + cmd.StdOut.Should().ContainVisuallySameFragment(HelpText); + } + [Fact] public void WhenInvalidCommandIsPassedToDotnetHelpItPrintsError() { var cmd = new DotnetCommand() .ExecuteWithCapturedOutput("help invalid"); - + cmd.Should().Fail(); cmd.StdErr.Should().ContainVisuallySameFragment($"Specified command 'invalid' is not a valid CLI command. Please specify a valid CLI commands. For more information, run dotnet help."); cmd.StdOut.Should().ContainVisuallySameFragment(HelpText); @@ -92,7 +101,7 @@ Advanced Commands: var proc = HelpActual.HelpCommand.ConfigureProcess("https://aka.ms/dotnet-build"); Assert.Equal("xdg-open", proc.StartInfo.FileName); Assert.Equal("https://aka.ms/dotnet-build", proc.StartInfo.Arguments); - + } [MacOsOnlyFact] public void WhenRunOnMacOsDotnetHelpCommandShouldContainProperProcessInformation() diff --git a/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetHelpCommand.cs b/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetHelpCommand.cs new file mode 100644 index 000000000..e24d4e56a --- /dev/null +++ b/test/dotnet-help.Tests/GivenThatIWantToShowHelpForDotnetHelpCommand.cs @@ -0,0 +1,37 @@ +// 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 Microsoft.DotNet.Tools.Test.Utilities; +using Xunit; +using FluentAssertions; +using HelpActual = Microsoft.DotNet.Tools.Help; + +namespace Microsoft.DotNet.Help.Tests +{ + public class GivenThatIWantToShowHelpForDotnetHelpCommand : TestBase + { + private const string HelpText = +@".NET CLI help utility + +Usage: dotnet help [options] + +Arguments: + CLI command for which to view more detailed help. + +Options: + -h, --help Show help information"; + + [Theory] + [InlineData("--help")] + [InlineData("-h")] + [InlineData("-?")] + [InlineData("/?")] + public void WhenHelpOptionIsPassedToDotnetHelpCommandItPrintsUsage(string helpArg) + { + var cmd = new HelpCommand() + .ExecuteWithCapturedOutput($"{helpArg}"); + cmd.Should().Pass(); + cmd.StdOut.Should().ContainVisuallySameFragment(HelpText); + } + } +}