Index: client/cros/gooftools.py |
diff --git a/client/cros/gooftools.py b/client/cros/gooftools.py |
index b3dbdcc3bf11f1b174be31e58aeaf1f9079da0b0..c8f07ab7c587fa73f6e6a031614948b3b47db68c 100644 |
--- a/client/cros/gooftools.py |
+++ b/client/cros/gooftools.py |
@@ -29,40 +29,56 @@ def run(command, ignore_status=False): |
command: Shell command to execute. |
ignore_status: False to raise exectopion when execution result is not 0. |
+ Returns: |
+ (stdout, stderr, return_code) of the execution results. |
+ |
Raises: |
error.TestError: The error message in "ERROR:.*" form by command. |
""" |
- # prepare command |
- system_cmd = 'PATH="%s:$PATH" %s' % (GOOFTOOL_HOME, command) |
- factory.log("Running gooftool: " + system_cmd) |
- # prepare execution environment |
+ factory.log("Running gooftool: " + command) |
+ |
+ # We want the stderr goes to CONSOLE_LOG_PATH immediately, but tee only |
+ # works with stdout; so here's a tiny trick to swap the handles. |
+ swap_stdout_stderr = '3>&1 1>&2 2>&3' |
+ |
+ # When using pipes, return code is from the last command; so we need to use |
+ # a temporary file for the return code of first command. |
+ return_code_file = tempfile.NamedTemporaryFile() |
+ system_cmd = ('(PATH=%s:$PATH %s %s || echo $? >"%s") | tee -a "%s"' % |
+ (GOOFTOOL_HOME, command, swap_stdout_stderr, |
+ return_code_file.name, factory.CONSOLE_LOG_PATH)) |
proc = subprocess.Popen(system_cmd, |
stderr=subprocess.PIPE, |
stdout=subprocess.PIPE, |
shell=True) |
- (out, err) = proc.communicate() |
+ |
+ # The order of output is reversed because we swapped stdout and stderr. |
+ (err, out) = proc.communicate() |
# normalize output data |
- if out[-1:] == '\n': |
+ out = out or '' |
+ err = err or '' |
+ if out.endswith('\n'): |
out = out[:-1] |
- err = err.strip() |
- |
- if proc.wait() and (not ignore_status): |
- # log every detail. |
- out = out.strip() |
- if out or err: |
- message = '\n'.join([out, err]) |
- else: |
- message = '(None)' |
- factory.log('gooftool execution failed, message: ' + message) |
+ if err.endswith('\n'): |
+ err = err[:-1] |
+ |
+ # build return code and log results |
+ return_code_file.seek(0) |
+ return_code = int(return_code_file.read() or '0') |
+ return_code_file.close() |
+ return_code = proc.wait() or return_code |
+ message = ('gooftool result: %s (%s), message: %s' % |
+ (('FAILED' if return_code else 'SUCCESS'), |
+ return_code, '\n'.join([out,err]) or '(None)')) |
+ factory.log(message) |
+ |
+ if return_code and (not ignore_status): |
# try to parse "ERROR.*" from err & out. |
- exception_message = [error_message for error_message in err.splitlines() |
- if error_message.startswith('ERROR')] |
- exception_message = ('\n'.join(exception_message) |
- if exception_message |
- else 'Failed: %s\n%s\n%s' % (system_cmd, out, err)) |
+ exception_message = '\n'.join( |
+ [error_message for error_message in err.splitlines() |
+ if error_message.startswith('ERROR')]) or message |
raise error.TestError(exception_message) |
- if out or err: |
- factory.log('gooftool results:\n%s\n%s' % (out, err)) |
- return out |
+ |
+ return (out, err, return_code) |