| OLD | NEW |
| 1 # coding=utf8 | 1 # coding=utf8 |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 """Collection of subprocess wrapper functions. | 5 """Collection of subprocess wrapper functions. |
| 6 | 6 |
| 7 In theory you shouldn't need anything else in subprocess, or this module failed. | 7 In theory you shouldn't need anything else in subprocess, or this module failed. |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 from __future__ import with_statement | 10 from __future__ import with_statement |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 | 132 |
| 133 | 133 |
| 134 class Popen(subprocess.Popen): | 134 class Popen(subprocess.Popen): |
| 135 """Wraps subprocess.Popen() with various workarounds. | 135 """Wraps subprocess.Popen() with various workarounds. |
| 136 | 136 |
| 137 - Forces English output since it's easier to parse the stdout if it is always | 137 - Forces English output since it's easier to parse the stdout if it is always |
| 138 in English. | 138 in English. |
| 139 - Sets shell=True on windows by default. You can override this by forcing | 139 - Sets shell=True on windows by default. You can override this by forcing |
| 140 shell parameter to a value. | 140 shell parameter to a value. |
| 141 - Adds support for VOID to not buffer when not needed. | 141 - Adds support for VOID to not buffer when not needed. |
| 142 - Adds self.start property. |
| 142 | 143 |
| 143 Note: Popen() can throw OSError when cwd or args[0] doesn't exist. Translate | 144 Note: Popen() can throw OSError when cwd or args[0] doesn't exist. Translate |
| 144 exceptions generated by cygwin when it fails trying to emulate fork(). | 145 exceptions generated by cygwin when it fails trying to emulate fork(). |
| 145 """ | 146 """ |
| 146 def __init__(self, args, **kwargs): | 147 def __init__(self, args, **kwargs): |
| 147 # Make sure we hack subprocess if necessary. | 148 # Make sure we hack subprocess if necessary. |
| 148 hack_subprocess() | 149 hack_subprocess() |
| 149 add_kill() | 150 add_kill() |
| 150 | 151 |
| 151 env = get_english_env(kwargs.get('env')) | 152 env = get_english_env(kwargs.get('env')) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 173 # Replaces VOID with handle to /dev/null. | 174 # Replaces VOID with handle to /dev/null. |
| 174 # Create a temporary file to workaround python's deadlock. | 175 # Create a temporary file to workaround python's deadlock. |
| 175 # http://docs.python.org/library/subprocess.html#subprocess.Popen.wait | 176 # http://docs.python.org/library/subprocess.html#subprocess.Popen.wait |
| 176 # When the pipe fills up, it will deadlock this process. Using a real | 177 # When the pipe fills up, it will deadlock this process. Using a real |
| 177 # file works around that issue. | 178 # file works around that issue. |
| 178 kwargs[stream] = open(os.devnull, 'w') | 179 kwargs[stream] = open(os.devnull, 'w') |
| 179 | 180 |
| 180 fix('stdout') | 181 fix('stdout') |
| 181 fix('stderr') | 182 fix('stderr') |
| 182 | 183 |
| 184 self.start = time.time() |
| 185 |
| 183 try: | 186 try: |
| 184 super(Popen, self).__init__(args, **kwargs) | 187 super(Popen, self).__init__(args, **kwargs) |
| 185 except OSError, e: | 188 except OSError, e: |
| 186 if e.errno == errno.EAGAIN and sys.platform == 'cygwin': | 189 if e.errno == errno.EAGAIN and sys.platform == 'cygwin': |
| 187 # Convert fork() emulation failure into a CygwinRebaseError(). | 190 # Convert fork() emulation failure into a CygwinRebaseError(). |
| 188 raise CygwinRebaseError( | 191 raise CygwinRebaseError( |
| 189 e.errno, | 192 e.errno, |
| 190 args, | 193 args, |
| 191 kwargs.get('cwd'), | 194 kwargs.get('cwd'), |
| 192 None, | 195 None, |
| 193 'Visit ' | 196 'Visit ' |
| 194 'http://code.google.com/p/chromium/wiki/CygwinDllRemappingFailure ' | 197 'http://code.google.com/p/chromium/wiki/CygwinDllRemappingFailure ' |
| 195 'to learn how to fix this error; you need to rebase your cygwin ' | 198 'to learn how to fix this error; you need to rebase your cygwin ' |
| 196 'dlls') | 199 'dlls') |
| 197 # Popen() can throw OSError when cwd or args[0] doesn't exist. Let it go | 200 # Popen() can throw OSError when cwd or args[0] doesn't exist. Let it go |
| 198 # through | 201 # through |
| 199 raise | 202 raise |
| 200 | 203 |
| 201 | 204 |
| 202 def communicate(args, timeout=None, **kwargs): | 205 def communicate(args, timeout=None, **kwargs): |
| 203 """Wraps subprocess.Popen().communicate(). | 206 """Wraps subprocess.Popen().communicate() and add timeout support. |
| 204 | 207 |
| 205 Returns ((stdout, stderr), returncode). | 208 Returns ((stdout, stderr), returncode). |
| 206 | 209 |
| 207 - The process will be killed after |timeout| seconds and returncode set to | 210 - The process will be killed after |timeout| seconds and returncode set to |
| 208 TIMED_OUT. | 211 TIMED_OUT. |
| 209 - Automatically passes stdin content as input so do not specify stdin=PIPE. | 212 - Automatically passes stdin content as input so do not specify stdin=PIPE. |
| 210 """ | 213 """ |
| 211 stdin = kwargs.pop('stdin', None) | 214 stdin = kwargs.pop('stdin', None) |
| 212 if stdin is not None: | 215 if stdin is not None: |
| 213 if stdin is VOID: | 216 if stdin is VOID: |
| (...skipping 11 matching lines...) Expand all Loading... |
| 225 if stdin is not None: | 228 if stdin is not None: |
| 226 return proc.communicate(stdin), proc.returncode | 229 return proc.communicate(stdin), proc.returncode |
| 227 else: | 230 else: |
| 228 return proc.communicate(), proc.returncode | 231 return proc.communicate(), proc.returncode |
| 229 | 232 |
| 230 # Create a temporary file to workaround python's deadlock. | 233 # Create a temporary file to workaround python's deadlock. |
| 231 # http://docs.python.org/library/subprocess.html#subprocess.Popen.wait | 234 # http://docs.python.org/library/subprocess.html#subprocess.Popen.wait |
| 232 # When the pipe fills up, it will deadlock this process. Using a real file | 235 # When the pipe fills up, it will deadlock this process. Using a real file |
| 233 # works around that issue. | 236 # works around that issue. |
| 234 with tempfile.TemporaryFile() as buff: | 237 with tempfile.TemporaryFile() as buff: |
| 235 start = time.time() | |
| 236 kwargs['stdout'] = buff | 238 kwargs['stdout'] = buff |
| 237 proc = Popen(args, **kwargs) | 239 proc = Popen(args, **kwargs) |
| 238 if stdin is not None: | 240 if stdin is not None: |
| 239 proc.stdin.write(stdin) | 241 proc.stdin.write(stdin) |
| 240 while proc.returncode is None: | 242 while proc.returncode is None: |
| 241 proc.poll() | 243 proc.poll() |
| 242 if timeout and (time.time() - start) > timeout: | 244 if timeout and (time.time() - proc.start) > timeout: |
| 243 proc.kill() | 245 proc.kill() |
| 244 proc.wait() | 246 proc.wait() |
| 245 # It's -9 on linux and 1 on Windows. Standardize to TIMED_OUT. | 247 # It's -9 on linux and 1 on Windows. Standardize to TIMED_OUT. |
| 246 proc.returncode = TIMED_OUT | 248 proc.returncode = TIMED_OUT |
| 247 time.sleep(0.001) | 249 time.sleep(0.001) |
| 248 # Now that the process died, reset the cursor and read the file. | 250 # Now that the process died, reset the cursor and read the file. |
| 249 buff.seek(0) | 251 buff.seek(0) |
| 250 out = (buff.read(), None) | 252 out = (buff.read(), None) |
| 251 return out, proc.returncode | 253 return out, proc.returncode |
| 252 | 254 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 | 304 |
| 303 Captures stdout of a process call and returns stdout only. | 305 Captures stdout of a process call and returns stdout only. |
| 304 | 306 |
| 305 - Throws if return code is not 0. | 307 - Throws if return code is not 0. |
| 306 - Works even prior to python 2.7. | 308 - Works even prior to python 2.7. |
| 307 - Blocks stdin by default if not specified since no output will be visible. | 309 - Blocks stdin by default if not specified since no output will be visible. |
| 308 - As per doc, "The stdout argument is not allowed as it is used internally." | 310 - As per doc, "The stdout argument is not allowed as it is used internally." |
| 309 """ | 311 """ |
| 310 kwargs.setdefault('stdin', VOID) | 312 kwargs.setdefault('stdin', VOID) |
| 311 return check_call_out(args, stdout=PIPE, **kwargs)[0] | 313 return check_call_out(args, stdout=PIPE, **kwargs)[0] |
| OLD | NEW |