Tyrrrz / CliWrap

Library for running command-line processes
MIT License
4.32k stars 264 forks source link

Not getting the proper response from docker command #207

Closed samcov closed 1 year ago

samcov commented 1 year ago

Version

3.6

Details

I'm trying to execute the following docker command, I know the expected output docker exec alantus_ivc-mariadb-1 mysqldump -u root -pMyPwd createdbtest>createdbtestDump.sql

The output should be: "mysqldump: Got error: 1049: "Unknown database 'createdbtest'" when selecting the database"

  1. If I run this on the commandline, I get the proper response.
  2. If I place it in a .bat file, I get the proper response

However, If I run either in CliWrap, it never gets the output and fails. In the catch, it shows

  1. That the command is proper, it looks just like the above commandline
  2. When run as a .bat file, it shows the command, so I put a pause in it and it processes the pause without ever showing the output of the docker command.
var result = await Cli.Wrap("docker")
.WithArguments(new[] { "exec", "alantus_ivc-mariadb-1", "mysqldump", "-u", "root", "-pMyPwd", "createdbtest>createdbtestDump.sql" })
.WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdOutBuffer))
.WithStandardErrorPipe(PipeTarget.ToStringBuilder(stdErrBuffer))
.ExecuteAsync();

Questions:

  1. Does it do this because the docker command returns an error, which in reality I would want to see, and
  2. Is it that for whatever reason, it's not waiting for the docker command to finish before moving on to the next line in the batch file?

Steps to reproduce

Shown above...

Tyrrrz commented 1 year ago

...>createdbtestDump.sql is shell syntax, not a command line argument. You'd have to do Cli.Wrap(...) | PipeTarget.ToFile("createdbtestDump.sql") to achieve equivalent behavior.

Edit: sorry, didn't notice you were running exec, which I assume would probably allocate a shell under the hood.

To answer your questions:

Does it do this because the docker command returns an error, which in reality I would want to see, and

If there's an error (non-zero exit code), you'll get an exception using the code in your sample. If you don't get an exception, the process exited with 0.

Since you're running ExecuteAsync(), there is no stderr in the exception message. You're responsible for handling it yourself. However, you can replace it with ExecuteBufferedAsync() (which sounds like what you really want, based on your sample), and that will add the stderr data in your exception. That should help in debugging.

Is it that for whatever reason, it's not waiting for the docker command to finish before moving on to the next line in the batch file?

Not impossible. You could remove lines and isolate one command in your bat file to test.

samcov commented 1 year ago

You were absolutely correct, it was the ExecuteBufferedAsync() that I needed and I got the expected output.

Then I tried to do it in a real case, and I'm having trouble with the final parameters.

It can't seem to figure out the "createdbtest>createdbtestDump.sql" part. Output is: "Unknown database 'createdbtest > createdbtestdump.sql'" when selecting the database

However, if I just give it the dbname(createdbtest), it does dump it right into the console. Not where I want it, which is in the docker container.

It doesn't like redirecting the output to a file, is there something I'm missing, i.e. how to add the parameters correctly?

samcov commented 1 year ago

Additional note: This is likely where using a batch file works best.

I used a batch file and everything works as it should!

Tyrrrz commented 1 year ago

It can't seem to figure out the "createdbtest>createdbtestDump.sql" part. Output is: "Unknown database 'createdbtest > createdbtestdump.sql'" when selecting the database

Well, it does really seem like whatever docker exec is using doesn't recognize the > operator. Note that > should not be part of the command line passed to the process. It should be parsed by the shell as instructions on how to deal with the output. In CliWrap's case, CliWrap is essentially the shell and the pipes are expressed differently -- i.e., through objects instead of strings.

The correct solution depends on what you're trying to achieve. If you want to pipe the output to a local file, then use PipeTarget.ToFile(...) like I explained in the previous comment (the part that is strikethrough-ed). If you want to pipe the output to a file inside the container, then you should probably do something like dotnet exec /bin/bash -c ... so that the underlying shell (bash in this case) can parse your input and execute it properly.

samcov commented 1 year ago

Exactly, but it works a treat when I use a .bat file, and I'm sure a .sh file on linux.

Thanks a LOT!