Completed
Pull Request — master (#2500)
by Zatreanu
01:48
created

call_without_output()   A

Complexity

Conditions 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
c 1
b 0
f 0
dl 0
loc 8
rs 9.4285
1
from contextlib import contextmanager
2
import functools
0 ignored issues
show
Unused Code introduced by
The import functools seems to be unused.
Loading history...
3
import platform
4
import shlex
5
from subprocess import PIPE, Popen, call, DEVNULL
6
7
8
def call_without_output(command):
9
    """
10
    Uses subprocess.call to execute a command, but surpresses the output and
11
    the errors.
12
    """
13
    if platform.system() == 'Windows':  # pragma: no cover
14
        command = ['cmd', '/c'] + command
15
    call((command), stdout=DEVNULL, stderr=DEVNULL)
16
17
18
@contextmanager
19
def run_interactive_shell_command(command, **kwargs):
20
    """
21
    Runs a single command in shell and provides stdout, stderr and stdin
22
    streams.
23
24
    This function creates a context manager that sets up the process (using
25
    ``subprocess.Popen()``), returns to caller and waits for process to exit on
26
    leaving.
27
28
    By default the process is opened in ``universal_newlines`` mode and creates
29
    pipes for all streams (stdout, stderr and stdin) using ``subprocess.PIPE``
30
    special value. These pipes are closed automatically, so if you want to get
31
    the contents of the streams you should retrieve them before the context
32
    manager exits.
33
34
    >>> with run_interactive_shell_command(["echo", "TEXT"]) as p:
35
    ...     stdout = p.stdout
36
    ...     stdout_text = stdout.read()
37
    >>> stdout_text
38
    'TEXT\\n'
39
    >>> stdout.closed
40
    True
41
42
    Custom streams provided are not closed except of ``subprocess.PIPE``.
43
44
    >>> from tempfile import TemporaryFile
45
    >>> stream = TemporaryFile()
46
    >>> with run_interactive_shell_command(["echo", "TEXT"],
47
    ...                                    stdout=stream) as p:
48
    ...     stderr = p.stderr
49
    >>> stderr.closed
50
    True
51
    >>> stream.closed
52
    False
53
54
    :param command: The command to run on shell. This parameter can either
55
                    be a sequence of arguments that are directly passed to
56
                    the process or a string. A string gets splitted beforehand
57
                    using ``shlex.split()``. If providing ``shell=True`` as a
58
                    keyword-argument, no ``shlex.split()`` is performed and the
59
                    command string goes directly to ``subprocess.Popen()``.
60
    :param kwargs:  Additional keyword arguments to pass to
61
                    ``subprocess.Popen`` that are used to spawn the process.
62
    :return:        A context manager yielding the process started from the
63
                    command.
64
    """
65
    if not kwargs.get("shell", False) and isinstance(command, str):
66
        command = shlex.split(command)
67
68
    args = {"stdout": PIPE,
69
            "stderr": PIPE,
70
            "stdin": PIPE,
71
            "universal_newlines": True}
72
    args.update(kwargs)
73
74
    process = Popen(command, **args)
75
    try:
76
        yield process
77
    finally:
78
        if args["stdout"] is PIPE:
79
            process.stdout.close()
80
        if args["stderr"] is PIPE:
81
            process.stderr.close()
82
        if args["stdin"] is PIPE:
83
            process.stdin.close()
84
85
        process.wait()
86
87
88
def run_shell_command(command, stdin=None, **kwargs):
89
    """
90
    Runs a single command in shell and returns the read stdout and stderr data.
91
92
    This function waits for the process (created using ``subprocess.Popen()``)
93
    to exit. Effectively it wraps ``run_interactive_shell_command()`` and uses
94
    ``communicate()`` on the process.
95
96
    See also ``run_interactive_shell_command()``.
97
98
    :param command: The command to run on shell. This parameter can either
99
                    be a sequence of arguments that are directly passed to
100
                    the process or a string. A string gets splitted beforehand
101
                    using ``shlex.split()``.
102
    :param stdin:   Initial input to send to the process.
103
    :param kwargs:  Additional keyword arguments to pass to
104
                    ``subprocess.Popen`` that is used to spawn the process.
105
    :return:        A tuple with ``(stdoutstring, stderrstring)``.
106
    """
107
    with run_interactive_shell_command(command, **kwargs) as p:
108
        ret = p.communicate(stdin)
109
    return ret
110
111
112
def get_shell_type():  # pragma: no cover
113
    """
114
    Finds the current shell type based on the outputs of common pre-defined
115
    variables in them. This is useful to identify which sort of escaping
116
    is required for strings.
117
118
    :return: The shell type. This can be either "powershell" if Windows
119
             Powershell is detected, "cmd" if command prompt is been
120
             detected or "sh" if it's neither of these.
121
    """
122
    out = run_shell_command("echo $host.name", shell=True)[0]
123
    if out.strip() == "ConsoleHost":
124
        return "powershell"
125
    out = run_shell_command("echo $0", shell=True)[0]
126
    if out.strip() == "$0":
127
        return "cmd"
128
    return "sh"
129