Closed YouKnowThem closed 1 year ago
Hey there.
In general, responding to prompts is done by piping standard input data, as that's where the underlying console application reads the input from (usually separated by new lines).
If you know all the prompts and the respective inputs ahead of time, you can just pre-compute the corresponding stdin string and pipe it to the command.
If you need to react to prompts dynamically, the best solution is to create your own PipeSource
and use a synchronization primitive to write data. Something like this:
using var semaphore = new SemaphoreSlim(0, 1);
var buffer = new StringBuilder();
var stdin = PipeSource.Create(async (destination, cancellationToken) =>
{
while (!cancellationToken.IsCancellationRequested)
{
await semaphore.WaitAsync(cancellationToken);
var data = Encoding.UTF8.GetBytes(buffer.ToString());
await destination.WriteAsync(data, 0, data.Length, cancellationToken);
}
});
var cmd = stdin | Cli.Wrap("my cmd");
await foreach (var cmdEvent in cmd.ListenAsync())
{
if (cmdEvent is StandardOutputEvent stdOutEvent)
{
// Detect if it's a prompt
if (stdOutEvent.Text.Contains("Prompt"))
{
// Write the response
buffer.Clear();
buffer.AppendLine("Hello world");
semaphore.Release();
}
}
}
Thanks for the clarification. It's just that the await ListenAsync does not return on this JLinkSTM32.exe's output. I don't know why it doesn't. If it did, your example code would do exactly what I need.
What do you mean by "does not return"?
The await ListenAsync
waits indefinetly. Although when opening the CLI software JLinkSTM32.exe manually shows an immediate output with a promt waiting for user input.
That particular output is not fetched by await ListenAsync
. My C# software waits for the JLinkSTM32 output forever. Although I expect it to be already there.
I don't know what JLinkSTM32
does, but it might be because it detects that the standard input is already redirected at the start and switches to some alternative execution mode.
I did not think about such behavior. Also did not know such a thing would exist. But thinking about it feels like it makes sense. I have tried piping an input in. In this case I do not get any output also the CLI does seem to never exit. A screenshot from task manager. I guess this is the JLinkSTM32.exe's fault?
It's weird that it would never exit. In the worst case, you can probably fool it by wrapping cmd
and using it to launch JLinkSTM32
. Most likely it will behave the same as if it were launched from a terminal.
Good idea. I tried that.
var jLinkSTM32 = await (
"JLinkSTM32.exe\r\n" |
Cli.Wrap("cmd")
.WithWorkingDirectory(@"C:\Program Files\SEGGER\JLink")
.WithStandardOutputPipe(PipeTarget.ToDelegate(line => Console.WriteLine(line)))
.WithStandardErrorPipe(PipeTarget.ToDelegate(line => Console.WriteLine(line)))
)
.ExecuteBufferedAsync();
But without success. CMD did actually output its contents. JLinkSTM32 kept quiet again. So all I saw was this:
I've been having a similar problem and, adding to the discussion, I would like to suggest this feature:
In the same way that the TargetPipe has a ToDelegate(Action<string> delegate)
, it could be useful to have a FromDelegate(Func<string> delegate)
in the PipeSource
@vpenades it's a good idea but not super straightforward. Please make a new issue for it because this one is old.
Version
3.6.0
Details
I have an external CLI software, that ouputs information and prompts the user for imput. I wanted to automate this and using the CliWrap in C# to wait for the prompts and then dynamically output the right user inputs (so a script is not intended). The output of the CLI contains information used to decide on what to feed the CLI prompt.
Steps to reproduce
I know that
.ExecuteBufferedAsync()
is not what I need. It is just to reproduce the issue.