From 69c24c8dfc677a36e7a7a2845ac16ae8fe34eacc Mon Sep 17 00:00:00 2001 From: Alexey Golub Date: Sun, 19 Jul 2020 18:11:54 +0300 Subject: [PATCH] Refactor --- CliFx.Tests/DirectivesSpecs.cs | 32 +---------------- CliFx.Tests/HelpTextSpecs.cs | 4 +-- CliFx/ApplicationConfiguration.cs | 13 ++----- CliFx/CliApplication.cs | 18 +++------- CliFx/CliApplicationBuilder.cs | 8 ++--- CliFx/Domain/CommandArgumentSchema.cs | 2 +- CliFx/Domain/CommandInput.cs | 2 +- CliFx/Domain/CommandOptionInput.cs | 2 +- CliFx/Domain/CommandSchema.cs | 2 +- CliFx/Domain/HelpTextWriter.cs | 2 +- CliFx/Domain/RootSchema.cs | 2 +- CliFx/Exceptions/CliFxException.cs | 2 +- CliFx/Exceptions/CommandException.cs | 34 ++++++------------- .../{ => Extensions}/CollectionExtensions.cs | 2 +- .../{ => Extensions}/StringExtensions.cs | 2 +- .../{ => Extensions}/TypeExtensions.cs | 2 +- .../{ => Extensions}/VersionExtensions.cs | 2 +- Readme.md | 4 +-- 18 files changed, 35 insertions(+), 100 deletions(-) rename CliFx/Internal/{ => Extensions}/CollectionExtensions.cs (88%) rename CliFx/Internal/{ => Extensions}/StringExtensions.cs (96%) rename CliFx/Internal/{ => Extensions}/TypeExtensions.cs (98%) rename CliFx/Internal/{ => Extensions}/VersionExtensions.cs (86%) diff --git a/CliFx.Tests/DirectivesSpecs.cs b/CliFx.Tests/DirectivesSpecs.cs index dda0512..52d0812 100644 --- a/CliFx.Tests/DirectivesSpecs.cs +++ b/CliFx.Tests/DirectivesSpecs.cs @@ -1,12 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Text; -using System.Threading; using System.Threading.Tasks; -using CliFx.Tests.Internal; -using CliWrap; -using CliWrap.Buffered; using FluentAssertions; using Xunit; @@ -14,30 +8,6 @@ namespace CliFx.Tests { public partial class DirectivesSpecs { - [Fact] - public async Task Debug_directive_can_be_specified_to_have_the_application_wait_until_debugger_is_attached() - { - // We can't actually attach a debugger in tests, so instead just cancel execution after some time - - // Arrange - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); - var stdOut = new StringBuilder(); - - var command = Cli.Wrap("dotnet") - .WithArguments(a => a - .Add(Dummy.Program.Location) - .Add("[debug]")) - .WithEnvironmentVariables(e => e - .Set("ENV_TARGET", "Mars")) | stdOut; - - // Act - await command.ExecuteAsync(cts.Token).Task.IgnoreCancellation(); - var stdOutData = stdOut.ToString(); - - // Assert - stdOutData.Should().Contain("Attach debugger to"); - } - [Fact] public async Task Preview_directive_can_be_specified_to_print_provided_arguments_as_they_were_parsed() { diff --git a/CliFx.Tests/HelpTextSpecs.cs b/CliFx.Tests/HelpTextSpecs.cs index e2431b5..de8e06a 100644 --- a/CliFx.Tests/HelpTextSpecs.cs +++ b/CliFx.Tests/HelpTextSpecs.cs @@ -1,6 +1,4 @@ -using System; -using System.Globalization; -using System.IO; +using System.IO; using System.Threading.Tasks; using FluentAssertions; using Xunit; diff --git a/CliFx/ApplicationConfiguration.cs b/CliFx/ApplicationConfiguration.cs index 7a7e7cd..f03de68 100644 --- a/CliFx/ApplicationConfiguration.cs +++ b/CliFx/ApplicationConfiguration.cs @@ -17,30 +17,23 @@ namespace CliFx /// Whether debug mode is allowed in this application. /// public bool IsDebugModeAllowed { get; } - + /// /// Whether preview mode is allowed in this application. /// public bool IsPreviewModeAllowed { get; } - /// - /// Prompt debugger launch when application is in debug mode - /// - public bool PromptDebuggerLaunchInDebugMode { get; } - /// /// Initializes an instance of . /// public ApplicationConfiguration( IReadOnlyList commandTypes, - bool isDebugModeAllowed, - bool isPreviewModeAllowed, - bool promptDebuggerLaunchInDebugMode) + bool isDebugModeAllowed, + bool isPreviewModeAllowed) { CommandTypes = commandTypes; IsDebugModeAllowed = isDebugModeAllowed; IsPreviewModeAllowed = isPreviewModeAllowed; - PromptDebuggerLaunchInDebugMode = promptDebuggerLaunchInDebugMode; } } } \ No newline at end of file diff --git a/CliFx/CliApplication.cs b/CliFx/CliApplication.cs index 1e46cfd..228ab5b 100644 --- a/CliFx/CliApplication.cs +++ b/CliFx/CliApplication.cs @@ -41,13 +41,15 @@ namespace CliFx private void WriteError(string message) => _console.WithForegroundColor(ConsoleColor.Red, () => _console.Error.WriteLine(message)); - private async ValueTask WaitForDebuggerAsync() + private async ValueTask LaunchAndWaitForDebuggerAsync() { var processId = ProcessEx.GetCurrentProcessId(); _console.WithForegroundColor(ConsoleColor.Green, () => _console.Output.WriteLine($"Attach debugger to PID {processId} to continue.")); + Debugger.Launch(); + while (!Debugger.IsAttached) await Task.Delay(100); } @@ -125,19 +127,7 @@ namespace CliFx // Debug mode if (_configuration.IsDebugModeAllowed && input.IsDebugDirectiveSpecified) { - if (_configuration.PromptDebuggerLaunchInDebugMode) - { - // Prompt debugger launcher dialog - if (!Debugger.IsAttached) - { - Debugger.Launch(); - } - } - else - { - // Ensure debugger is attached and continue - await WaitForDebuggerAsync(); - } + await LaunchAndWaitForDebuggerAsync(); } // Preview mode diff --git a/CliFx/CliApplicationBuilder.cs b/CliFx/CliApplicationBuilder.cs index 0405576..d75c135 100644 --- a/CliFx/CliApplicationBuilder.cs +++ b/CliFx/CliApplicationBuilder.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Reflection; using CliFx.Domain; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx { @@ -16,7 +16,6 @@ namespace CliFx private readonly HashSet _commandTypes = new HashSet(); private bool _isDebugModeAllowed = true; - private bool _promptDebuggerLaunch = false; private bool _isPreviewModeAllowed = true; private string? _title; private string? _executableName; @@ -79,10 +78,9 @@ namespace CliFx /// /// Specifies whether debug mode (enabled with [debug] directive) is allowed in the application. /// - public CliApplicationBuilder AllowDebugMode(bool isAllowed = true, bool promptDebuggerLaunch = false) + public CliApplicationBuilder AllowDebugMode(bool isAllowed = true) { _isDebugModeAllowed = isAllowed; - _promptDebuggerLaunch = promptDebuggerLaunch; return this; } @@ -168,7 +166,7 @@ namespace CliFx _typeActivator ??= new DefaultTypeActivator(); var metadata = new ApplicationMetadata(_title, _executableName, _versionText, _description); - var configuration = new ApplicationConfiguration(_commandTypes.ToArray(), _isDebugModeAllowed, _isPreviewModeAllowed, _promptDebuggerLaunch); + var configuration = new ApplicationConfiguration(_commandTypes.ToArray(), _isDebugModeAllowed, _isPreviewModeAllowed); return new CliApplication(metadata, configuration, _console, _typeActivator); } diff --git a/CliFx/Domain/CommandArgumentSchema.cs b/CliFx/Domain/CommandArgumentSchema.cs index 71b4333..59f74b5 100644 --- a/CliFx/Domain/CommandArgumentSchema.cs +++ b/CliFx/Domain/CommandArgumentSchema.cs @@ -4,7 +4,7 @@ using System.Globalization; using System.Linq; using System.Reflection; using CliFx.Exceptions; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx.Domain { diff --git a/CliFx/Domain/CommandInput.cs b/CliFx/Domain/CommandInput.cs index 440e75d..7134814 100644 --- a/CliFx/Domain/CommandInput.cs +++ b/CliFx/Domain/CommandInput.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx.Domain { diff --git a/CliFx/Domain/CommandOptionInput.cs b/CliFx/Domain/CommandOptionInput.cs index 832f564..1706009 100644 --- a/CliFx/Domain/CommandOptionInput.cs +++ b/CliFx/Domain/CommandOptionInput.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx.Domain { diff --git a/CliFx/Domain/CommandSchema.cs b/CliFx/Domain/CommandSchema.cs index d78f282..99df332 100644 --- a/CliFx/Domain/CommandSchema.cs +++ b/CliFx/Domain/CommandSchema.cs @@ -6,7 +6,7 @@ using System.Reflection; using System.Text; using CliFx.Attributes; using CliFx.Exceptions; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx.Domain { diff --git a/CliFx/Domain/HelpTextWriter.cs b/CliFx/Domain/HelpTextWriter.cs index 71b50d4..7724425 100644 --- a/CliFx/Domain/HelpTextWriter.cs +++ b/CliFx/Domain/HelpTextWriter.cs @@ -3,7 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx.Domain { diff --git a/CliFx/Domain/RootSchema.cs b/CliFx/Domain/RootSchema.cs index 75159a1..de4821f 100644 --- a/CliFx/Domain/RootSchema.cs +++ b/CliFx/Domain/RootSchema.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Linq; using CliFx.Exceptions; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx.Domain { diff --git a/CliFx/Exceptions/CliFxException.cs b/CliFx/Exceptions/CliFxException.cs index 6955e36..f02c7f8 100644 --- a/CliFx/Exceptions/CliFxException.cs +++ b/CliFx/Exceptions/CliFxException.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using CliFx.Attributes; using CliFx.Domain; -using CliFx.Internal; +using CliFx.Internal.Extensions; namespace CliFx.Exceptions { diff --git a/CliFx/Exceptions/CommandException.cs b/CliFx/Exceptions/CommandException.cs index a748888..029a3f9 100644 --- a/CliFx/Exceptions/CommandException.cs +++ b/CliFx/Exceptions/CommandException.cs @@ -14,9 +14,7 @@ namespace CliFx.Exceptions private readonly bool _isMessageSet; /// - /// Returns an exit code associated with this exception. - /// On Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use exit codes between 1 and 255 - /// otherwise it may overflow and yield unexpected results. + /// Exit code returned by the application when this exception is handled. /// public int ExitCode { get; } @@ -28,14 +26,9 @@ namespace CliFx.Exceptions /// /// Initializes an instance of . /// - /// The exception message. - /// The inner exception. - /// - /// The exit code associated with this exception. - /// On Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use exit codes between 1 and 255 - /// otherwise it may overflow and yield unexpected results. - /// - /// Whether to show the help text after handling this exception. + /// + /// On Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use values between 1 and 255 to avoid overflow. + /// public CommandException(string? message, Exception? innerException, int exitCode = DefaultExitCode, bool showHelp = false) : base(message, innerException) { @@ -49,13 +42,9 @@ namespace CliFx.Exceptions /// /// Initializes an instance of . /// - /// The exception message. - /// - /// The exit code associated with this exception. - /// On Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use exit codes between 1 and 255 - /// otherwise it may overflow and yield unexpected results. - /// - /// Whether to show the help text after handling this exception. + /// + /// On Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use values between 1 and 255 to avoid overflow. + /// public CommandException(string? message, int exitCode = DefaultExitCode, bool showHelp = false) : this(message, null, exitCode, showHelp) { @@ -64,12 +53,9 @@ namespace CliFx.Exceptions /// /// Initializes an instance of . /// - /// - /// The exit code associated with this exception. - /// On Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use exit codes between 1 and 255 - /// otherwise it may overflow and yield unexpected results. - /// - /// Whether to show the help text after handling this exception. + /// + /// On Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use values between 1 and 255 to avoid overflow. + /// public CommandException(int exitCode = DefaultExitCode, bool showHelp = false) : this(null, exitCode, showHelp) { diff --git a/CliFx/Internal/CollectionExtensions.cs b/CliFx/Internal/Extensions/CollectionExtensions.cs similarity index 88% rename from CliFx/Internal/CollectionExtensions.cs rename to CliFx/Internal/Extensions/CollectionExtensions.cs index 454585e..9ef38fd 100644 --- a/CliFx/Internal/CollectionExtensions.cs +++ b/CliFx/Internal/Extensions/CollectionExtensions.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace CliFx.Internal +namespace CliFx.Internal.Extensions { internal static class CollectionExtensions { diff --git a/CliFx/Internal/StringExtensions.cs b/CliFx/Internal/Extensions/StringExtensions.cs similarity index 96% rename from CliFx/Internal/StringExtensions.cs rename to CliFx/Internal/Extensions/StringExtensions.cs index 6c659c1..fbafbe0 100644 --- a/CliFx/Internal/StringExtensions.cs +++ b/CliFx/Internal/Extensions/StringExtensions.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace CliFx.Internal +namespace CliFx.Internal.Extensions { internal static class StringExtensions { diff --git a/CliFx/Internal/TypeExtensions.cs b/CliFx/Internal/Extensions/TypeExtensions.cs similarity index 98% rename from CliFx/Internal/TypeExtensions.cs rename to CliFx/Internal/Extensions/TypeExtensions.cs index 309d574..6032bc2 100644 --- a/CliFx/Internal/TypeExtensions.cs +++ b/CliFx/Internal/Extensions/TypeExtensions.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -namespace CliFx.Internal +namespace CliFx.Internal.Extensions { internal static class TypeExtensions { diff --git a/CliFx/Internal/VersionExtensions.cs b/CliFx/Internal/Extensions/VersionExtensions.cs similarity index 86% rename from CliFx/Internal/VersionExtensions.cs rename to CliFx/Internal/Extensions/VersionExtensions.cs index 3f7aeca..092bc1c 100644 --- a/CliFx/Internal/VersionExtensions.cs +++ b/CliFx/Internal/Extensions/VersionExtensions.cs @@ -1,6 +1,6 @@ using System; -namespace CliFx.Internal +namespace CliFx.Internal.Extensions { internal static class VersionExtensions { diff --git a/Readme.md b/Readme.md index 0bbeb55..d101dbd 100644 --- a/Readme.md +++ b/Readme.md @@ -396,11 +396,11 @@ You can run `myapp.exe cmd1 [command] --help` to show help on a specific command You may have noticed that commands in CliFx don't return exit codes. This is by design as exit codes are considered a higher-level concern and thus handled by `CliApplication`, not by individual commands. -Commands can report execution failure simply by throwing exceptions just like any other C# code. When an exception is thrown, `CliApplication` will catch it, print the error, and return an exit code `1` to the calling process. +Commands can report execution failure simply by throwing exceptions just like any other C# code. When an exception is thrown, `CliApplication` will catch it, print the error, and return `1` as the exit code to the calling process. If you want to communicate a specific error through exit code, you can instead throw an instance of `CommandException` which takes an exit code as a parameter. When a command throws an exception of type `CommandException`, it is assumed that this was a result of a handled error and, as such, only the exception message will be printed to the error stream. If a command throws an exception of any other type, the full stack trace will be printed as well. -> Please note that on Unix systems an exit code is 8-bit unsigned integer so it's strongly recommended to use exit codes between `1` and `255` otherwise it may overflow and yield unexpected results. +> Note: Unix systems rely on 8-bit unsigned integers for exit codes, so it's strongly recommended to use values between `1` and `255` to avoid potential overflow issues. ```c# [Command]