On Sat, Oct 15, 2016 at 8:12 PM, Stephen R. van den Berg srb@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.CalledProcessEr...
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