Run a command specified by args, and return string representing the stdout of the run command, raising an error if exit code was nonzero (unless exitcode kwarg is specified; see below). Args: *args: the list of command line arguments to run e
(
self,
*args: str, # noqa: C901
env: Optional[Dict[str, str]] = None,
stderr: _HANDLE = None,
# TODO: Arguably bytes should be accepted here too
input: Optional[str] = None,
stdin: _HANDLE = None,
stdout: _HANDLE = subprocess.PIPE,
exitcode: bool = False,
tick: bool = False,
)
| 83 | self.testing_time = 1112911993 |
| 84 | |
| 85 | def sh( |
| 86 | self, |
| 87 | *args: str, # noqa: C901 |
| 88 | env: Optional[Dict[str, str]] = None, |
| 89 | stderr: _HANDLE = None, |
| 90 | # TODO: Arguably bytes should be accepted here too |
| 91 | input: Optional[str] = None, |
| 92 | stdin: _HANDLE = None, |
| 93 | stdout: _HANDLE = subprocess.PIPE, |
| 94 | exitcode: bool = False, |
| 95 | tick: bool = False, |
| 96 | ) -> _SHELL_RET: |
| 97 | """ |
| 98 | Run a command specified by args, and return string representing |
| 99 | the stdout of the run command, raising an error if exit code |
| 100 | was nonzero (unless exitcode kwarg is specified; see below). |
| 101 | |
| 102 | Args: |
| 103 | *args: the list of command line arguments to run |
| 104 | env: any extra environment variables to set when running the |
| 105 | command. Environment variables set this way are ADDITIVE |
| 106 | (unlike subprocess default) |
| 107 | stderr: where to pipe stderr; by default, we pipe it straight |
| 108 | to this process's stderr |
| 109 | input: string value to pass stdin. This is mutually exclusive |
| 110 | with stdin |
| 111 | stdin: where to pipe stdin from. This is mutually exclusive |
| 112 | with input |
| 113 | stdout: where to pipe stdout; by default, we capture the stdout |
| 114 | and return it |
| 115 | exitcode: if True, return a bool rather than string, specifying |
| 116 | whether or not the process successfully returned with exit |
| 117 | code 0. We never raise an exception when this is True. |
| 118 | """ |
| 119 | assert not (stdin and input) |
| 120 | if tick: |
| 121 | self.test_tick() |
| 122 | if input: |
| 123 | stdin = subprocess.PIPE |
| 124 | if not self.quiet: |
| 125 | log_command(args) |
| 126 | if env is not None: |
| 127 | env = merge_dicts(dict(os.environ), env) |
| 128 | |
| 129 | # The things we do for logging... |
| 130 | # |
| 131 | # - I didn't make a PTY, so programs are going to give |
| 132 | # output assuming there isn't a terminal at the other |
| 133 | # end. This is less nice for direct terminal use, but |
| 134 | # it's better for logging (since we get to dispense |
| 135 | # with the control codes). |
| 136 | # |
| 137 | # - We assume line buffering. This is kind of silly but |
| 138 | # we need to assume *some* sort of buffering with the |
| 139 | # stream API. |
| 140 | |
| 141 | async def process_stream( |
| 142 | proc_stream: asyncio.StreamReader, setting: _HANDLE, default_stream: IO[str] |