summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2015-02-08 12:43:18 +0200
committerLars Wirzenius <liw@liw.fi>2015-02-08 12:43:18 +0200
commitb60e77b2c8d30d8b1673d45a529623cd76e2b917 (patch)
tree1cda19b7467776ee187465073a85998a4e58f9a6
parent21a3b4c139bebfbd918220f67aeb2fc754defcf9 (diff)
parenta8f4c1c898814b75b366060993e46f4b53f7596f (diff)
downloadcliapp-b60e77b2c8d30d8b1673d45a529623cd76e2b917.tar.gz
Collect all stderrs from pipeline
-rw-r--r--NEWS4
-rw-r--r--cliapp/runcmd.py20
2 files changed, 20 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index f831ace..0e21b58 100644
--- a/NEWS
+++ b/NEWS
@@ -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,