mirror of
https://git.launchpad.net/ubuntu-dev-tools
synced 2025-03-13 16:11:15 +00:00
112 lines
3.6 KiB
Python
112 lines
3.6 KiB
Python
"""Drop-in replacement for subprocess with better defaults
|
|
|
|
This is an API-compatible replacement for the built-in subprocess
|
|
module whose defaults better line up with our tastes.
|
|
|
|
In particular, it:
|
|
- Adds support for the restore_signals flag if subprocess itself
|
|
doesn't support it
|
|
- Defaults close_fds to True
|
|
"""
|
|
|
|
|
|
from __future__ import absolute_import
|
|
|
|
import inspect
|
|
import signal
|
|
import subprocess
|
|
|
|
from subprocess import PIPE, STDOUT, CalledProcessError
|
|
|
|
__all__ = ['Popen', 'call', 'check_call', 'check_output', 'CalledProcessError',
|
|
'PIPE', 'STDOUT']
|
|
|
|
|
|
class Popen(subprocess.Popen):
|
|
def __init__(self, *args, **kwargs):
|
|
kwargs.setdefault('close_fds', True)
|
|
|
|
if ('restore_signals' not in
|
|
inspect.getargspec(subprocess.Popen.__init__)[0]):
|
|
given_preexec_fn = kwargs.pop('preexec_fn', None)
|
|
restore_signals = kwargs.pop('restore_signals', True)
|
|
def preexec_fn():
|
|
if restore_signals:
|
|
for sig in ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ'):
|
|
if hasattr(signal, sig):
|
|
signal.signal(getattr(signal, sig),
|
|
signal.SIG_DFL)
|
|
|
|
if given_preexec_fn:
|
|
given_preexec_fn()
|
|
kwargs['preexec_fn'] = preexec_fn
|
|
|
|
subprocess.Popen.__init__(self, *args, **kwargs)
|
|
|
|
|
|
# call, check_call, and check_output are copied directly from the
|
|
# subprocess module shipped with Python 2.7.1-5ubuntu2
|
|
|
|
|
|
def call(*popenargs, **kwargs):
|
|
"""Run command with arguments. Wait for command to complete, then
|
|
return the returncode attribute.
|
|
|
|
The arguments are the same as for the Popen constructor. Example:
|
|
|
|
retcode = call(["ls", "-l"])
|
|
"""
|
|
return Popen(*popenargs, **kwargs).wait()
|
|
|
|
|
|
def check_call(*popenargs, **kwargs):
|
|
"""Run command with arguments. Wait for command to complete. If
|
|
the exit code was zero then return, otherwise raise
|
|
CalledProcessError. The CalledProcessError object will have the
|
|
return code in the returncode attribute.
|
|
|
|
The arguments are the same as for the Popen constructor. Example:
|
|
|
|
check_call(["ls", "-l"])
|
|
"""
|
|
retcode = call(*popenargs, **kwargs)
|
|
if retcode:
|
|
cmd = kwargs.get("args")
|
|
if cmd is None:
|
|
cmd = popenargs[0]
|
|
raise CalledProcessError(retcode, cmd)
|
|
return 0
|
|
|
|
|
|
def check_output(*popenargs, **kwargs):
|
|
r"""Run command with arguments and return its output as a byte string.
|
|
|
|
If the exit code was non-zero it raises a CalledProcessError. The
|
|
CalledProcessError object will have the return code in the returncode
|
|
attribute and output in the output attribute.
|
|
|
|
The arguments are the same as for the Popen constructor. Example:
|
|
|
|
>>> check_output(["ls", "-l", "/dev/null"])
|
|
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
|
|
|
|
The stdout argument is not allowed as it is used internally.
|
|
To capture standard error in the result, use stderr=STDOUT.
|
|
|
|
>>> check_output(["/bin/sh", "-c",
|
|
... "ls -l non_existent_file ; exit 0"],
|
|
... stderr=STDOUT)
|
|
'ls: non_existent_file: No such file or directory\n'
|
|
"""
|
|
if 'stdout' in kwargs:
|
|
raise ValueError('stdout argument not allowed, it will be overridden.')
|
|
process = Popen(stdout=PIPE, *popenargs, **kwargs)
|
|
output, unused_err = process.communicate()
|
|
retcode = process.poll()
|
|
if retcode:
|
|
cmd = kwargs.get("args")
|
|
if cmd is None:
|
|
cmd = popenargs[0]
|
|
raise CalledProcessError(retcode, cmd, output=output)
|
|
return output
|