Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2006-2008 The Chromium 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 """Shared process-related utility functions.""" | 4 """Shared process-related utility functions.""" |
| 5 | 5 |
| 6 import errno | 6 import errno |
| 7 import os | 7 import os |
| 8 import subprocess | 8 import subprocess |
| 9 import sys | 9 import sys |
| 10 | 10 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 126 Otherwise, prints only the command's stderr to stdout. | 126 Otherwise, prints only the command's stderr to stdout. |
| 127 | 127 |
| 128 Returns: | 128 Returns: |
| 129 The process's exit status. | 129 The process's exit status. |
| 130 | 130 |
| 131 Raises: | 131 Raises: |
| 132 CommandNotFound if the command executable could not be found. | 132 CommandNotFound if the command executable could not be found. |
| 133 """ | 133 """ |
| 134 return RunCommandFull(command, verbose)[0] | 134 return RunCommandFull(command, verbose)[0] |
| 135 | 135 |
| 136 def RunCommandsInParallel(commands, verbose=True, collect_output=False, | |
| 137 print_output=True): | |
| 138 """Runs a list of commands in parallel, waits for all commands to terminate | |
| 139 and returns their status. If specified, the ouput of commands can be | |
| 140 returned and/or printed. | |
| 141 | |
| 142 Args: | |
| 143 commands: the list of commands to run, each as a list of one or more | |
| 144 strings. | |
| 145 verbose: if True, combines stdout and stderr into stdout. | |
| 146 Otherwise, prints only the command's stderr to stdout. | |
| 147 collect_output: if True, collects the output of the each command as a list | |
| 148 of lines and returns it. | |
| 149 print_output: if True, prints the output of each command. | |
| 150 | |
| 151 Returns: | |
| 152 A list of tuples consisting of each command's exit status and output. If | |
| 153 collect_output is False, the output will be []. | |
| 154 | |
| 155 Raises: | |
| 156 CommandNotFound if any of the command executables could not be found. | |
| 157 """ | |
| 158 | |
| 159 command_num = len(commands) | |
| 160 outputs = [[] for i in xrange(command_num)] | |
| 161 procs = [None for i in xrange(command_num)] | |
| 162 eofs = [False for i in xrange(command_num)] | |
| 163 | |
| 164 for command in commands: | |
| 165 print '\n' + subprocess.list2cmdline(command).replace('\\', '/') + '\n', | |
| 166 | |
| 167 if verbose: | |
| 168 out = subprocess.PIPE | |
| 169 err = subprocess.STDOUT | |
| 170 else: | |
| 171 out = file(os.devnull, 'w') | |
| 172 err = subprocess.PIPE | |
| 173 | |
| 174 for i in xrange(command_num): | |
| 175 try: | |
| 176 command = commands[i] | |
| 177 procs[i] = subprocess.Popen(command, stdout=out, stderr=err, bufsize=1) | |
| 178 except OSError, e: | |
| 179 if e.errno == errno.ENOENT: | |
| 180 raise CommandNotFound('Unable to find "%s"' % command[0]) | |
| 181 raise | |
| 182 # We could consider terminating the processes already started. | |
| 183 # But Popen.kill() is only available in version 2.6. | |
| 184 # For now the clean up is done by KillAll. | |
| 185 | |
| 186 while True: | |
| 187 eof_all = True | |
| 188 for i in xrange(command_num): | |
| 189 if eofs[i]: | |
| 190 continue | |
| 191 if verbose: | |
| 192 read_from = procs[i].stdout | |
| 193 else: | |
| 194 read_from = procs[i].stderr | |
| 195 line = read_from.readline() | |
| 196 if line: | |
| 197 eof_all = False | |
| 198 line = line.rstrip() | |
| 199 outputs[i].append(line) | |
| 200 if print_output: | |
| 201 # Windows Python converts \n to \r\n automatically whenever it | |
|
M-A Ruel
2009/07/29 22:24:46
This looks odd.
sys.stdout.write(line + '\n')
will
| |
| 202 # encounters it written to a text file (including stdout). The only | |
| 203 # way around it is to write to a binary file, which isn't feasible | |
| 204 # for stdout. So we end up with \r\n here even though we explicitly | |
| 205 # write \n. (We could write \r instead, which doesn't get converted | |
| 206 # to \r\n, but that's probably more troublesome for people trying to | |
| 207 # read the files.) | |
| 208 print line + '\n', | |
| 209 else: | |
| 210 eofs[i] = True | |
| 211 if eof_all: | |
| 212 break | |
| 213 | |
| 214 # Make sure the process terminates. | |
| 215 for i in xrange(command_num): | |
| 216 procs[i].wait() | |
| 217 | |
| 218 if not verbose: | |
| 219 out.close() | |
| 220 | |
| 221 return [(procs[i].returncode, outputs[i]) for i in xrange(command_num)] | |
| OLD | NEW |