blob: d4b9ba4bd7ac038123f5fb4318df542ef9f8cb7c [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
Owen Lin7ab45a22013-11-19 17:26:33 +080014def kill_silently(*popens):
15 '''Kill all the processes of the given Popens without rasie any exceptions
16 in any cases.
17
18 @param poopens: The Popens to be killed.
19 '''
20 for p in popens:
21 if p and p.pid:
22 try:
23 p.kill()
24 except:
25 logging.exception('failed to kill %d', p.pid)
26
27
Owen Lin9d19b272013-11-28 12:13:24 +080028def wait_and_check_returncode(*popens):
29 '''Wait for all the Popens and check the return code is 0.
30
31 If the return code is not 0, it raises an RuntimeError.
Owen Lin7ab45a22013-11-19 17:26:33 +080032
33 @param popens: The Popens to be checked.
Owen Lin9d19b272013-11-28 12:13:24 +080034 '''
Owen Lin7ab45a22013-11-19 17:26:33 +080035 error_message = None
Owen Lin9d19b272013-11-28 12:13:24 +080036 for p in popens:
37 if p.wait() != 0:
Owen Lin7ab45a22013-11-19 17:26:33 +080038 error_message = ('Command failed(%d, %d): %s' %
39 (p.pid, p.returncode, p.command))
40 logging.error(error_message)
41 if error_message:
42 raise RuntimeError(error_message)
Owen Lin9d19b272013-11-28 12:13:24 +080043
44
45def execute(args, stdin=None, stdout=None):
46 '''Executes a child command and wait for it.
47
48 Returns the output from standard output if 'stdout' is subprocess.PIPE.
49 Raises RuntimeException if the return code of the child command is not 0.
50
51 @param args: the command to be executed
52 @param stdin: the executed program's standard input
53 @param stdout: the executed program's stdandrd output
54 '''
55 ps = popen(args, stdin=stdin, stdout=stdout)
56 out = ps.communicate()[0] if stdout == subprocess.PIPE else None
57 wait_and_check_returncode(ps)
58 return out
59
60
61def popen(*args, **kargs):
62 '''Returns a Popen object just as subprocess.Popen does but with the
63 executed command stored in Popen.command.
64 '''
Owen Lin0d65e8a2013-11-28 14:29:54 +080065 # The lock is required for http://crbug.com/323843.
66 with _popen_lock:
67 ps = subprocess.Popen(*args, **kargs)
Owen Lin9d19b272013-11-28 12:13:24 +080068 the_args = args[0] if len(args) > 0 else kargs['args']
69 ps.command = ' '.join(pipes.quote(x) for x in the_args)
70 logging.info('Running(%d): %s', ps.pid, ps.command)
71 return ps