diff options
author | Lars Wirzenius <liw@liw.fi> | 2015-02-08 12:43:18 +0200 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2015-02-08 12:43:18 +0200 |
commit | b60e77b2c8d30d8b1673d45a529623cd76e2b917 (patch) | |
tree | 1cda19b7467776ee187465073a85998a4e58f9a6 | |
parent | 21a3b4c139bebfbd918220f67aeb2fc754defcf9 (diff) | |
parent | a8f4c1c898814b75b366060993e46f4b53f7596f (diff) | |
download | cliapp-b60e77b2c8d30d8b1673d45a529623cd76e2b917.tar.gz |
Collect all stderrs from pipeline
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | cliapp/runcmd.py | 20 |
2 files changed, 20 insertions, 4 deletions
@@ -15,6 +15,10 @@ Version UNRELEASED descriptor in the parent results in `SIGPIPE` being sent to the `cat` process once `false` terminates. +* Richard Maw changed `cliapp.runcmd` so that the stderr of all + commands in the pipeline are collected, when stderr is set to + `subprocess.PIPE`. + Version 1.20140719 ------------------ diff --git a/cliapp/runcmd.py b/cliapp/runcmd.py index 2757068..5ac8da5 100644 --- a/cliapp/runcmd.py +++ b/cliapp/runcmd.py @@ -112,23 +112,27 @@ def runcmd_unchecked(argv, *argvs, **kwargs): def _build_pipeline(argvs, pipe_stdin, pipe_stdout, pipe_stderr, kwargs): procs = [] + + if pipe_stderr == subprocess.PIPE: + # Make pipe for all subprocesses to share + rpipe, wpipe = os.pipe() + stderr = wpipe + else: + stderr = pipe_stderr + for i, argv in enumerate(argvs): if i == 0 and i == len(argvs) - 1: stdin = pipe_stdin stdout = pipe_stdout - stderr = pipe_stderr elif i == 0: stdin = pipe_stdin stdout = subprocess.PIPE - stderr = pipe_stderr elif i == len(argvs) - 1: stdin = procs[-1].stdout stdout = pipe_stdout - stderr = pipe_stderr else: stdin = procs[-1].stdout stdout = subprocess.PIPE - stderr = pipe_stderr p = subprocess.Popen(argv, stdin=stdin, stdout=stdout, stderr=stderr, close_fds=True, **kwargs) @@ -142,6 +146,14 @@ def _build_pipeline(argvs, pipe_stdin, pipe_stdout, pipe_stderr, kwargs): procs.append(p) + if pipe_stderr == subprocess.PIPE: + # Ensure only subprocesses hold the write end of the pipe, so we get + # EOF when they all terminate + os.close(wpipe) + # Allow reading of the stderr of every process as the stderr of + # the last element + procs[-1].stderr = os.fdopen(rpipe) + return procs def _run_pipeline(procs, feed_stdin, pipe_stdin, pipe_stdout, pipe_stderr, |