Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WithExitCondition feature #242

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions CliWrap/Command.Execution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,17 @@ private async Task<CommandResult> ExecuteAsync(
.Register(process.Interrupt)
.ToAsyncDisposable();

// Create token to cancel piping when process is finished and we don't need to finish piping
using var outputProcessingCts = new CancellationTokenSource();
using var pipeStdOutErrCts = CancellationTokenSource.CreateLinkedTokenSource(
forcefulCancellationToken,
outputProcessingCts.Token
);
// Start piping streams in the background
var pipingTask = Task.WhenAll(
PipeStandardInputAsync(process, stdInCts.Token),
PipeStandardOutputAsync(process, forcefulCancellationToken),
PipeStandardErrorAsync(process, forcefulCancellationToken)
PipeStandardOutputAsync(process, pipeStdOutErrCts.Token),
PipeStandardErrorAsync(process, pipeStdOutErrCts.Token)
);

try
Expand All @@ -239,8 +245,21 @@ private async Task<CommandResult> ExecuteAsync(
// If the pipe is still trying to transfer data, this will cause it to abort.
await stdInCts.CancelAsync();

// Wait until piping is done and propagate exceptions
await pipingTask.ConfigureAwait(false);
if (WaitForOutputProcessing)
{
// Wait until piping is done and propagate exceptions
await pipingTask.ConfigureAwait(false);
}
else
{
try
{
// Cancel piping if we don't need to wait for it
await outputProcessingCts.CancelAsync();
await pipingTask.ConfigureAwait(false);
}
catch (OperationCanceledException) { }
}
}
// Swallow exceptions caused by internal and user-provided cancellations,
// because we have a separate mechanism for handling them below.
Expand Down
54 changes: 43 additions & 11 deletions CliWrap/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public partial class Command(
CommandResultValidation validation,
PipeSource standardInputPipe,
PipeTarget standardOutputPipe,
PipeTarget standardErrorPipe
PipeTarget standardErrorPipe,
bool waitForOutputProcessing
dmilosz marked this conversation as resolved.
Show resolved Hide resolved
) : ICommandConfiguration
{
/// <summary>
Expand All @@ -35,7 +36,8 @@ public Command(string targetFilePath)
CommandResultValidation.ZeroExitCode,
PipeSource.Null,
PipeTarget.Null,
PipeTarget.Null
PipeTarget.Null,
true
) { }

/// <inheritdoc />
Expand All @@ -50,6 +52,9 @@ public Command(string targetFilePath)
/// <inheritdoc />
public Credentials Credentials { get; } = credentials;

/// <inheritdoc />
public bool WaitForOutputProcessing { get; } = waitForOutputProcessing;

/// <inheritdoc />
public IReadOnlyDictionary<string, string?> EnvironmentVariables { get; } =
environmentVariables;
Expand Down Expand Up @@ -80,7 +85,8 @@ public Command WithTargetFile(string targetFilePath) =>
Validation,
StandardInputPipe,
StandardOutputPipe,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
Expand All @@ -101,7 +107,8 @@ public Command WithArguments(string arguments) =>
Validation,
StandardInputPipe,
StandardOutputPipe,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
Expand Down Expand Up @@ -147,7 +154,8 @@ public Command WithWorkingDirectory(string workingDirPath) =>
Validation,
StandardInputPipe,
StandardOutputPipe,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
Expand All @@ -164,7 +172,8 @@ public Command WithCredentials(Credentials credentials) =>
Validation,
StandardInputPipe,
StandardOutputPipe,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
Expand Down Expand Up @@ -196,7 +205,8 @@ public Command WithEnvironmentVariables(
Validation,
StandardInputPipe,
StandardOutputPipe,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
Expand Down Expand Up @@ -226,7 +236,26 @@ public Command WithValidation(CommandResultValidation validation) =>
validation,
StandardInputPipe,
StandardOutputPipe,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
/// Creates a copy of this command, setting the waiting for output processing flag to the specified value.
/// </summary>
[Pure]
public Command WithWaitingForOutputProcessing(bool waitForOutputProcessing = true) =>
new(
TargetFilePath,
Arguments,
WorkingDirPath,
Credentials,
EnvironmentVariables,
Validation,
StandardInputPipe,
StandardOutputPipe,
StandardErrorPipe,
waitForOutputProcessing
);

/// <summary>
Expand All @@ -243,7 +272,8 @@ public Command WithStandardInputPipe(PipeSource source) =>
Validation,
source,
StandardOutputPipe,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
Expand All @@ -260,7 +290,8 @@ public Command WithStandardOutputPipe(PipeTarget target) =>
Validation,
StandardInputPipe,
target,
StandardErrorPipe
StandardErrorPipe,
WaitForOutputProcessing
);

/// <summary>
Expand All @@ -277,7 +308,8 @@ public Command WithStandardErrorPipe(PipeTarget target) =>
Validation,
StandardInputPipe,
StandardOutputPipe,
target
target,
WaitForOutputProcessing
);

/// <inheritdoc />
Expand Down