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 signal | 10 import signal |
11 import subprocess | 11 import subprocess |
(...skipping 24 matching lines...) Expand all Loading... | |
36 return (type(self) == type(other) and | 36 return (type(self) == type(other) and |
37 str(self) == str(other) and | 37 str(self) == str(other) and |
38 self.cmd == other.cmd) | 38 self.cmd == other.cmd) |
39 | 39 |
40 def __ne__(self, other): | 40 def __ne__(self, other): |
41 return not self.__eq__(other) | 41 return not self.__eq__(other) |
42 | 42 |
43 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None, | 43 def RunCommand(cmd, print_cmd=True, error_ok=False, error_message=None, |
44 exit_code=False, redirect_stdout=False, redirect_stderr=False, | 44 exit_code=False, redirect_stdout=False, redirect_stderr=False, |
45 cwd=None, input=None, enter_chroot=False, shell=False, | 45 cwd=None, input=None, enter_chroot=False, shell=False, |
46 env=None, ignore_sigint=False, combine_stdout_stderr=False): | 46 env=None, extra_env=None, ignore_sigint=False, |
47 combine_stdout_stderr=False): | |
47 """Runs a command. | 48 """Runs a command. |
48 | 49 |
49 Args: | 50 Args: |
50 cmd: cmd to run. Should be input to subprocess.Popen. | 51 cmd: cmd to run. Should be input to subprocess.Popen. If a string, shell |
52 must be true, and it will be passed to one, otherwise the command is | |
davidjames
2011/04/19 06:38:59
Run-on sentence. The phrase "and it will be passed
Peter Mayo
2011/04/19 17:43:17
Done.
| |
53 an array of arguments, and shell must be false. | |
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. Shell must also be false, and |
davidjames
2011/04/19 06:38:59
Looks like this implementation works now if enter_
Peter Mayo
2011/04/19 17:43:17
Done.
| |
61 shell: If shell is True, the specified command will be executed through | 64 the cmd must be an array. |
62 the shell. | 65 shell: Controls whether we add a shell as a command interpreter. See cmd |
63 env: If non-None, this is the environment for the new process. | 66 since it has to agree as to the type. |
67 env: If non-None, this is the environment for the new process. If | |
68 enter_chroot is true then this is the environment of the enter_chroot, | |
69 most of which gets removed from the cmd run. | |
davidjames
2011/04/19 06:38:59
These are removed by sudo itself thanks to the env
Peter Mayo
2011/04/19 17:43:17
I think that baking in any more of the implementat
| |
70 extra_env: If set, this is added to the environment for the new process. | |
davidjames
2011/04/19 06:38:59
Unlike env, these variables are explicitly whiteli
Peter Mayo
2011/04/19 17:43:17
I meant to comment that, as well as the assymetry
| |
64 ignore_sigint: If True, we'll ignore signal.SIGINT before calling the | 71 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 | 72 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 | 73 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. | 74 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. | 75 combine_stdout_stderr: Combines stdout and stdin streams into stdout. |
69 | 76 |
70 Returns: | 77 Returns: |
71 A CommandResult object. | 78 A CommandResult object. |
72 | 79 |
73 Raises: | 80 Raises: |
74 Exception: Raises generic exception on error with optional error_message. | 81 Exception: Raises generic exception on error with optional error_message. |
75 """ | 82 """ |
76 # Set default for variables. | 83 # Set default for variables. |
77 stdout = None | 84 stdout = None |
78 stderr = None | 85 stderr = None |
79 stdin = None | 86 stdin = None |
80 cmd_result = CommandResult() | 87 cmd_result = CommandResult() |
81 | 88 |
82 # Modify defaults based on parameters. | 89 # Modify defaults based on parameters. |
83 if redirect_stdout: stdout = subprocess.PIPE | 90 if redirect_stdout: stdout = subprocess.PIPE |
84 if redirect_stderr: stderr = subprocess.PIPE | 91 if redirect_stderr: stderr = subprocess.PIPE |
85 if combine_stdout_stderr: stderr = subprocess.STDOUT | 92 if combine_stdout_stderr: stderr = subprocess.STDOUT |
86 # TODO(sosa): gpylint complains about redefining built-in 'input'. | 93 # TODO(sosa): gpylint complains about redefining built-in 'input'. |
87 # Can we rename this variable? | 94 # Can we rename this variable? |
88 if input: stdin = subprocess.PIPE | 95 if input: stdin = subprocess.PIPE |
96 | |
89 if isinstance(cmd, basestring): | 97 if isinstance(cmd, basestring): |
90 if enter_chroot: cmd = './enter_chroot.sh -- ' + cmd | 98 if not shell: |
91 cmd_str = cmd | 99 raise Exception(msg="Can not run a string command without a shell") |
davidjames
2011/04/19 06:38:59
s/Can not/Cannot/
s/"/'/g
Peter Mayo
2011/04/19 17:43:17
Done.
Peter Mayo
2011/04/19 17:43:17
Done.
| |
92 else: | 100 cmd = ['/bin/sh', '-c', cmd] |
93 if enter_chroot: cmd = ['./enter_chroot.sh', '--'] + cmd | 101 shell = False |
94 cmd_str = ' '.join(cmd) | 102 elif shell: |
103 raise Exception(msg="Can not run an array command with a shell") | |
davidjames
2011/04/19 06:38:59
Same here.
Peter Mayo
2011/04/19 17:43:17
Done.
| |
104 | |
105 # If we are using enter_chroot we need to use enterchroot pass env through | |
106 # to the final command. | |
107 if enter_chroot: | |
108 cmd = ['./enter_chroot.sh', '--'] + cmd | |
109 if extra_env: | |
110 for (key, value) in extra_env.items(): | |
111 cmd.insert(1, '%s=%s' % (key, value)) | |
112 elif extra_env: | |
113 if env is not None: | |
114 env = env.copy() | |
115 else: | |
116 env = os.environ.copy() | |
117 | |
118 env.update(extra_env) | |
95 | 119 |
96 # Print out the command before running. | 120 # Print out the command before running. |
97 if print_cmd: | 121 if print_cmd: |
98 if cwd: | 122 if cwd: |
99 Info('RunCommand: %s in %s' % (cmd_str, cwd)) | 123 Info('RunCommand: %r in %s' % (cmd, cwd)) |
100 else: | 124 else: |
101 Info('RunCommand: %s' % cmd_str) | 125 Info('RunCommand: %r' % cmd) |
102 cmd_result.cmd = cmd | 126 cmd_result.cmd = cmd |
103 | 127 |
104 try: | 128 try: |
105 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin, stdout=stdout, | 129 proc = subprocess.Popen(cmd, cwd=cwd, stdin=stdin, stdout=stdout, |
106 stderr=stderr, shell=shell, env=env) | 130 stderr=stderr, shell=False, env=env) |
107 if ignore_sigint: | 131 if ignore_sigint: |
108 old_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN) | 132 old_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN) |
109 try: | 133 try: |
110 (cmd_result.output, cmd_result.error) = proc.communicate(input) | 134 (cmd_result.output, cmd_result.error) = proc.communicate(input) |
111 finally: | 135 finally: |
112 if ignore_sigint: | 136 if ignore_sigint: |
113 signal.signal(signal.SIGINT, old_sigint) | 137 signal.signal(signal.SIGINT, old_sigint) |
114 | 138 |
115 if exit_code: | 139 if exit_code: |
116 cmd_result.returncode = proc.returncode | 140 cmd_result.returncode = proc.returncode |
117 | 141 |
118 if not error_ok and proc.returncode: | 142 if not error_ok and proc.returncode: |
119 msg = ('Command "%s" failed.\n' % cmd_str + | 143 msg = ('Command "%r" failed.\n' % cmd + |
120 (error_message or cmd_result.error or cmd_result.output or '')) | 144 (error_message or cmd_result.error or cmd_result.output or '')) |
121 raise RunCommandError(msg, cmd) | 145 raise RunCommandError(msg, cmd) |
122 # TODO(sosa): is it possible not to use the catch-all Exception here? | 146 # TODO(sosa): is it possible not to use the catch-all Exception here? |
123 except Exception, e: | 147 except Exception, e: |
124 if not error_ok: | 148 if not error_ok: |
125 raise | 149 raise |
126 else: | 150 else: |
127 Warning(str(e)) | 151 Warning(str(e)) |
128 | 152 |
129 return cmd_result | 153 return cmd_result |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 except RunCommandException as e: | 401 except RunCommandException as e: |
378 if not error_ok and retry_count == num_retries: | 402 if not error_ok and retry_count == num_retries: |
379 raise e | 403 raise e |
380 else: | 404 else: |
381 Warning(str(e)) | 405 Warning(str(e)) |
382 if print_cmd: | 406 if print_cmd: |
383 Info('PROGRAM(%s) -> RunCommand: retrying %r in dir %s' % | 407 Info('PROGRAM(%s) -> RunCommand: retrying %r in dir %s' % |
384 (GetCallerName(), cmd, cwd)) | 408 (GetCallerName(), cmd, cwd)) |
385 | 409 |
386 return output | 410 return output |
OLD | NEW |