113 lines
3.2 KiB
C#
113 lines
3.2 KiB
C#
using System.Runtime.CompilerServices;
|
|
using CliWrap;
|
|
using CliWrap.Buffered;
|
|
using FluentValidation;
|
|
using MfGames.Gallium;
|
|
using MfGames.Nitride.Generators;
|
|
using Serilog;
|
|
|
|
// ReSharper disable ClassNeverInstantiated.Global
|
|
|
|
namespace MfGames.Nitride.Exec;
|
|
|
|
/// <summary>
|
|
/// An operation that wraps around CliWrap to run an executable.
|
|
/// </summary>
|
|
[WithProperties]
|
|
public partial class ExecOperation : AsyncOperationBase
|
|
{
|
|
private readonly ILogger logger;
|
|
|
|
private readonly IValidator<ExecOperation> validator;
|
|
|
|
public ExecOperation(ILogger logger, IValidator<ExecOperation> validator)
|
|
{
|
|
this.logger = logger.ForContext<ExecOperation>();
|
|
this.validator = validator;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the command associated with this operation.
|
|
/// </summary>
|
|
public Func<Command>? CreateCommand { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a callback to process the buffered output.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This is mutually exclusive with OnResult.
|
|
/// </remarks>
|
|
public Func<BufferedCommandResult, IEnumerable<Entity>>? OnBufferedResult { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a callback to process the output.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This is mutually exclusive with OnBufferedResult.
|
|
/// </remarks>
|
|
public Func<CommandResult, IEnumerable<Entity>>? OnResult { get; set; }
|
|
|
|
/// <inheritdoc />
|
|
public override async IAsyncEnumerable<Entity> RunAsync(
|
|
IAsyncEnumerable<Entity> input,
|
|
[EnumeratorCancellation] CancellationToken cancellationToken = default
|
|
)
|
|
{
|
|
// Make sure everything is validated.
|
|
await this.validator.ValidateAndThrowAsync(this, cancellationToken);
|
|
|
|
// Drain the inputs.
|
|
await foreach (Entity item in input.WithCancellation(cancellationToken))
|
|
{
|
|
yield return item;
|
|
}
|
|
|
|
// Create the command from the input, then execute it as a buffered
|
|
// output if we have a buffered result callback, otherwise as a command
|
|
// result.
|
|
Command command = this.CreateCommand!();
|
|
|
|
if (this.OnBufferedResult != null)
|
|
{
|
|
BufferedCommandResult result = await command.ExecuteBufferedAsync(cancellationToken);
|
|
|
|
this.logger.Debug(
|
|
"Execute buffered: {Command} {Arguments} = {ExitCode}",
|
|
command.TargetFilePath,
|
|
command.Arguments,
|
|
result.ExitCode
|
|
);
|
|
|
|
IEnumerable<Entity> list = this.OnBufferedResult(result);
|
|
|
|
foreach (Entity item in list)
|
|
{
|
|
yield return item;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CommandResult result = await command.ExecuteAsync(cancellationToken);
|
|
|
|
this.logger.Debug(
|
|
"Execute non-buffered: {Command} {Arguments} = {ExitCode}",
|
|
command.TargetFilePath,
|
|
command.Arguments,
|
|
result.ExitCode
|
|
);
|
|
|
|
IEnumerable<Entity>? list = this.OnResult?.Invoke(result);
|
|
|
|
if (list == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
foreach (Entity item in list)
|
|
{
|
|
yield return item;
|
|
}
|
|
}
|
|
}
|
|
}
|