2017-05-24 23:33:35 +00:00
|
|
|
from functools import partial
|
2017-05-16 01:54:51 +00:00
|
|
|
import subprocess
|
|
|
|
|
2017-05-24 21:11:37 +00:00
|
|
|
def execute_cmd(cmd, capture=False, **kwargs):
|
2017-05-16 01:54:51 +00:00
|
|
|
"""
|
2017-05-24 21:11:37 +00:00
|
|
|
Call given command, yielding output line by line if capture=True
|
2017-05-16 01:54:51 +00:00
|
|
|
"""
|
2017-05-24 21:11:37 +00:00
|
|
|
if capture:
|
|
|
|
kwargs['stdout'] = subprocess.PIPE
|
|
|
|
kwargs['stderr'] = subprocess.STDOUT
|
|
|
|
|
|
|
|
proc = subprocess.Popen(cmd, **kwargs)
|
|
|
|
|
|
|
|
if not capture:
|
2017-05-24 23:42:25 +00:00
|
|
|
# not capturing output, let the subprocesses talk directly to the terminal
|
2017-05-24 21:11:37 +00:00
|
|
|
ret = proc.wait()
|
|
|
|
if ret != 0:
|
|
|
|
raise subprocess.CalledProcessError(ret, cmd)
|
|
|
|
return
|
2017-05-24 23:33:35 +00:00
|
|
|
|
2017-05-24 23:42:25 +00:00
|
|
|
# Capture output for logging.
|
|
|
|
# Each line will be yielded as text.
|
|
|
|
# This should behave the same as .readline(), but splits on `\r` OR `\n`,
|
|
|
|
# not just `\n`.
|
2017-05-24 23:33:35 +00:00
|
|
|
buf = []
|
|
|
|
def flush():
|
|
|
|
line = b''.join(buf).decode('utf8', 'replace')
|
|
|
|
buf[:] = []
|
|
|
|
return line
|
|
|
|
|
|
|
|
c_last = ''
|
2017-05-19 07:07:39 +00:00
|
|
|
try:
|
2017-05-24 23:33:35 +00:00
|
|
|
for c in iter(partial(proc.stdout.read, 1), b''):
|
|
|
|
if c_last == b'\r' and buf and c != b'\n':
|
|
|
|
yield flush()
|
|
|
|
buf.append(c)
|
|
|
|
if c == b'\n':
|
|
|
|
yield flush()
|
|
|
|
c_last = c
|
2017-05-19 07:07:39 +00:00
|
|
|
finally:
|
|
|
|
ret = proc.wait()
|
|
|
|
if ret != 0:
|
|
|
|
raise subprocess.CalledProcessError(ret, cmd)
|