diff --git a/src/dotnet/CommandLine/CommandParsingException.cs b/src/dotnet/CommandLine/CommandParsingException.cs index ef8aaf470..606db5564 100644 --- a/src/dotnet/CommandLine/CommandParsingException.cs +++ b/src/dotnet/CommandLine/CommandParsingException.cs @@ -8,18 +8,21 @@ namespace Microsoft.DotNet.Cli.CommandLine { internal class CommandParsingException : Exception { - private bool _isRequireSubCommandMissing; + private readonly bool _isRequireSubCommandMissing; + + public CommandParsingException(string message) : base(message) + { + Data.Add("CLI_User_Displayed_Exception", true); + } public CommandParsingException( CommandLineApplication command, string message, bool isRequireSubCommandMissing = false) - : base(message) + : this(message) { Command = command; _isRequireSubCommandMissing = isRequireSubCommandMissing; - - Data.Add("CLI_User_Displayed_Exception", true); } public CommandLineApplication Command { get; } @@ -29,9 +32,9 @@ namespace Microsoft.DotNet.Cli.CommandLine get { return _isRequireSubCommandMissing - ? CommonLocalizableStrings.RequiredCommandNotPassed - : base.Message; + ? CommonLocalizableStrings.RequiredCommandNotPassed + : base.Message; } } } -} +} \ No newline at end of file diff --git a/src/dotnet/CommonOptions.cs b/src/dotnet/CommonOptions.cs index 67df7f4e8..277e90211 100644 --- a/src/dotnet/CommonOptions.cs +++ b/src/dotnet/CommonOptions.cs @@ -65,6 +65,22 @@ namespace Microsoft.DotNet.Cli public static ArgumentsRule DefaultToCurrentDirectory(this ArgumentsRule rule) => rule.With(defaultValue: () => PathUtility.EnsureTrailingSlash(Directory.GetCurrentDirectory())); + public static ArgumentsRule ExistingFilesOnly( + this ArgumentsRule rule) => + rule.And(new ArgumentsRule(o => + { + foreach (var filePath in o.Arguments) + { + if (!File.Exists(filePath) && + !Directory.Exists(filePath)) + { + return $"File not found: {filePath}"; + } + } + + return null; + })); + public static ArgumentsRule ExistingSlnFileOrDirectoryOnly( this ArgumentsRule rule) => rule diff --git a/src/dotnet/DotNetTopLevelCommandBase.cs b/src/dotnet/DotNetTopLevelCommandBase.cs index f1469da2b..17cdb5e30 100644 --- a/src/dotnet/DotNetTopLevelCommandBase.cs +++ b/src/dotnet/DotNetTopLevelCommandBase.cs @@ -25,7 +25,7 @@ namespace Microsoft.DotNet.Cli var result = parser.ParseFrom($"dotnet {CommandName}", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); var subcommandName = result.Command().Name; diff --git a/src/dotnet/ParseResultExtensions.cs b/src/dotnet/ParseResultExtensions.cs index f19d0cd94..d98991fa4 100644 --- a/src/dotnet/ParseResultExtensions.cs +++ b/src/dotnet/ParseResultExtensions.cs @@ -12,8 +12,15 @@ namespace Microsoft.DotNet.Cli public static void ShowHelp(this ParseResult parseResult) => Console.WriteLine(parseResult.Command().HelpView()); - public static void ShowHelpIfRequested(this ParseResult parseResult) + public static void ShowHelpOrErrorIfAppropriate(this ParseResult parseResult) { + if (parseResult.Errors.Any()) + { + throw new CommandParsingException( + string.Join(Environment.NewLine, + parseResult.Errors.Select(e => e.Message))); + } + if (parseResult.AppliedCommand().HasOption("help")) { // NOTE: this is a temporary stage in refactoring toward the ClicCommandLineParser being used at the CLI entry point. diff --git a/src/dotnet/commands/dotnet-add/AddCommandParser.cs b/src/dotnet/commands/dotnet-add/AddCommandParser.cs index 062a97a11..dcc48737a 100644 --- a/src/dotnet/commands/dotnet-add/AddCommandParser.cs +++ b/src/dotnet/commands/dotnet-add/AddCommandParser.cs @@ -8,6 +8,7 @@ using System.Net.Http; using System.Threading; using Microsoft.DotNet.Cli.CommandLine; using Newtonsoft.Json.Linq; +using LocalizableStrings = Microsoft.DotNet.Tools.Add.PackageReference.LocalizableStrings; namespace Microsoft.DotNet.Cli { @@ -23,7 +24,7 @@ namespace Microsoft.DotNet.Cli Create.Command( "package", ".NET Add Package reference Command", - Accept.ExactlyOneArgument() + Accept.ExactlyOneArgument(errorMessage: o => LocalizableStrings.SpecifyExactlyOnePackageReference) .WithSuggestionsFrom(QueryNuGet), CommonOptions.HelpOption(), Create.Option("-v|--version", diff --git a/src/dotnet/commands/dotnet-build/BuildCommand.cs b/src/dotnet/commands/dotnet-build/BuildCommand.cs index aef57ebb4..691d5ef21 100644 --- a/src/dotnet/commands/dotnet-build/BuildCommand.cs +++ b/src/dotnet/commands/dotnet-build/BuildCommand.cs @@ -25,7 +25,7 @@ namespace Microsoft.DotNet.Tools.Build var result = parser.ParseFrom("dotnet build", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); var appliedBuildOptions = result["dotnet"]["build"]; diff --git a/src/dotnet/commands/dotnet-cache/Program.cs b/src/dotnet/commands/dotnet-cache/Program.cs index 3eb78e3da..64d70a169 100644 --- a/src/dotnet/commands/dotnet-cache/Program.cs +++ b/src/dotnet/commands/dotnet-cache/Program.cs @@ -29,7 +29,7 @@ namespace Microsoft.DotNet.Tools.Cache var result = parser.ParseFrom("dotnet cache", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); var appliedBuildOptions = result["dotnet"]["cache"]; diff --git a/src/dotnet/commands/dotnet-clean/Program.cs b/src/dotnet/commands/dotnet-clean/Program.cs index bcedf9501..e07ec356d 100644 --- a/src/dotnet/commands/dotnet-clean/Program.cs +++ b/src/dotnet/commands/dotnet-clean/Program.cs @@ -25,7 +25,7 @@ namespace Microsoft.DotNet.Tools.Clean var result = parser.ParseFrom("dotnet clean", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); var parsedClean = result["dotnet"]["clean"]; diff --git a/src/dotnet/commands/dotnet-migrate/Program.cs b/src/dotnet/commands/dotnet-migrate/Program.cs index ce406290c..72001edd7 100644 --- a/src/dotnet/commands/dotnet-migrate/Program.cs +++ b/src/dotnet/commands/dotnet-migrate/Program.cs @@ -20,7 +20,7 @@ namespace Microsoft.DotNet.Tools.Migrate var result = parser.ParseFrom("dotnet migrate", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); return result["dotnet"]["migrate"].Value(); } diff --git a/src/dotnet/commands/dotnet-pack/PackCommand.cs b/src/dotnet/commands/dotnet-pack/PackCommand.cs index 37f4dbe61..2821c23d8 100644 --- a/src/dotnet/commands/dotnet-pack/PackCommand.cs +++ b/src/dotnet/commands/dotnet-pack/PackCommand.cs @@ -24,7 +24,7 @@ namespace Microsoft.DotNet.Tools.Pack var result = parser.ParseFrom("dotnet pack", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); var parsedPack = result["dotnet"]["pack"]; diff --git a/src/dotnet/commands/dotnet-publish/Program.cs b/src/dotnet/commands/dotnet-publish/Program.cs index 8a556f5fa..8c8fbc9cf 100644 --- a/src/dotnet/commands/dotnet-publish/Program.cs +++ b/src/dotnet/commands/dotnet-publish/Program.cs @@ -27,7 +27,7 @@ namespace Microsoft.DotNet.Tools.Publish var result = parser.ParseFrom("dotnet publish", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); msbuildArgs.Add("/t:Publish"); diff --git a/src/dotnet/commands/dotnet-restore/Program.cs b/src/dotnet/commands/dotnet-restore/Program.cs index 01b456109..1e1ff728d 100644 --- a/src/dotnet/commands/dotnet-restore/Program.cs +++ b/src/dotnet/commands/dotnet-restore/Program.cs @@ -29,7 +29,7 @@ namespace Microsoft.DotNet.Tools.Restore var result = parser.ParseFrom("dotnet restore", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); var parsedRestore = result["dotnet"]["restore"]; diff --git a/src/dotnet/commands/dotnet-run/Program.cs b/src/dotnet/commands/dotnet-run/Program.cs index 016aa5422..6bfaffefa 100644 --- a/src/dotnet/commands/dotnet-run/Program.cs +++ b/src/dotnet/commands/dotnet-run/Program.cs @@ -17,7 +17,7 @@ namespace Microsoft.DotNet.Tools.Run var result = parser.ParseFrom("dotnet run", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); return result["dotnet"]["run"].Value(); } diff --git a/src/dotnet/commands/dotnet-sln/SlnCommandParser.cs b/src/dotnet/commands/dotnet-sln/SlnCommandParser.cs index 684809e3e..d20cef621 100644 --- a/src/dotnet/commands/dotnet-sln/SlnCommandParser.cs +++ b/src/dotnet/commands/dotnet-sln/SlnCommandParser.cs @@ -13,7 +13,8 @@ namespace Microsoft.DotNet.Cli ".NET modify solution file command", Accept.ExactlyOneArgument() .ExistingSlnFileOrDirectoryOnly() - .DefaultToCurrentDirectory(), + .DefaultToCurrentDirectory() + .With(name: "SLN_FILE" ), CommonOptions.HelpOption(), Create.Command("add", ".NET Add project(s) to a solution file Command", @@ -21,7 +22,6 @@ namespace Microsoft.DotNet.Cli CommonOptions.HelpOption()), Create.Command("list", "List all projects in the solution.", - Accept.OneOrMoreArguments(), CommonOptions.HelpOption()), Create.Command("remove", "Remove the specified project(s) from the solution. The project is not impacted.", diff --git a/src/dotnet/commands/dotnet-test/Program.cs b/src/dotnet/commands/dotnet-test/Program.cs index 563b86be3..913181a20 100644 --- a/src/dotnet/commands/dotnet-test/Program.cs +++ b/src/dotnet/commands/dotnet-test/Program.cs @@ -34,7 +34,7 @@ namespace Microsoft.DotNet.Tools.Test var result = parser.ParseFrom("dotnet test", args); - result.ShowHelpIfRequested(); + result.ShowHelpOrErrorIfAppropriate(); var parsedTest = result["dotnet"]["test"];