diff options
-rw-r--r-- | gbp/command_wrappers.py | 65 |
1 files changed, 49 insertions, 16 deletions
diff --git a/gbp/command_wrappers.py b/gbp/command_wrappers.py index f99b1e85..e16c1080 100644 --- a/gbp/command_wrappers.py +++ b/gbp/command_wrappers.py @@ -22,6 +22,10 @@ git-buildpackage and friends import subprocess import os import signal +import sys +from contextlib import contextmanager +from tempfile import TemporaryFile + import gbp.log as log @@ -30,6 +34,35 @@ class CommandExecFailed(Exception): pass +@contextmanager +def proxy_stdf(): + """ + Circulate stdout/stderr via a proper file object. Designed to work around a + problem where Python nose replaces sys.stdout/stderr with a custom 'Tee' + object that is not a file object (compatible) and thus causes a crash with + Popen. + """ + stdout = None + if not hasattr(sys.stdout, 'fileno'): + stdout = sys.stdout + sys.stdout = TemporaryFile() + stderr = None + if not hasattr(sys.stderr, 'fileno'): + stderr = sys.stderr + sys.stderr = TemporaryFile() + try: + yield + finally: + if stdout: + sys.stdout.seek(0) + stdout.write(sys.stdout.read()) + sys.stdout = stdout + if stderr: + sys.stderr.seek(0) + stderr.write(sys.stderr.read()) + sys.stderr = stderr + + class Command(object): """ Wraps a shell command, so we don't have to store any kind of command @@ -67,26 +100,26 @@ class Command(object): log.debug("%s %s %s" % (self.cmd, self.args, args)) self._reset_state() - stdout_arg = subprocess.PIPE if self.capture_stdout else None - stderr_arg = subprocess.PIPE if self.capture_stderr else None cmd = [self.cmd] + self.args + args if self.shell: # subprocess.call only cares about the first argument if shell=True cmd = " ".join(cmd) - - try: - popen = subprocess.Popen(cmd, - cwd=self.cwd, - shell=self.shell, - env=self.env, - preexec_fn=default_sigpipe, - stdout=stdout_arg, - stderr=stderr_arg) - (self.stdout, self.stderr) = popen.communicate() - except OSError as err: - self.err_reason = "execution failed: %s" % str(err) - self.retcode = 1 - raise + with proxy_stdf(): + stdout_arg = subprocess.PIPE if self.capture_stdout else sys.stdout + stderr_arg = subprocess.PIPE if self.capture_stderr else sys.stderr + try: + popen = subprocess.Popen(cmd, + cwd=self.cwd, + shell=self.shell, + env=self.env, + preexec_fn=default_sigpipe, + stdout=stdout_arg, + stderr=stderr_arg) + (self.stdout, self.stderr) = popen.communicate() + except OSError as err: + self.err_reason = "execution failed: %s" % str(err) + self.retcode = 1 + raise self.retcode = popen.returncode if self.retcode < 0: |