mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Fix exit code overflow for unhandled exceptions on Unix systems (#62)
This commit is contained in:
@@ -20,7 +20,7 @@ namespace CliFx.Tests
|
||||
private class CommandExceptionCommand : ICommand
|
||||
{
|
||||
[CommandOption("code", 'c')]
|
||||
public int ExitCode { get; set; } = 1337;
|
||||
public int ExitCode { get; set; } = 133;
|
||||
|
||||
[CommandOption("msg", 'm')]
|
||||
public string? Message { get; set; }
|
||||
|
||||
@@ -263,7 +263,7 @@ namespace CliFx
|
||||
public static int FromException(Exception ex) =>
|
||||
ex is CommandException cmdEx
|
||||
? cmdEx.ExitCode
|
||||
: ex.HResult;
|
||||
: 1;
|
||||
}
|
||||
|
||||
[Command]
|
||||
|
||||
@@ -9,12 +9,14 @@ namespace CliFx.Exceptions
|
||||
/// </summary>
|
||||
public class CommandException : Exception
|
||||
{
|
||||
private const int DefaultExitCode = -1;
|
||||
private const int DefaultExitCode = 1;
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
public int ExitCode { get; }
|
||||
|
||||
@@ -26,6 +28,14 @@ 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>
|
||||
public CommandException(string? message, Exception? innerException, int exitCode = DefaultExitCode, bool showHelp = false)
|
||||
: base(message, innerException)
|
||||
{
|
||||
@@ -39,6 +49,13 @@ 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>
|
||||
public CommandException(string? message, int exitCode = DefaultExitCode, bool showHelp = false)
|
||||
: this(message, null, exitCode, showHelp)
|
||||
{
|
||||
@@ -47,6 +64,12 @@ 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>
|
||||
public CommandException(int exitCode = DefaultExitCode, bool showHelp = false)
|
||||
: this(null, exitCode, showHelp)
|
||||
{
|
||||
|
||||
10
Readme.md
10
Readme.md
@@ -396,10 +396,12 @@ 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 appropriate exit code 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 an exit code `1` 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.
|
||||
|
||||
```c#
|
||||
[Command]
|
||||
public class DivideCommand : ICommand
|
||||
@@ -414,8 +416,8 @@ public class DivideCommand : ICommand
|
||||
{
|
||||
if (Math.Abs(Divisor) < double.Epsilon)
|
||||
{
|
||||
// This will print the error and set exit code to 1337
|
||||
throw new CommandException("Division by zero is not supported.", 1337);
|
||||
// This will print the error and set exit code to 133
|
||||
throw new CommandException("Division by zero is not supported.", 133);
|
||||
}
|
||||
|
||||
var result = Dividend / Divisor;
|
||||
@@ -434,7 +436,7 @@ Division by zero is not supported.
|
||||
|
||||
> $LastExitCode
|
||||
|
||||
1337
|
||||
133
|
||||
```
|
||||
|
||||
You can also specify the `showHelp` parameter to instruct whether to show the help text for the current command after printing the error:
|
||||
|
||||
Reference in New Issue
Block a user