Execute CLI command :param cmd: Program and arguments :type cmd: [str] :param env: Environment variables :type env: dict | None :param stdin: File to use for stdin :type stdin: file :param timeout: The timeout for the process to terminate. :type timeout: int :rai
(cmd, env=None, stdin=None, timeout=None)
| 9 | |
| 10 | |
| 11 | def exec_cmd(cmd, env=None, stdin=None, timeout=None): |
| 12 | """Execute CLI command |
| 13 | |
| 14 | :param cmd: Program and arguments |
| 15 | :type cmd: [str] |
| 16 | :param env: Environment variables |
| 17 | :type env: dict | None |
| 18 | :param stdin: File to use for stdin |
| 19 | :type stdin: file |
| 20 | :param timeout: The timeout for the process to terminate. |
| 21 | :type timeout: int |
| 22 | :raises: subprocess.TimeoutExpired when the timeout is reached |
| 23 | before the process finished. |
| 24 | :returns: A tuple with the returncode, stdout and stderr |
| 25 | :rtype: (int, bytes, bytes) |
| 26 | """ |
| 27 | |
| 28 | print('CMD: {!r}'.format(cmd)) |
| 29 | |
| 30 | process = subprocess.Popen( |
| 31 | cmd, |
| 32 | stdin=stdin, |
| 33 | stdout=subprocess.PIPE, |
| 34 | stderr=subprocess.PIPE, |
| 35 | env=env) |
| 36 | |
| 37 | try: |
| 38 | streams = process.communicate(timeout=timeout) |
| 39 | except subprocess.TimeoutExpired: |
| 40 | # The child process is not killed if the timeout expires, so in order |
| 41 | # to cleanup properly a well-behaved application should kill the child |
| 42 | # process and finish communication. |
| 43 | # https://docs.python.org/3.5/library/subprocess.html#subprocess.Popen.communicate |
| 44 | process.kill() |
| 45 | stdout, stderr = process.communicate() |
| 46 | print('STDOUT: {}'.format(stdout.decode('utf-8'))) |
| 47 | print('STDERR: {}'.format(stderr.decode('utf-8'))) |
| 48 | raise |
| 49 | |
| 50 | # This is needed to get rid of '\r' from Windows's lines endings. |
| 51 | stdout, stderr = [stream.replace(b'\r', b'').decode('utf-8') for stream in streams] |
| 52 | |
| 53 | # We should always print the stdout and stderr |
| 54 | print('STDOUT: {}'.format(stdout)) |
| 55 | print('STDERR: {}'.format(stderr)) |
| 56 | |
| 57 | return (process.returncode, stdout, stderr) |
| 58 | |
| 59 | |
| 60 | @pytest.fixture() |
no outgoing calls