| File: Invocation\InvocationPipeline.cs | Web Access |
| Project: src\command-line-api\src\System.CommandLine\System.CommandLine.csproj (System.CommandLine) |
// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Threading; using System.Threading.Tasks; namespace System.CommandLine.Invocation { internal static class InvocationPipeline { internal static async Task<int> InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken) { ProcessTerminationHandler? terminationHandler = null; using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); try { int actionResult = 0; int preActionResult = 0; if (parseResult.PreActions is not null) { for (int i = 0; i < parseResult.PreActions.Count; i++) { var action = parseResult.PreActions[i]; var result = 0; switch (action) { case SynchronousCommandLineAction syncAction: result = syncAction.Invoke(parseResult); break; case AsynchronousCommandLineAction asyncAction: result = await asyncAction.InvokeAsync(parseResult, cts.Token); break; } if (result != 0) { preActionResult = result; } } } if (parseResult.Action is null) { return preActionResult != 0 ? preActionResult : ReturnCodeForMissingAction(parseResult); } switch (parseResult.Action) { case SynchronousCommandLineAction syncAction: actionResult = syncAction.Invoke(parseResult); break; case AsynchronousCommandLineAction asyncAction: var timeout = parseResult.InvocationConfiguration.ProcessTerminationTimeout; if (timeout.HasValue) { terminationHandler = new(cts, timeout.Value); } var startedInvocation = asyncAction.InvokeAsync(parseResult, cts.Token); if (terminationHandler is null) { actionResult = await startedInvocation; } else { terminationHandler.StartedHandler = startedInvocation; // Handlers may not implement cancellation. // In such cases, when CancelOnProcessTermination is configured and user presses Ctrl+C, // ProcessTerminationCompletionSource completes first, with the result equal to native exit code for given signal. Task<int> firstCompletedTask = await Task.WhenAny(startedInvocation, terminationHandler.ProcessTerminationCompletionSource.Task); actionResult = await firstCompletedTask; // return the result or propagate the exception } break; default: throw new ArgumentOutOfRangeException(nameof(parseResult.Action)); } return preActionResult != 0 ? preActionResult : actionResult; } catch (Exception ex) when (parseResult.InvocationConfiguration.EnableDefaultExceptionHandler) { return DefaultExceptionHandler(ex, parseResult); } finally { terminationHandler?.Dispose(); } } internal static int Invoke(ParseResult parseResult) { try { int preActionResult = 0; if (parseResult.PreActions is not null) { for (var i = 0; i < parseResult.PreActions.Count; i++) { if (parseResult.PreActions[i] is SynchronousCommandLineAction syncPreAction) { int result = syncPreAction.Invoke(parseResult); if (result != 0) { preActionResult = result; } } } } switch (parseResult.Action) { case null: return preActionResult != 0 ? preActionResult : ReturnCodeForMissingAction(parseResult); case SynchronousCommandLineAction syncAction: int actionResult = syncAction.Invoke(parseResult); return preActionResult != 0 ? preActionResult : actionResult; default: throw new InvalidOperationException($"{nameof(AsynchronousCommandLineAction)} called within non-async invocation."); } } catch (Exception ex) when (parseResult.InvocationConfiguration.EnableDefaultExceptionHandler) { return DefaultExceptionHandler(ex, parseResult); } } private static int DefaultExceptionHandler(Exception exception, ParseResult parseResult) { if (exception is not OperationCanceledException) { ConsoleHelpers.ResetTerminalForegroundColor(); ConsoleHelpers.SetTerminalForegroundRed(); var error = parseResult.InvocationConfiguration.Error; error.Write(LocalizationResources.ExceptionHandlerHeader()); error.WriteLine(exception.ToString()); ConsoleHelpers.ResetTerminalForegroundColor(); } return 1; } private static int ReturnCodeForMissingAction(ParseResult parseResult) { if (parseResult.Errors.Count > 0) { return 1; } else { return 0; } } } }