blob: 03c0c147d7c3728cb49f1a8f5c5c074c7aa41413 [file] [log] [blame]
Owen Lin9d19b272013-11-28 12:13:24 +08001#!/usr/bin/python
2# Copyright (c) 2013 The Chromium OS 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
6import logging
7import pipes
8import subprocess
Owen Lin0d65e8a2013-11-28 14:29:54 +08009import threading
10
11_popen_lock = threading.Lock()
Owen Lin9d19b272013-11-28 12:13:24 +080012
13
14def wait_and_check_returncode(*popens):
15 '''Wait for all the Popens and check the return code is 0.
16
17 If the return code is not 0, it raises an RuntimeError.
18 '''
19 for p in popens:
20 if p.wait() != 0:
21 raise RuntimeError(
22 'Command failed(%d, %d): %s' %
23 (p.pid, p.returncode, p.command))
24
25
26def execute(args, stdin=None, stdout=None):
27 '''Executes a child command and wait for it.
28
29 Returns the output from standard output if 'stdout' is subprocess.PIPE.
30 Raises RuntimeException if the return code of the child command is not 0.
31
32 @param args: the command to be executed
33 @param stdin: the executed program's standard input
34 @param stdout: the executed program's stdandrd output
35 '''
36 ps = popen(args, stdin=stdin, stdout=stdout)
37 out = ps.communicate()[0] if stdout == subprocess.PIPE else None
38 wait_and_check_returncode(ps)
39 return out
40
41
42def popen(*args, **kargs):
43 '''Returns a Popen object just as subprocess.Popen does but with the
44 executed command stored in Popen.command.
45 '''
Owen Lin0d65e8a2013-11-28 14:29:54 +080046 # The lock is required for http://crbug.com/323843.
47 with _popen_lock:
48 ps = subprocess.Popen(*args, **kargs)
Owen Lin9d19b272013-11-28 12:13:24 +080049 the_args = args[0] if len(args) > 0 else kargs['args']
50 ps.command = ' '.join(pipes.quote(x) for x in the_args)
51 logging.info('Running(%d): %s', ps.pid, ps.command)
52 return ps