/// <summary> /// Control flow begins here. /// </summary> /// <param name="args">Command-line arguments. See <see cref="CommandLineInput.ShowUsage"/> /// for usage.</param>. /// <returns>0 on success, -1 on bad input, 1 on runtime error. See also <see cref="Result"/> /// enum.</returns> public static int Main(string[] args) { var input = new CommandLineInput(args); Feature?feature = input.Parse(); if (feature == null) { return(CommandLineInput.ShowUsage()); } // hijack Console.Out so it writes to a text file RedirectOutput(input.OutputFilename); // load configurable properties from a properties file ConfiguredProperties properties = ConfiguredProperties.Load(input.PropertiesFilename); // map the feature and configurable properties to a Program instance Program p = GetProgramInstance(feature.Value, properties); if (p == null) { return(Result.Invalid); } return(TryToExecute(p, DateTime.Now)); }
/// <summary> /// Runs the application with specified command line arguments and environment variables, and returns the exit code. /// </summary> public async ValueTask <int> RunAsync( IReadOnlyList <string> commandLineArguments, IReadOnlyDictionary <string, string> environmentVariables) { try { var applicationSchema = ApplicationSchema.Resolve(_configuration.CommandTypes); var commandLineInput = CommandLineInput.Parse(commandLineArguments); return (await HandleDebugDirectiveAsync(commandLineInput) ?? HandlePreviewDirective(applicationSchema, commandLineInput) ?? HandleVersionOption(commandLineInput) ?? HandleHelpOption(applicationSchema, commandLineInput) ?? await HandleCommandExecutionAsync(applicationSchema, commandLineInput, environmentVariables)); } catch (Exception ex) { // We want to catch exceptions in order to print errors and return correct exit codes. // Doing this also gets rid of the annoying Windows troubleshooting dialog that shows up on unhandled exceptions. // Prefer showing message without stack trace on exceptions coming from CliFx or on CommandException var errorMessage = !string.IsNullOrWhiteSpace(ex.Message) && (ex is CliFxException || ex is CommandException) ? ex.Message : ex.ToString(); _console.WithForegroundColor(ConsoleColor.Red, () => _console.Error.WriteLine(errorMessage)); return(ex is CommandException commandException ? commandException.ExitCode : ex.HResult); } }
/// <summary> /// Runs the application with specified command line arguments and environment variables, and returns the exit code. /// </summary> public async ValueTask <int> RunAsync( IReadOnlyList <string> commandLineArguments, IReadOnlyDictionary <string, string> environmentVariables) { try { var applicationSchema = ApplicationSchema.Resolve(_configuration.CommandTypes); var commandLineInput = CommandLineInput.Parse(commandLineArguments); return (await HandleDebugDirectiveAsync(commandLineInput) ?? HandlePreviewDirective(applicationSchema, commandLineInput) ?? HandleVersionOption(commandLineInput) ?? HandleHelpOption(applicationSchema, commandLineInput) ?? await HandleCommandExecutionAsync(applicationSchema, commandLineInput, environmentVariables)); } catch (CliFxException cfe) { // We want to catch exceptions in order to print errors and return correct exit codes. // Doing this also gets rid of the annoying Windows troubleshooting dialog that shows up on unhandled exceptions. var exitCode = HandleCliFxException(commandLineArguments, cfe); return(exitCode); } catch (Exception ex) { // For all other errors, we just write the entire thing to stderr. _console.WithForegroundColor(ConsoleColor.Red, () => _console.Error.WriteLine(ex.ToString())); return(ex.HResult); } }
public void Parse_Test(IReadOnlyList <string> commandLineArguments, CommandLineInput expectedResult) { // Act var result = CommandLineInput.Parse(commandLineArguments); // Assert result.Should().BeEquivalentTo(expectedResult); }
internal void Directive_can_be_enabled_by_specifying_its_name_in_square_brackets(string[] arguments, CommandLineInput expectedInput) { // Act var input = CommandLineInput.Parse(arguments); // Assert input.Should().BeEquivalentTo(expectedInput); }
internal void Any_remaining_arguments_are_treated_as_unbound_arguments(string[] arguments, CommandLineInput expectedInput) { // Act var input = CommandLineInput.Parse(arguments); // Assert input.Should().BeEquivalentTo(expectedInput); }
internal void Option_can_be_set_by_specifying_its_short_name_after_a_single_dash(string[] arguments, CommandLineInput expectedInput) { // Act var input = CommandLineInput.Parse(arguments); // Assert input.Should().BeEquivalentTo(expectedInput); }
public void Input_is_empty_if_no_arguments_are_provided() { // Arrange var args = Array.Empty <string>(); // Act var input = CommandLineInput.Parse(args); // Assert input.Should().BeEquivalentTo(CommandLineInput.Empty); }
/// <summary> /// Handle <see cref="CommandException"/>s differently from the rest because we want to /// display it different based on whether we are showing the help text or not. /// </summary> private int HandleCliFxException(IReadOnlyList <string> commandLineArguments, CliFxException cfe) { var showHelp = cfe.ShowHelp; var errorMessage = cfe.HasMessage ? cfe.Message : cfe.ToString(); _console.WithForegroundColor(ConsoleColor.Red, () => _console.Error.WriteLine(errorMessage)); if (showHelp) { var applicationSchema = ApplicationSchema.Resolve(_configuration.CommandTypes); var commandLineInput = CommandLineInput.Parse(commandLineArguments); var commandSchema = applicationSchema.TryFindCommand(commandLineInput) ?? CommandSchema.StubDefaultCommand; _helpTextWriter.Write(applicationSchema, commandSchema); } return(cfe.ExitCode); }