summaryrefslogtreecommitdiffstats
path: root/third_party/python/cram/cram/_process.py
blob: decdfbc3a7081278a9998873621d94aab2b98f7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"""Utilities for running subprocesses"""

import os
import signal
import subprocess
import sys

from cram._encoding import fsdecode

__all__ = ['PIPE', 'STDOUT', 'execute']

PIPE = subprocess.PIPE
STDOUT = subprocess.STDOUT

def _makeresetsigpipe():
    """Make a function to reset SIGPIPE to SIG_DFL (for use in subprocesses).

    Doing subprocess.Popen(..., preexec_fn=makeresetsigpipe()) will prevent
    Python's SIGPIPE handler (SIG_IGN) from being inherited by the
    child process.
    """
    if (sys.platform == 'win32' or
        getattr(signal, 'SIGPIPE', None) is None): # pragma: nocover
        return None
    return lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL)

def execute(args, stdin=None, stdout=None, stderr=None, cwd=None, env=None):
    """Run a process and return its output and return code.

    stdin may either be None or a string to send to the process.

    stdout may either be None or PIPE. If set to PIPE, the process's output
    is returned as a string.

    stderr may either be None or STDOUT. If stdout is set to PIPE and stderr
    is set to STDOUT, the process's stderr output will be interleaved with
    stdout and returned as a string.

    cwd sets the process's current working directory.

    env can be set to a dictionary to override the process's environment
    variables.

    This function returns a 2-tuple of (output, returncode).
    """
    if sys.platform == 'win32': # pragma: nocover
        args = [fsdecode(arg) for arg in args]

    p = subprocess.Popen(args, stdin=PIPE, stdout=stdout, stderr=stderr,
                         cwd=cwd, env=env, bufsize=-1,
                         preexec_fn=_makeresetsigpipe(),
                         close_fds=os.name == 'posix')
    out, err = p.communicate(stdin)
    return out, p.returncode