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 |