OLD | NEW |
---|---|
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2011 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 shlex | |
davidjames
2011/04/14 21:59:05
This is unused now, right?
Peter Mayo
2011/04/19 03:59:39
Done.
| |
10 import signal | 11 import signal |
11 import subprocess | 12 import subprocess |
12 import sys | 13 import sys |
13 from terminal import Color | 14 from terminal import Color |
14 | 15 |
15 | 16 |
16 _STDOUT_IS_TTY = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() | 17 _STDOUT_IS_TTY = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() |
17 | 18 |
18 | 19 |
19 class CommandResult(object): | 20 class CommandResult(object): |
(...skipping 16 matching lines...) Expand all Loading... | |
36 return (type(self) == type(other) and | 37 return (type(self) == type(other) and |
37 str(self) == str(other) and | 38 str(self) == str(other) and |
38 self.cmd == other.cmd) | 39 self.cmd == other.cmd) |
39 | 40 |
40 def __ne__(self, other): | 41 def __ne__(self, other): |
41 return not self.__eq__(other) | 42 return not self.__eq__(other) |
42 | 43 |
43 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None, | 44 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None, |
44 exit_code=False, redirect_stdout=False, redirect_stderr=False, | 45 exit_code=False, redirect_stdout=False, redirect_stderr=False, |
45 cwd=None, input=None, enter_chroot=False, shell=False, | 46 cwd=None, input=None, enter_chroot=False, shell=False, |
46 env=None, ignore_sigint=False, combine_stdout_stderr=False): | 47 env=None, extra_env=None, ignore_sigint=False, |
48 combine_stdout_stderr=False): | |
47 """Runs a command. | 49 """Runs a command. |
48 | 50 |
49 Args: | 51 Args: |
50 cmd: cmd to run. Should be input to subprocess.Popen. | 52 cmd: cmd to run. Should be input to subprocess.Popen. If a string, it will |
53 be converted to an array by shlex.split() | |
sosa
2011/04/14 21:22:18
Indentation is inconsistent here.
davidjames
2011/04/14 21:59:05
Document that if shell is False, cmd must be an ar
Peter Mayo
2011/04/19 03:59:39
Done.
| |
51 print_cmd: prints the command before running it. | 54 print_cmd: prints the command before running it. |
52 error_ok: does not raise an exception on error. | 55 error_ok: does not raise an exception on error. |
53 error_message: prints out this message when an error occurrs. | 56 error_message: prints out this message when an error occurrs. |
54 exit_code: returns the return code of the shell command. | 57 exit_code: returns the return code of the shell command. |
55 redirect_stdout: returns the stdout. | 58 redirect_stdout: returns the stdout. |
56 redirect_stderr: holds stderr output until input is communicated. | 59 redirect_stderr: holds stderr output until input is communicated. |
57 cwd: the working directory to run this cmd. | 60 cwd: the working directory to run this cmd. |
58 input: input to pipe into this command through stdin. | 61 input: input to pipe into this command through stdin. |
59 enter_chroot: this command should be run from within the chroot. If set, | 62 enter_chroot: this command should be run from within the chroot. If set, |
60 cwd must point to the scripts directory. | 63 cwd must point to the scripts directory. |
61 shell: If shell is True, the specified command will be executed through | 64 shell: If shell is True, the specified command will be executed through |
62 the shell. | 65 the shell. |
davidjames
2011/04/14 21:59:05
Document that if shell is True then we expect a st
Peter Mayo
2011/04/19 03:59:39
Done.
| |
63 env: If non-None, this is the environment for the new process. | 66 env: If non-None, this is the environment for the new process. |
davidjames
2011/04/14 21:59:05
Document that this is not compatible with enter_ch
Peter Mayo
2011/04/19 03:59:39
It's not incompatible, just mostly useless - docum
| |
67 extra_env: If set, this is added to the environment for the new process. | |
64 ignore_sigint: If True, we'll ignore signal.SIGINT before calling the | 68 ignore_sigint: If True, we'll ignore signal.SIGINT before calling the |
65 child. This is the desired behavior if we know our child will handle | 69 child. This is the desired behavior if we know our child will handle |
66 Ctrl-C. If we don't do this, I think we and the child will both get | 70 Ctrl-C. If we don't do this, I think we and the child will both get |
67 Ctrl-C at the same time, which means we'll forcefully kill the child. | 71 Ctrl-C at the same time, which means we'll forcefully kill the child. |
68 combine_stdout_stderr: Combines stdout and stdin streams into stdout. | 72 combine_stdout_stderr: Combines stdout and stdin streams into stdout. |
69 | 73 |
70 Returns: | 74 Returns: |
71 A CommandResult object. | 75 A CommandResult object. |
72 | 76 |
73 Raises: | 77 Raises: |
74 Exception: Raises generic exception on error with optional error_message. | 78 Exception: Raises generic exception on error with optional error_message. |
75 """ | 79 """ |
76 # Set default for variables. | 80 # Set default for variables. |
77 stdout = None | 81 stdout = None |
78 stderr = None | 82 stderr = None |
79 stdin = None | 83 stdin = None |
80 cmd_result = CommandResult() | 84 cmd_result = CommandResult() |
81 | 85 |
82 # Modify defaults based on parameters. | 86 # Modify defaults based on parameters. |
83 if redirect_stdout: stdout = subprocess.PIPE | 87 if redirect_stdout: stdout = subprocess.PIPE |
84 if redirect_stderr: stderr = subprocess.PIPE | 88 if redirect_stderr: stderr = subprocess.PIPE |
85 if combine_stdout_stderr: stderr = subprocess.STDOUT | 89 if combine_stdout_stderr: stderr = subprocess.STDOUT |
86 # TODO(sosa): gpylint complains about redefining built-in 'input'. | 90 # TODO(sosa): gpylint complains about redefining built-in 'input'. |
87 # Can we rename this variable? | 91 # Can we rename this variable? |
88 if input: stdin = subprocess.PIPE | 92 if input: stdin = subprocess.PIPE |
89 if isinstance(cmd, basestring): | 93 |
90 if enter_chroot: cmd = './enter_chroot.sh -- ' + cmd | 94 if isinstance(cmd, basestring) or shell: |
davidjames
2011/04/14 21:59:05
Can we report errors when the shell variable is no
Peter Mayo
2011/04/19 03:59:39
Done.
| |
91 cmd_str = cmd | 95 cmd = ['sh', '-c', cmd] |
sosa
2011/04/14 21:22:18
Does this work for piped commands?
davidjames
2011/04/14 21:59:05
It should work. We should probably use /bin/sh for
Peter Mayo
2011/04/19 03:59:39
Done. But I didn't change the isinstance that way
| |
92 else: | 96 shell = False |
93 if enter_chroot: cmd = ['./enter_chroot.sh', '--'] + cmd | 97 |
94 cmd_str = ' '.join(cmd) | 98 # If we are using enter_chroot we need to use enterchroot pass env through |
99 # to the final command. | |
100 if enter_chroot: | |
101 cmd = ['./enter_chroot.sh', '--'] + cmd | |
102 if extra_env: | |
sosa
2011/04/14 21:22:18
So env is incompatible with extra_env ... should t
davidjames
2011/04/14 21:59:05
env is just plain ignored in enter_chroot mode. Ye
Peter Mayo
2011/04/19 03:59:39
I don't think so ... I have documented the probabl
| |
103 for (key, value) in extra_env.items(): | |
104 cmd.insert(1, '%s=%s' % (key, value)) | |
105 elif extra_env: | |
106 if env is not None: | |
sosa
2011/04/14 21:22:18
if env:
davidjames
2011/04/14 21:59:05
What if env is the empty array? It's useful to be
Peter Mayo
2011/04/19 03:59:39
I agree with davidjames here.
| |
107 env = env.copy() | |
108 else: | |
109 env = os.environ.copy() | |
sosa
2011/04/14 21:22:18
Add extra line
Peter Mayo
2011/04/19 03:59:39
OK, Done... it reads worse to my eye the new way
| |
110 env.update(extra_env) | |
95 | 111 |
96 # Print out the command before running. | 112 # Print out the command before running. |
97 if print_cmd: | 113 if print_cmd: |
98 if cwd: | 114 if cwd: |
99 Info('RunCommand: %s in %s' % (cmd_str, cwd)) | 115 Info('RunCommand: %r in %s' % (cmd, cwd)) |
100 else: | 116 else: |
101 Info('RunCommand: %s' % cmd_str) | 117 Info('RunCommand: %r' % cmd) |
102 cmd_result.cmd = cmd | 118 cmd_result.cmd = cmd |
103 | 119 |
104 try: | 120 try: |
105 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin, stdout=stdout, | 121 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin, stdout=stdout, |
106 stderr=stderr, shell=shell, env=env) | 122 stderr=stderr, shell=False, env=env) |
107 if ignore_sigint: | 123 if ignore_sigint: |
108 old_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN) | 124 old_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN) |
109 try: | 125 try: |
110 (cmd_result.output, cmd_result.error) = proc.communicate(input) | 126 (cmd_result.output, cmd_result.error) = proc.communicate(input) |
111 finally: | 127 finally: |
112 if ignore_sigint: | 128 if ignore_sigint: |
113 signal.signal(signal.SIGINT, old_sigint) | 129 signal.signal(signal.SIGINT, old_sigint) |
114 | 130 |
115 if exit_code: | 131 if exit_code: |
116 cmd_result.returncode = proc.returncode | 132 cmd_result.returncode = proc.returncode |
117 | 133 |
118 if not error_ok and proc.returncode: | 134 if not error_ok and proc.returncode: |
119 msg = ('Command "%s" failed.\n' % cmd_str + | 135 msg = ('Command "%r" failed.\n' % cmd + |
120 (error_message or cmd_result.error or cmd_result.output or '')) | 136 (error_message or cmd_result.error or cmd_result.output or '')) |
121 raise RunCommandError(msg, cmd) | 137 raise RunCommandError(msg, cmd) |
122 # TODO(sosa): is it possible not to use the catch-all Exception here? | 138 # TODO(sosa): is it possible not to use the catch-all Exception here? |
123 except Exception, e: | 139 except Exception, e: |
124 if not error_ok: | 140 if not error_ok: |
125 raise | 141 raise |
126 else: | 142 else: |
127 Warning(str(e)) | 143 Warning(str(e)) |
128 | 144 |
129 return cmd_result | 145 return cmd_result |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 except RunCommandException as e: | 393 except RunCommandException as e: |
378 if not error_ok and retry_count == num_retries: | 394 if not error_ok and retry_count == num_retries: |
379 raise e | 395 raise e |
380 else: | 396 else: |
381 Warning(str(e)) | 397 Warning(str(e)) |
382 if print_cmd: | 398 if print_cmd: |
383 Info('PROGRAM(%s) -> RunCommand: retrying %r in dir %s' % | 399 Info('PROGRAM(%s) -> RunCommand: retrying %r in dir %s' % |
384 (GetCallerName(), cmd, cwd)) | 400 (GetCallerName(), cmd, cwd)) |
385 | 401 |
386 return output | 402 return output |
OLD | NEW |