Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
16 changes: 16 additions & 0 deletions CliWrap.Tests/ExecutionSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,22 @@ public async Task I_can_execute_a_command_with_a_configured_awaiter()
await cmd.ExecuteAsync().ConfigureAwait(false);
}

[Fact(Timeout = 15000)]
public async Task I_can_execute_a_command_with_manually_configured_process_settings()
{
// Arrange
var cmd = Cli.Wrap(Dummy.Program.FilePath).WithValidation(CommandResultValidation.None);

// Act
var result = await cmd.ExecuteAsync(
startInfo => startInfo.Arguments = "exit 13",
process => process.PriorityBoostEnabled = false
);

// Assert
result.ExitCode.Should().Be(13);
}

[Fact(Timeout = 15000)]
public async Task I_can_execute_a_command_and_not_hang_on_large_stdout_and_stderr()
{
Expand Down
32 changes: 28 additions & 4 deletions CliWrap/Command.Execution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -296,17 +296,27 @@ Command execution failed because the underlying process ({process.Name}#{process

/// <summary>
/// Executes the command asynchronously.
/// This overload allows you to directly configure the underlying process, and should
/// only be used in rare cases when you need to break out of the abstraction model
/// provided by CliWrap.
/// This overload comes with no warranty and using it may lead to unexpected behavior.
/// </summary>
/// <remarks>
/// This method can be awaited.
/// </remarks>
// TODO: (breaking change) use optional parameters and remove the other overload
// Added to facilitate running the command without redirecting some/all of the streams
// https://github.com/Tyrrrz/CliWrap/issues/79
public CommandTask<CommandResult> ExecuteAsync(
CancellationToken forcefulCancellationToken,
CancellationToken gracefulCancellationToken
Action<ProcessStartInfo>? configureStartInfo,
Action<Process>? configureProcess = null,
CancellationToken forcefulCancellationToken = default,
CancellationToken gracefulCancellationToken = default
)
{
var process = new ProcessEx(CreateStartInfo());
var startInfo = CreateStartInfo();
configureStartInfo?.Invoke(startInfo);

var process = new ProcessEx(startInfo);

// This method may fail, and we want to propagate the exceptions immediately instead
// of wrapping them in a task, so it needs to be executed in a synchronous context.
Expand Down Expand Up @@ -343,6 +353,8 @@ CancellationToken gracefulCancellationToken
// This exception could indicate that the process has exited before we had a chance to set the policy.
// This is not an exceptional situation, so we don't need to do anything here.
}

configureProcess?.Invoke(p);
});

// Extract the process ID before calling ExecuteAsync(), because the process may
Expand All @@ -355,6 +367,18 @@ CancellationToken gracefulCancellationToken
);
}

/// <summary>
/// Executes the command asynchronously.
/// </summary>
/// <remarks>
/// This method can be awaited.
/// </remarks>
// TODO: (breaking change) use optional parameters and remove the other overload
public CommandTask<CommandResult> ExecuteAsync(
CancellationToken forcefulCancellationToken,
CancellationToken gracefulCancellationToken
) => ExecuteAsync(null, null, forcefulCancellationToken, gracefulCancellationToken);

/// <summary>
/// Executes the command asynchronously.
/// </summary>
Expand Down