This commit is contained in:
Alexey Golub
2020-07-19 18:11:54 +03:00
parent 004f906148
commit 69c24c8dfc
18 changed files with 35 additions and 100 deletions

View File

@@ -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()
{

View File

@@ -1,6 +1,4 @@
using System;
using System.Globalization;
using System.IO;
using System.IO;
using System.Threading.Tasks;
using FluentAssertions;
using Xunit;

View File

@@ -23,24 +23,17 @@ namespace CliFx
/// </summary>
public bool IsPreviewModeAllowed { get; }
/// <summary>
/// Prompt debugger launch when application is in debug mode
/// </summary>
public bool PromptDebuggerLaunchInDebugMode { get; }
/// <summary>
/// Initializes an instance of <see cref="ApplicationConfiguration"/>.
/// </summary>
public ApplicationConfiguration(
IReadOnlyList<Type> commandTypes,
bool isDebugModeAllowed,
bool isPreviewModeAllowed,
bool promptDebuggerLaunchInDebugMode)
bool isPreviewModeAllowed)
{
CommandTypes = commandTypes;
IsDebugModeAllowed = isDebugModeAllowed;
IsPreviewModeAllowed = isPreviewModeAllowed;
PromptDebuggerLaunchInDebugMode = promptDebuggerLaunchInDebugMode;
}
}
}

View File

@@ -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

View File

@@ -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<Type> _commandTypes = new HashSet<Type>();
private bool _isDebugModeAllowed = true;
private bool _promptDebuggerLaunch = false;
private bool _isPreviewModeAllowed = true;
private string? _title;
private string? _executableName;
@@ -79,10 +78,9 @@ namespace CliFx
/// <summary>
/// Specifies whether debug mode (enabled with [debug] directive) is allowed in the application.
/// </summary>
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);
}

View File

@@ -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
{

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CliFx.Internal;
using CliFx.Internal.Extensions;
namespace CliFx.Domain
{

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using CliFx.Internal;
using CliFx.Internal.Extensions;
namespace CliFx.Domain
{

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using CliFx.Exceptions;
using CliFx.Internal;
using CliFx.Internal.Extensions;
namespace CliFx.Domain
{

View File

@@ -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
{

View File

@@ -14,9 +14,7 @@ namespace CliFx.Exceptions
private readonly bool _isMessageSet;
/// <summary>
/// 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.
/// </summary>
public int ExitCode { get; }
@@ -28,14 +26,9 @@ namespace CliFx.Exceptions
/// <summary>
/// Initializes an instance of <see cref="CommandException"/>.
/// </summary>
/// <param name="message">The exception message.</param>
/// <param name="innerException">The inner exception.</param>
/// <param name="exitCode">
/// 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.
/// </param>
/// <param name="showHelp">Whether to show the help text after handling this exception.</param>
/// <remarks>
/// 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.
/// </remarks>
public CommandException(string? message, Exception? innerException, int exitCode = DefaultExitCode, bool showHelp = false)
: base(message, innerException)
{
@@ -49,13 +42,9 @@ namespace CliFx.Exceptions
/// <summary>
/// Initializes an instance of <see cref="CommandException"/>.
/// </summary>
/// <param name="message">The exception message.</param>
/// <param name="exitCode">
/// 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.
/// </param>
/// <param name="showHelp">Whether to show the help text after handling this exception.</param>
/// <remarks>
/// 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.
/// </remarks>
public CommandException(string? message, int exitCode = DefaultExitCode, bool showHelp = false)
: this(message, null, exitCode, showHelp)
{
@@ -64,12 +53,9 @@ namespace CliFx.Exceptions
/// <summary>
/// Initializes an instance of <see cref="CommandException"/>.
/// </summary>
/// <param name="exitCode">
/// 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.
/// </param>
/// <param name="showHelp">Whether to show the help text after handling this exception.</param>
/// <remarks>
/// 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.
/// </remarks>
public CommandException(int exitCode = DefaultExitCode, bool showHelp = false)
: this(null, exitCode, showHelp)
{

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
namespace CliFx.Internal
namespace CliFx.Internal.Extensions
{
internal static class CollectionExtensions
{

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text;
namespace CliFx.Internal
namespace CliFx.Internal.Extensions
{
internal static class StringExtensions
{

View File

@@ -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
{

View File

@@ -1,6 +1,6 @@
using System;
namespace CliFx.Internal
namespace CliFx.Internal.Extensions
{
internal static class VersionExtensions
{

View File

@@ -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]