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 """Common python commands used by various build scripts.""" | 5 """Common python commands used by various build scripts.""" |
6 | 6 |
7 import inspect | 7 import inspect |
8 import os | 8 import os |
9 import re | 9 import re |
10 import subprocess | 10 import subprocess |
11 import sys | 11 import sys |
12 | 12 |
13 _STDOUT_IS_TTY = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() | 13 _STDOUT_IS_TTY = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() |
14 | 14 |
15 # TODO(sosa): Move logging to logging module. | 15 # TODO(sosa): Move logging to logging module. |
16 | 16 |
17 class RunCommandException(Exception): | 17 class RunCommandException(Exception): |
18 """Raised when there is an error in RunCommand.""" | 18 """Raised when there is an error in RunCommand.""" |
19 pass | 19 pass |
20 | 20 |
21 | 21 |
22 def GetCallerName(): | 22 def GetCallerName(): |
23 """Returns the name of the calling module with __main__.""" | 23 """Returns the name of the calling module with __main__.""" |
24 top_frame = inspect.stack()[-1][0] | 24 top_frame = inspect.stack()[-1][0] |
25 return os.path.basename(top_frame.f_code.co_filename) | 25 return os.path.basename(top_frame.f_code.co_filename) |
26 | 26 |
27 | 27 |
28 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None, | 28 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None, |
29 exit_code=False, redirect_stdout=False, redirect_stderr=False, | 29 exit_code=False, redirect_stdout=False, redirect_stderr=False, |
30 cwd=None, input=None, enter_chroot=False, num_retries=0): | 30 cwd=None, input=None, enter_chroot=False, num_retries=0, |
| 31 log_to_file=None): |
31 """Runs a shell command. | 32 """Runs a shell command. |
32 | 33 |
33 Arguments: | 34 Arguments: |
34 cmd: cmd to run. Should be input to subprocess.POpen. If a string, | 35 cmd: cmd to run. Should be input to subprocess.POpen. If a string, |
35 converted to an array using split(). | 36 converted to an array using split(). |
36 print_cmd: prints the command before running it. | 37 print_cmd: prints the command before running it. |
37 error_ok: does not raise an exception on error. | 38 error_ok: does not raise an exception on error. |
38 error_message: prints out this message when an error occurrs. | 39 error_message: prints out this message when an error occurrs. |
39 exit_code: returns the return code of the shell command. | 40 exit_code: returns the return code of the shell command. |
40 redirect_stdout: returns the stdout. | 41 redirect_stdout: returns the stdout. |
41 redirect_stderr: holds stderr output until input is communicated. | 42 redirect_stderr: holds stderr output until input is communicated. |
42 cwd: the working directory to run this cmd. | 43 cwd: the working directory to run this cmd. |
43 input: input to pipe into this command through stdin. | 44 input: input to pipe into this command through stdin. |
44 enter_chroot: this command should be run from within the chroot. If set, | 45 enter_chroot: this command should be run from within the chroot. If set, |
45 cwd must point to the scripts directory. | 46 cwd must point to the scripts directory. |
46 num_retries: the number of retries to perform before dying | 47 num_retries: the number of retries to perform before dying |
| 48 log_to_file: Redirects all stderr and stdout to file specified by this path. |
47 | 49 |
48 Returns: | 50 Returns: |
49 If exit_code is True, returns the return code of the shell command. | 51 If exit_code is True, returns the return code of the shell command. |
50 Else returns the output of the shell command. | 52 Else returns the output of the shell command. |
51 | 53 |
52 Raises: | 54 Raises: |
53 Exception: Raises RunCommandException on error with optional error_message, | 55 Exception: Raises RunCommandException on error with optional error_message, |
| 56 |
54 but only if exit_code, and error_ok are both False. | 57 but only if exit_code, and error_ok are both False. |
55 """ | 58 """ |
56 # Set default for variables. | 59 # Set default for variables. |
57 stdout = None | 60 stdout = None |
58 stderr = None | 61 stderr = None |
59 stdin = None | 62 stdin = None |
| 63 file_handle = None |
60 output = '' | 64 output = '' |
61 | 65 |
62 # Modify defaults based on parameters. | 66 # Modify defaults based on parameters. |
63 if redirect_stdout: stdout = subprocess.PIPE | 67 if log_to_file: |
64 if redirect_stderr: stderr = subprocess.PIPE | 68 file_handle = open(log_to_file, 'w+') |
| 69 stdout = file_handle |
| 70 stderr = file_handle |
| 71 else: |
| 72 if redirect_stdout: stdout = subprocess.PIPE |
| 73 if redirect_stderr: stderr = subprocess.PIPE |
| 74 |
65 if input: stdin = subprocess.PIPE | 75 if input: stdin = subprocess.PIPE |
66 if enter_chroot: cmd = ['./enter_chroot.sh', '--'] + cmd | 76 if enter_chroot: cmd = ['./enter_chroot.sh', '--'] + cmd |
67 | 77 |
68 # Print out the command before running. | 78 # Print out the command before running. |
| 79 cmd_string = 'PROGRAM(%s) -> RunCommand: %r in dir %s' % (GetCallerName(), |
| 80 cmd, cwd) |
69 if print_cmd: | 81 if print_cmd: |
70 Info('PROGRAM(%s) -> RunCommand: %r in dir %s' % | 82 if not log_to_file: |
71 (GetCallerName(), cmd, cwd)) | 83 Info(cmd_string) |
| 84 else: |
| 85 Info('%s -- Logging to %s' % (cmd_string, log_to_file)) |
72 | 86 |
73 for retry_count in range(num_retries + 1): | 87 for retry_count in range(num_retries + 1): |
74 | 88 |
75 # If it's not the first attempt, it's a retry | 89 # If it's not the first attempt, it's a retry |
76 if retry_count > 0 and print_cmd: | 90 if retry_count > 0 and print_cmd: |
77 Info('PROGRAM(%s) -> RunCommand: retrying %r in dir %s' % | 91 Info('PROGRAM(%s) -> RunCommand: retrying %r in dir %s' % |
78 (GetCallerName(), cmd, cwd)) | 92 (GetCallerName(), cmd, cwd)) |
79 | 93 |
80 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin, | 94 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin, |
81 stdout=stdout, stderr=stderr) | 95 stdout=stdout, stderr=stderr) |
82 (output, error) = proc.communicate(input) | 96 (output, error) = proc.communicate(input) |
83 | 97 |
84 # if the command worked, don't retry any more. | 98 # if the command worked, don't retry any more. |
85 if proc.returncode == 0: | 99 if proc.returncode == 0: |
86 break | 100 break |
87 | 101 |
| 102 if file_handle: file_handle.close() |
| 103 |
88 # If they asked for an exit_code, give it to them on success or failure | 104 # If they asked for an exit_code, give it to them on success or failure |
89 if exit_code: | 105 if exit_code: |
90 return proc.returncode | 106 return proc.returncode |
91 | 107 |
92 # If the command (and all retries) failed, handle error result | 108 # If the command (and all retries) failed, handle error result |
93 if proc.returncode != 0: | 109 if proc.returncode != 0: |
94 if error_ok: | 110 if error_ok: |
95 Warning('Command "%r" failed.\n' % (cmd) + | 111 Warning('Command "%r" failed.\n' % (cmd) + |
96 (error_message or error or output or '')) | 112 (error_message or error or output or '')) |
97 else: | 113 else: |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 # Strip the repository root from the path and strip first /. | 265 # Strip the repository root from the path and strip first /. |
250 relative_path = path_abs_path.replace(root_abs_path, '')[1:] | 266 relative_path = path_abs_path.replace(root_abs_path, '')[1:] |
251 | 267 |
252 if relative_path == path_abs_path: | 268 if relative_path == path_abs_path: |
253 raise Exception('Error: path is outside your src tree, cannot reinterpret.') | 269 raise Exception('Error: path is outside your src tree, cannot reinterpret.') |
254 | 270 |
255 new_path = os.path.join('/home', os.getenv('USER'), 'trunk', relative_path) | 271 new_path = os.path.join('/home', os.getenv('USER'), 'trunk', relative_path) |
256 return new_path | 272 return new_path |
257 | 273 |
258 | 274 |
| 275 def PrependChrootPath(path): |
| 276 """Assumes path is a chroot path and prepends chroot to create full path.""" |
| 277 chroot_path = os.path.join(FindRepoDir(), '..', 'chroot') |
| 278 if path.startswith('/'): |
| 279 return os.path.realpath(os.path.join(chroot_path, path[1:])) |
| 280 else: |
| 281 return os.path.realpath(os.path.join(chroot_path, path)) |
| 282 |
| 283 |
259 def GetIPAddress(device='eth0'): | 284 def GetIPAddress(device='eth0'): |
260 """Returns the IP Address for a given device using ifconfig. | 285 """Returns the IP Address for a given device using ifconfig. |
261 | 286 |
262 socket.gethostname() is insufficient for machines where the host files are | 287 socket.gethostname() is insufficient for machines where the host files are |
263 not set up "correctly." Since some of our builders may have this issue, | 288 not set up "correctly." Since some of our builders may have this issue, |
264 this method gives you a generic way to get the address so you are reachable | 289 this method gives you a generic way to get the address so you are reachable |
265 either via a VM or remote machine on the same network. | 290 either via a VM or remote machine on the same network. |
266 """ | 291 """ |
267 ifconfig_output = RunCommand(['/sbin/ifconfig', device], | 292 ifconfig_output = RunCommand(['/sbin/ifconfig', device], |
268 redirect_stdout=True, print_cmd=False) | 293 redirect_stdout=True, print_cmd=False) |
269 match = re.search('.*inet addr:(\d+\.\d+\.\d+\.\d+).*', ifconfig_output) | 294 match = re.search('.*inet addr:(\d+\.\d+\.\d+\.\d+).*', ifconfig_output) |
270 if match: | 295 if match: |
271 return match.group(1) | 296 return match.group(1) |
272 else: | 297 else: |
273 Warning('Failed to find ip address in %s' % ifconfig_output) | 298 Warning('Failed to find ip address in %s' % ifconfig_output) |
274 return None | 299 return None |
OLD | NEW |