On Sat, Oct 15, 2016 at 8:12 PM, Stephen R. van den Berg <s...@cuci.nl> wrote:
> Chris Angelico wrote:
>>Two features added to the Process module. Firstly, a simple wrapper
>>Process.check_run that calls Process.run and throws an error if the
>>exit code isn't 0;
>
> This is a bit overkill, I'd say.  It's not generic enough to put in the
> lib.  What if you want to check for a certain range of exitcodes instead?
> If you want this, I'd say you inherit the class and add your own convenience
> functions to it, but at application level.

There's a strong convention that zero == success, nonzero == failure,
so this would apply as-is to a lot of programs. Obviously this
shouldn't be the one and only way to run a subprocess (this is NOT a
proposed change to Process.run, it's a separate function), so if you
want to invoke grep(1) and accept 0 (lines found) and 1 (no lines
found) but not 2 (error), then you'd make an app-specific function;
but 0 vs other is common enough that I think this fits the standard
library.

Example of prior art: Python's subprocess.check_call and check_output
functions raise an exception on non-zero return value:

https://docs.python.org/3/library/subprocess.html#subprocess.CalledProcessError

>> and secondly, a means for Process.run() to leave
>>stderr attached to the console. The intention is for this to be used
>
> That seems useful, so I'd welcome that.
> But then support it for stdout too.
> Then again, maybe this is better off generalised, into requiring/allowing
> you to specify things like:
>
> ({"stdout":Stdio.stdout, "stderr":Stdio.stderr})
>
> instead of the magic "-".
>
> This would support adding different objects too, in order to redirect
> directly into a file or some other pipe.

If you don't want to redirect either, or if you want to redirect them
both to files, use Process.Process or Process.create_process directly.
The advantage of Process.run is that it captures the output. I suppose
you might conceivably want to capture stderr but leave stdout attached
to the console, but it's a lot less common than "run program, give it
input, retrieve output, but if it displays an error, let that be
seen". I can't think of any use-cases for the converse. Process.run()
is great, but there are a lot of times when I have to either replicate
half of its code, or use run() and risk squashing an unexpected error.
With check_run, I'd be able to have virtually the same API, but with
the declaration that a program error is an exception.

Consider a simple way to get audio file information:

string info = Process.run(({"soxi", "audio_01.wav"}))->stdout;
//proceed to parse the given info, eg:
sscanf(info, "%*[\n]%{%s: %s\n%}", array lines);
mapping fields = (mapping)lines;

If soxi is not available, this will raise an immediate exception,
rather than charging on blindly; but if audio_01.wav isn't found,
there's no indication of the actual problem - you just don't get any
useful output. Using check_run causes an instant failure, saying that
the process exited 1; and keeping stderr attached to the console would
let the user see the message from soxi:

string info = Process.check_run(({"soxi", "audio_01.wav"}),
(["stderr": "-"]))->stdout;

In fact, this usage could itself be wrapped up another level, if
desired. I've tossed another commit onto the branch to add a
check_output function, but this one is less significant (it's just a
one-liner). With check_output, omitting the modifiers mapping gives
the natural and obvious behaviour of the above line of code.

ChrisA

Reply via email to