blob: 430010c144afd6e3798fd1e8bd7b22cf94374d6b [file] [log] [blame]
maruel@chromium.org4860f052011-03-25 20:34:38 +00001# coding=utf8
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
4# found in the LICENSE file.
5"""Collection of subprocess wrapper functions.
6
7In theory you shouldn't need anything else in subprocess, or this module failed.
8"""
9
maruel@chromium.org45d8db02011-03-31 20:43:56 +000010from __future__ import with_statement
maruel@chromium.org65be6f62011-11-09 13:57:57 +000011import cStringIO
maruel@chromium.org1d9f6292011-04-07 14:15:36 +000012import errno
maruel@chromium.org4860f052011-03-25 20:34:38 +000013import logging
14import os
maruel@chromium.org65be6f62011-11-09 13:57:57 +000015import Queue
maruel@chromium.orgfefff182011-11-09 19:30:57 +000016import select
maruel@chromium.org4860f052011-03-25 20:34:38 +000017import subprocess
18import sys
maruel@chromium.org4860f052011-03-25 20:34:38 +000019import time
20import threading
21
maruel@chromium.orgfefff182011-11-09 19:30:57 +000022if sys.platform != 'win32':
23 import fcntl
24
25
maruel@chromium.org4860f052011-03-25 20:34:38 +000026# Constants forwarded from subprocess.
27PIPE = subprocess.PIPE
28STDOUT = subprocess.STDOUT
maruel@chromium.org421982f2011-04-01 17:38:06 +000029# Sends stdout or stderr to os.devnull.
maruel@chromium.org0d5ef242011-04-18 13:52:58 +000030VOID = object()
maruel@chromium.org1d9f6292011-04-07 14:15:36 +000031# Error code when a process was killed because it timed out.
32TIMED_OUT = -2001
maruel@chromium.org4860f052011-03-25 20:34:38 +000033
34# Globals.
35# Set to True if you somehow need to disable this hack.
36SUBPROCESS_CLEANUP_HACKED = False
37
38
39class CalledProcessError(subprocess.CalledProcessError):
40 """Augment the standard exception with more data."""
41 def __init__(self, returncode, cmd, cwd, stdout, stderr):
42 super(CalledProcessError, self).__init__(returncode, cmd)
43 self.stdout = stdout
44 self.stderr = stderr
45 self.cwd = cwd
46
47 def __str__(self):
48 out = 'Command %s returned non-zero exit status %s' % (
49 ' '.join(self.cmd), self.returncode)
50 if self.cwd:
51 out += ' in ' + self.cwd
52 return '\n'.join(filter(None, (out, self.stdout, self.stderr)))
53
54
maruel@chromium.org1d9f6292011-04-07 14:15:36 +000055class CygwinRebaseError(CalledProcessError):
56 """Occurs when cygwin's fork() emulation fails due to rebased dll."""
57
58
maruel@chromium.orgfb3d3242011-04-01 14:03:08 +000059## Utility functions
60
61
62def kill_pid(pid):
63 """Kills a process by its process id."""
64 try:
65 # Unable to import 'module'
maruel@chromium.orgc98c0c52011-04-06 13:39:43 +000066 # pylint: disable=E1101,F0401
maruel@chromium.orgfb3d3242011-04-01 14:03:08 +000067 import signal
68 return os.kill(pid, signal.SIGKILL)
69 except ImportError:
70 pass
71
72
73def kill_win(process):
74 """Kills a process with its windows handle.
75
76 Has no effect on other platforms.
77 """
78 try:
79 # Unable to import 'module'
80 # pylint: disable=F0401
81 import win32process
82 # Access to a protected member _handle of a client class
83 # pylint: disable=W0212
84 return win32process.TerminateProcess(process._handle, -1)
85 except ImportError:
86 pass
87
88
89def add_kill():
90 """Adds kill() method to subprocess.Popen for python <2.6"""
91 if hasattr(subprocess.Popen, 'kill'):
92 return
93
94 if sys.platform == 'win32':
95 subprocess.Popen.kill = kill_win
96 else:
97 subprocess.Popen.kill = lambda process: kill_pid(process.pid)
98
99
maruel@chromium.org4860f052011-03-25 20:34:38 +0000100def hack_subprocess():
101 """subprocess functions may throw exceptions when used in multiple threads.
102
103 See http://bugs.python.org/issue1731717 for more information.
104 """
105 global SUBPROCESS_CLEANUP_HACKED
106 if not SUBPROCESS_CLEANUP_HACKED and threading.activeCount() != 1:
107 # Only hack if there is ever multiple threads.
108 # There is no point to leak with only one thread.
109 subprocess._cleanup = lambda: None
110 SUBPROCESS_CLEANUP_HACKED = True
111
112
113def get_english_env(env):
114 """Forces LANG and/or LANGUAGE to be English.
115
116 Forces encoding to utf-8 for subprocesses.
117
118 Returns None if it is unnecessary.
119 """
maruel@chromium.orgc98c0c52011-04-06 13:39:43 +0000120 if sys.platform == 'win32':
121 return None
maruel@chromium.org4860f052011-03-25 20:34:38 +0000122 env = env or os.environ
123
124 # Test if it is necessary at all.
125 is_english = lambda name: env.get(name, 'en').startswith('en')
126
127 if is_english('LANG') and is_english('LANGUAGE'):
128 return None
129
130 # Requires modifications.
131 env = env.copy()
132 def fix_lang(name):
133 if not is_english(name):
134 env[name] = 'en_US.UTF-8'
135 fix_lang('LANG')
136 fix_lang('LANGUAGE')
137 return env
138
139
140def Popen(args, **kwargs):
maruel@chromium.org57bf78d2011-09-08 18:57:33 +0000141 """Wraps subprocess.Popen() with various workarounds.
maruel@chromium.org4860f052011-03-25 20:34:38 +0000142
maruel@chromium.org421982f2011-04-01 17:38:06 +0000143 Returns a subprocess.Popen object.
maruel@chromium.org4860f052011-03-25 20:34:38 +0000144
maruel@chromium.org421982f2011-04-01 17:38:06 +0000145 - Forces English output since it's easier to parse the stdout if it is always
146 in English.
147 - Sets shell=True on windows by default. You can override this by forcing
148 shell parameter to a value.
149 - Adds support for VOID to not buffer when not needed.
maruel@chromium.org4860f052011-03-25 20:34:38 +0000150
maruel@chromium.org57bf78d2011-09-08 18:57:33 +0000151 Note: Popen() can throw OSError when cwd or args[0] doesn't exist. Translate
152 exceptions generated by cygwin when it fails trying to emulate fork().
maruel@chromium.org4860f052011-03-25 20:34:38 +0000153 """
154 # Make sure we hack subprocess if necessary.
155 hack_subprocess()
maruel@chromium.orgfb3d3242011-04-01 14:03:08 +0000156 add_kill()
maruel@chromium.org4860f052011-03-25 20:34:38 +0000157
158 env = get_english_env(kwargs.get('env'))
159 if env:
160 kwargs['env'] = env
maruel@chromium.orgf08b09c2011-04-06 13:14:27 +0000161 if kwargs.get('shell') is None:
maruel@chromium.org4860f052011-03-25 20:34:38 +0000162 # *Sigh*: Windows needs shell=True, or else it won't search %PATH% for the
163 # executable, but shell=True makes subprocess on Linux fail when it's called
164 # with a list because it only tries to execute the first item in the list.
maruel@chromium.orgf08b09c2011-04-06 13:14:27 +0000165 kwargs['shell'] = bool(sys.platform=='win32')
maruel@chromium.org4860f052011-03-25 20:34:38 +0000166
maruel@chromium.org55156552011-10-21 12:48:25 +0000167 if isinstance(args, basestring):
168 tmp_str = args
169 elif isinstance(args, (list, tuple)):
170 tmp_str = ' '.join(args)
171 else:
172 raise CalledProcessError(None, args, kwargs.get('cwd'), None, None)
maruel@chromium.org4860f052011-03-25 20:34:38 +0000173 if kwargs.get('cwd', None):
174 tmp_str += '; cwd=%s' % kwargs['cwd']
175 logging.debug(tmp_str)
maruel@chromium.org421982f2011-04-01 17:38:06 +0000176
maruel@chromium.org1d9f6292011-04-07 14:15:36 +0000177 def fix(stream):
178 if kwargs.get(stream) in (VOID, os.devnull):
179 # Replaces VOID with handle to /dev/null.
180 # Create a temporary file to workaround python's deadlock.
181 # http://docs.python.org/library/subprocess.html#subprocess.Popen.wait
182 # When the pipe fills up, it will deadlock this process. Using a real file
183 # works around that issue.
184 kwargs[stream] = open(os.devnull, 'w')
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000185 if callable(kwargs.get(stream)):
186 # Callable stdout/stderr should be used only with call() wrappers.
187 kwargs[stream] = PIPE
maruel@chromium.org1d9f6292011-04-07 14:15:36 +0000188
189 fix('stdout')
190 fix('stderr')
191
192 try:
193 return subprocess.Popen(args, **kwargs)
194 except OSError, e:
195 if e.errno == errno.EAGAIN and sys.platform == 'cygwin':
196 # Convert fork() emulation failure into a CygwinRebaseError().
197 raise CygwinRebaseError(
198 e.errno,
199 args,
200 kwargs.get('cwd'),
201 None,
202 'Visit '
203 'http://code.google.com/p/chromium/wiki/CygwinDllRemappingFailure to '
204 'learn how to fix this error; you need to rebase your cygwin dlls')
205 # Popen() can throw OSError when cwd or args[0] doesn't exist. Let it go
206 # through
207 raise
maruel@chromium.org4860f052011-03-25 20:34:38 +0000208
209
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000210def _queue_pipe_read(pipe, name, done, dest):
maruel@chromium.orgfefff182011-11-09 19:30:57 +0000211 """Queues characters read from a pipe into a queue.
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000212
213 Left outside the _tee_threads function to not introduce a function closure
214 to speed up variable lookup.
215 """
216 while not done.isSet():
217 data = pipe.read(1)
218 if not data:
219 break
220 dest.put((name, data))
221 dest.put(name)
222
223
224def _tee_threads(proc, timeout, start, stdin, args, kwargs):
225 """Does I/O for a process's pipes using thread.
226
227 It's the simplest and slowest implementation. Expect very slow behavior.
228
229 If there is a callback and it doesn't keep up with the calls, the timeout
230 effectiveness will be delayed accordingly.
231 """
232 # TODO(maruel): Implement a select based implementation on POSIX and a Windows
233 # one using WaitForMultipleObjects().
234 #
235 # Queue of either of <threadname> when done or (<threadname>, data).
236 # In theory we would like to limit to ~64kb items to not cause large memory
237 # usage when the callback blocks. It is not done because it slows down
238 # processing on OSX10.6 by a factor of 2x, making it even slower than Windows!
239 # Revisit this decision if it becomes a problem, e.g. crash because of
240 # memory exhaustion.
241 queue = Queue.Queue()
242 done = threading.Event()
243
244 def write_stdin():
245 stdin_io = cStringIO.StringIO(stdin)
246 while not done.isSet():
247 data = stdin_io.read(1024)
248 if data:
249 proc.stdin.write(data)
250 else:
251 proc.stdin.close()
252 break
253 queue.put('stdin')
254
255 def timeout_fn():
256 done.wait(timeout)
257 # No need to close the pipes since killing should be sufficient.
258 queue.put('timeout')
259
260 # Starts up to 4 threads:
261 # Read stdout
262 # Read stderr
263 # Write stdin
264 # Timeout
265 threads = {}
266 if timeout is not None:
267 threads['timeout'] = threading.Thread(target=timeout_fn)
268 if callable(kwargs.get('stdout')):
269 threads['stdout'] = threading.Thread(
270 target=_queue_pipe_read, args=(proc.stdout, 'stdout', done, queue))
271 if callable(kwargs.get('stderr')):
272 threads['stderr'] = threading.Thread(
273 target=_queue_pipe_read,
274 args=(proc.stderr, 'stderr', done, queue))
275 if isinstance(stdin, str):
276 threads['stdin'] = threading.Thread(target=write_stdin)
277 for t in threads.itervalues():
278 t.daemon = True
279 t.start()
280
281 timed_out = False
282 try:
283 while proc.returncode is None:
284 assert threads
285 proc.poll()
286 item = queue.get()
287 if isinstance(item, str):
288 threads[item].join()
289 del threads[item]
290 if item == 'timeout' and not timed_out and proc.poll() is None:
291 logging.debug('Timed out: killing')
292 proc.kill()
293 timed_out = True
294 if not threads:
295 # We won't be waken up anymore. Need to busy loop.
296 break
297 else:
298 kwargs[item[0]](item[1])
299 finally:
300 # Stop the threads.
301 done.set()
302 # Join threads
303 for thread in threads.itervalues():
304 thread.join()
305
306 # Flush the queue.
307 try:
308 while True:
309 item = queue.get(False)
310 if isinstance(item, str):
311 if item == 'timeout':
312 # TODO(maruel): Does it make sense at that point?
313 if not timed_out and proc.poll() is None:
314 logging.debug('Timed out: killing')
315 proc.kill()
316 timed_out = True
317 else:
318 kwargs[item[0]](item[1])
319 except Queue.Empty:
320 pass
321
322 # Get the remainder.
323 if callable(kwargs.get('stdout')):
324 data = proc.stdout.read()
325 while data:
326 kwargs['stdout'](data)
327 data = proc.stdout.read()
328 if callable(kwargs.get('stderr')):
329 data = proc.stderr.read()
330 while data:
331 kwargs['stderr'](data)
332 data = proc.stderr.read()
333
334 if proc.returncode is None:
335 # Usually happens when killed with timeout but not listening to pipes.
336 proc.wait()
337
338 if timed_out:
339 return TIMED_OUT
340
341 return proc.returncode
342
343
maruel@chromium.orgfefff182011-11-09 19:30:57 +0000344def _read_pipe(handles, pipe, out_fn):
345 """Reads bytes from a pipe and calls the output callback."""
346 data = pipe.read()
347 if not data:
348 del handles[pipe]
349 else:
350 out_fn(data)
351
352
353def _tee_posix(proc, timeout, start, stdin, args, kwargs):
354 """Polls a process and its pipe using select.select().
355
356 TODO(maruel): Implement a non-polling method for OSes that support it.
357 """
358 handles_r = {}
359 if callable(kwargs.get('stdout')):
360 handles_r[proc.stdout] = lambda: _read_pipe(
361 handles_r, proc.stdout, kwargs['stdout'])
362 if callable(kwargs.get('stderr')):
363 handles_r[proc.stderr] = lambda: _read_pipe(
364 handles_r, proc.stderr, kwargs['stderr'])
365
366 handles_w = {}
367 if isinstance(stdin, str):
368 stdin_io = cStringIO.StringIO(stdin)
369 def write_stdin():
370 data = stdin_io.read(1)
371 if data:
372 proc.stdin.write(data)
373 else:
374 del handles_w[proc.stdin]
375 proc.stdin.close()
376 handles_w[proc.stdin] = write_stdin
377 else:
378 # TODO(maruel): Fix me, it could be VOID.
379 assert stdin is None
380
381 # Make all the file objects of the child process non-blocking file.
382 # TODO(maruel): Test if a pipe is handed to the child process.
383 for pipe in (proc.stdin, proc.stdout, proc.stderr):
384 fileno = pipe and getattr(pipe, 'fileno', lambda: None)()
385 if fileno:
386 # Note: making a pipe non-blocking means the C stdio could act wrong. In
387 # particular, readline() cannot be used. Work around is to use os.read().
388 fl = fcntl.fcntl(fileno, fcntl.F_GETFL)
389 fcntl.fcntl(fileno, fcntl.F_SETFL, fl | os.O_NONBLOCK)
390
391 timed_out = False
392 while handles_r or handles_w or (timeout and proc.poll() is None):
393 period = None
394 if timeout:
395 period = max(0, timeout - (time.time() - start))
396 if not period and not timed_out:
397 proc.kill()
398 timed_out = True
399 if timed_out:
400 period = 0.001
401
402 # It reconstructs objects on each loop, not very efficient.
403 reads, writes, _, = select.select(
404 handles_r.keys(), handles_w.keys(), [], period)
405 for read in reads:
406 handles_r[read]()
407 for write in writes:
408 handles_w[write]()
409
410 # No pipe open anymore and if there was a time out, the child process was
411 # killed already.
412 proc.wait()
413 if timed_out:
414 return TIMED_OUT
415 return proc.returncode
416
417
maruel@chromium.org1f063db2011-04-18 19:04:52 +0000418def communicate(args, timeout=None, **kwargs):
maruel@chromium.org4860f052011-03-25 20:34:38 +0000419 """Wraps subprocess.Popen().communicate().
420
maruel@chromium.org421982f2011-04-01 17:38:06 +0000421 Returns ((stdout, stderr), returncode).
maruel@chromium.org4860f052011-03-25 20:34:38 +0000422
maruel@chromium.org1d9f6292011-04-07 14:15:36 +0000423 - The process will be killed after |timeout| seconds and returncode set to
424 TIMED_OUT.
maruel@chromium.org421982f2011-04-01 17:38:06 +0000425 - Automatically passes stdin content as input so do not specify stdin=PIPE.
maruel@chromium.org4860f052011-03-25 20:34:38 +0000426 """
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000427 if timeout and kwargs.get('shell'):
428 raise TypeError(
429 'Using timeout and shell simultaneously will cause a process leak '
430 'since the shell will be killed instead of the child process.')
431
maruel@chromium.org4860f052011-03-25 20:34:38 +0000432 stdin = kwargs.pop('stdin', None)
433 if stdin is not None:
maruel@chromium.org0d5ef242011-04-18 13:52:58 +0000434 if stdin is VOID:
435 kwargs['stdin'] = open(os.devnull, 'r')
436 stdin = None
437 else:
maruel@chromium.org39f645f2011-04-21 00:07:53 +0000438 assert isinstance(stdin, basestring)
maruel@chromium.org0d5ef242011-04-18 13:52:58 +0000439 # When stdin is passed as an argument, use it as the actual input data and
440 # set the Popen() parameter accordingly.
441 kwargs['stdin'] = PIPE
maruel@chromium.org4860f052011-03-25 20:34:38 +0000442
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000443 start = time.time()
444 proc = Popen(args, **kwargs)
445 need_buffering = (timeout or
446 callable(kwargs.get('stdout')) or callable(kwargs.get('stderr')))
447
448 if not need_buffering:
maruel@chromium.org4860f052011-03-25 20:34:38 +0000449 # Normal workflow.
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000450 if stdin not in (None, VOID):
maruel@chromium.org1d9f6292011-04-07 14:15:36 +0000451 return proc.communicate(stdin), proc.returncode
maruel@chromium.org4860f052011-03-25 20:34:38 +0000452 else:
maruel@chromium.org1d9f6292011-04-07 14:15:36 +0000453 return proc.communicate(), proc.returncode
454
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000455 stdout = None
456 stderr = None
457 # Convert to a lambda to workaround python's deadlock.
maruel@chromium.org1d9f6292011-04-07 14:15:36 +0000458 # http://docs.python.org/library/subprocess.html#subprocess.Popen.wait
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000459 # When the pipe fills up, it will deadlock this process. Using a thread
460 # works around that issue. No need for thread safe function since the call
461 # backs are guaranteed to be called from the main thread.
462 if kwargs.get('stdout') == PIPE:
463 stdout = []
464 kwargs['stdout'] = stdout.append
465 if kwargs.get('stderr') == PIPE:
466 stderr = []
467 kwargs['stderr'] = stderr.append
maruel@chromium.orgfefff182011-11-09 19:30:57 +0000468 if sys.platform == 'win32':
469 # On cygwin, ctypes._FUNCFLAG_STDCALL, which is used by ctypes.WINFUNCTYPE,
470 # doesn't exist so _tee_win() cannot be used yet.
471 returncode = _tee_threads(proc, timeout, start, stdin, args, kwargs)
472 else:
473 returncode = _tee_posix(proc, timeout, start, stdin, args, kwargs)
maruel@chromium.org65be6f62011-11-09 13:57:57 +0000474 if not stdout is None:
475 stdout = ''.join(stdout)
476 if not stderr is None:
477 stderr = ''.join(stderr)
478 return (stdout, stderr), returncode
maruel@chromium.org4860f052011-03-25 20:34:38 +0000479
480
maruel@chromium.org1f063db2011-04-18 19:04:52 +0000481def call(args, **kwargs):
482 """Emulates subprocess.call().
483
484 Automatically convert stdout=PIPE or stderr=PIPE to VOID.
maruel@chromium.org87e6d332011-09-09 19:01:28 +0000485 In no case they can be returned since no code path raises
486 subprocess2.CalledProcessError.
maruel@chromium.org1f063db2011-04-18 19:04:52 +0000487 """
488 if kwargs.get('stdout') == PIPE:
489 kwargs['stdout'] = VOID
490 if kwargs.get('stderr') == PIPE:
491 kwargs['stderr'] = VOID
492 return communicate(args, **kwargs)[1]
493
494
maruel@chromium.org0bcd1d32011-04-26 15:55:49 +0000495def check_call_out(args, **kwargs):
maruel@chromium.org421982f2011-04-01 17:38:06 +0000496 """Improved version of subprocess.check_call().
maruel@chromium.org4860f052011-03-25 20:34:38 +0000497
maruel@chromium.org421982f2011-04-01 17:38:06 +0000498 Returns (stdout, stderr), unlike subprocess.check_call().
maruel@chromium.org4860f052011-03-25 20:34:38 +0000499 """
maruel@chromium.org1f063db2011-04-18 19:04:52 +0000500 out, returncode = communicate(args, **kwargs)
maruel@chromium.org4860f052011-03-25 20:34:38 +0000501 if returncode:
502 raise CalledProcessError(
503 returncode, args, kwargs.get('cwd'), out[0], out[1])
504 return out
505
506
maruel@chromium.org0bcd1d32011-04-26 15:55:49 +0000507def check_call(args, **kwargs):
508 """Emulate subprocess.check_call()."""
509 check_call_out(args, **kwargs)
510 return 0
511
512
maruel@chromium.org4860f052011-03-25 20:34:38 +0000513def capture(args, **kwargs):
514 """Captures stdout of a process call and returns it.
515
maruel@chromium.org421982f2011-04-01 17:38:06 +0000516 Returns stdout.
maruel@chromium.org4860f052011-03-25 20:34:38 +0000517
maruel@chromium.org421982f2011-04-01 17:38:06 +0000518 - Discards returncode.
maruel@chromium.org87e6d332011-09-09 19:01:28 +0000519 - Blocks stdin by default if not specified since no output will be visible.
maruel@chromium.org4860f052011-03-25 20:34:38 +0000520 """
maruel@chromium.org87e6d332011-09-09 19:01:28 +0000521 kwargs.setdefault('stdin', VOID)
522
523 # Like check_output, deny the caller from using stdout arg.
524 return communicate(args, stdout=PIPE, **kwargs)[0][0]
maruel@chromium.org4860f052011-03-25 20:34:38 +0000525
526
527def check_output(args, **kwargs):
maruel@chromium.org0bcd1d32011-04-26 15:55:49 +0000528 """Emulates subprocess.check_output().
maruel@chromium.org4860f052011-03-25 20:34:38 +0000529
maruel@chromium.org0bcd1d32011-04-26 15:55:49 +0000530 Captures stdout of a process call and returns stdout only.
maruel@chromium.org4860f052011-03-25 20:34:38 +0000531
maruel@chromium.org421982f2011-04-01 17:38:06 +0000532 - Throws if return code is not 0.
533 - Works even prior to python 2.7.
maruel@chromium.org87e6d332011-09-09 19:01:28 +0000534 - Blocks stdin by default if not specified since no output will be visible.
535 - As per doc, "The stdout argument is not allowed as it is used internally."
maruel@chromium.org4860f052011-03-25 20:34:38 +0000536 """
maruel@chromium.org87e6d332011-09-09 19:01:28 +0000537 kwargs.setdefault('stdin', VOID)
538 return check_call_out(args, stdout=PIPE, **kwargs)[0]