| OLD | NEW |
| 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 | 5 |
| 6 """Wrapper for Google Factory Tools (gooftool). | 6 """Wrapper for Google Factory Tools (gooftool). |
| 7 | 7 |
| 8 This module provides fast access to "gooftool". | 8 This module provides fast access to "gooftool". |
| 9 """ | 9 """ |
| 10 | 10 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 GOOFTOOL_HOME = '/usr/local/gooftool' | 22 GOOFTOOL_HOME = '/usr/local/gooftool' |
| 23 | 23 |
| 24 | 24 |
| 25 def run(command, ignore_status=False): | 25 def run(command, ignore_status=False): |
| 26 """Runs a gooftool command. | 26 """Runs a gooftool command. |
| 27 | 27 |
| 28 Args: | 28 Args: |
| 29 command: Shell command to execute. | 29 command: Shell command to execute. |
| 30 ignore_status: False to raise exectopion when execution result is not 0. | 30 ignore_status: False to raise exectopion when execution result is not 0. |
| 31 | 31 |
| 32 Returns: |
| 33 (stdout, stderr, return_code) of the execution results. |
| 34 |
| 32 Raises: | 35 Raises: |
| 33 error.TestError: The error message in "ERROR:.*" form by command. | 36 error.TestError: The error message in "ERROR:.*" form by command. |
| 34 """ | 37 """ |
| 35 # prepare command | |
| 36 system_cmd = 'PATH="%s:$PATH" %s' % (GOOFTOOL_HOME, command) | |
| 37 factory.log("Running gooftool: " + system_cmd) | |
| 38 | 38 |
| 39 # prepare execution environment | 39 factory.log("Running gooftool: " + command) |
| 40 |
| 41 # We want the stderr goes to CONSOLE_LOG_PATH immediately, but tee only |
| 42 # works with stdout; so here's a tiny trick to swap the handles. |
| 43 swap_stdout_stderr = '3>&1 1>&2 2>&3' |
| 44 |
| 45 # When using pipes, return code is from the last command; so we need to use |
| 46 # a temporary file for the return code of first command. |
| 47 return_code_file = tempfile.NamedTemporaryFile() |
| 48 system_cmd = ('(PATH=%s:$PATH %s %s || echo $? >"%s") | tee -a "%s"' % |
| 49 (GOOFTOOL_HOME, command, swap_stdout_stderr, |
| 50 return_code_file.name, factory.CONSOLE_LOG_PATH)) |
| 40 proc = subprocess.Popen(system_cmd, | 51 proc = subprocess.Popen(system_cmd, |
| 41 stderr=subprocess.PIPE, | 52 stderr=subprocess.PIPE, |
| 42 stdout=subprocess.PIPE, | 53 stdout=subprocess.PIPE, |
| 43 shell=True) | 54 shell=True) |
| 44 (out, err) = proc.communicate() | 55 |
| 56 # The order of output is reversed because we swapped stdout and stderr. |
| 57 (err, out) = proc.communicate() |
| 45 | 58 |
| 46 # normalize output data | 59 # normalize output data |
| 47 if out[-1:] == '\n': | 60 out = out or '' |
| 61 err = err or '' |
| 62 if out.endswith('\n'): |
| 48 out = out[:-1] | 63 out = out[:-1] |
| 49 err = err.strip() | 64 if err.endswith('\n'): |
| 65 err = err[:-1] |
| 50 | 66 |
| 51 if proc.wait() and (not ignore_status): | 67 # build return code and log results |
| 52 # log every detail. | 68 return_code_file.seek(0) |
| 53 out = out.strip() | 69 return_code = int(return_code_file.read() or '0') |
| 54 if out or err: | 70 return_code_file.close() |
| 55 message = '\n'.join([out, err]) | 71 return_code = proc.wait() or return_code |
| 56 else: | 72 message = ('gooftool result: %s (%s), message: %s' % |
| 57 message = '(None)' | 73 (('FAILED' if return_code else 'SUCCESS'), |
| 58 factory.log('gooftool execution failed, message: ' + message) | 74 return_code, '\n'.join([out,err]) or '(None)')) |
| 75 factory.log(message) |
| 76 |
| 77 if return_code and (not ignore_status): |
| 59 # try to parse "ERROR.*" from err & out. | 78 # try to parse "ERROR.*" from err & out. |
| 60 exception_message = [error_message for error_message in err.splitlines() | 79 exception_message = '\n'.join( |
| 61 if error_message.startswith('ERROR')] | 80 [error_message for error_message in err.splitlines() |
| 62 exception_message = ('\n'.join(exception_message) | 81 if error_message.startswith('ERROR')]) or message |
| 63 if exception_message | |
| 64 else 'Failed: %s\n%s\n%s' % (system_cmd, out, err)) | |
| 65 raise error.TestError(exception_message) | 82 raise error.TestError(exception_message) |
| 66 if out or err: | 83 |
| 67 factory.log('gooftool results:\n%s\n%s' % (out, err)) | 84 return (out, err, return_code) |
| 68 return out | |
| OLD | NEW |