blob: 3b8ec27ac3dd1e23014b8143ab7b081c2444bbff [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 Lin6513db52013-12-11 11:06:46 +080014def kill_or_log_returncode(*popens):
15 '''Kills all the processes of the given Popens or logs the return code.
Owen Lin7ab45a22013-11-19 17:26:33 +080016
17 @param poopens: The Popens to be killed.
18 '''
19 for p in popens:
Owen Lin6513db52013-12-11 11:06:46 +080020 if p.poll() is None:
Owen Lin7ab45a22013-11-19 17:26:33 +080021 try:
22 p.kill()
Owen Lin6513db52013-12-11 11:06:46 +080023 except Exception as e:
24 logging.warning('failed to kill %d, %s', p.pid, e)
25 else:
26 logging.warning('command exit (pid=%d, rc=%d): %s',
27 p.pid, p.returncode, p.command)
Owen Lin7ab45a22013-11-19 17:26:33 +080028
29
Owen Lin9d19b272013-11-28 12:13:24 +080030def wait_and_check_returncode(*popens):
31 '''Wait for all the Popens and check the return code is 0.
32
33 If the return code is not 0, it raises an RuntimeError.
Owen Lin7ab45a22013-11-19 17:26:33 +080034
35 @param popens: The Popens to be checked.
Owen Lin9d19b272013-11-28 12:13:24 +080036 '''
Owen Lin7ab45a22013-11-19 17:26:33 +080037 error_message = None
Owen Lin9d19b272013-11-28 12:13:24 +080038 for p in popens:
39 if p.wait() != 0:
Owen Lin7ab45a22013-11-19 17:26:33 +080040 error_message = ('Command failed(%d, %d): %s' %
41 (p.pid, p.returncode, p.command))
42 logging.error(error_message)
43 if error_message:
44 raise RuntimeError(error_message)
Owen Lin9d19b272013-11-28 12:13:24 +080045
46
47def execute(args, stdin=None, stdout=None):
48 '''Executes a child command and wait for it.
49
50 Returns the output from standard output if 'stdout' is subprocess.PIPE.
51 Raises RuntimeException if the return code of the child command is not 0.
52
53 @param args: the command to be executed
54 @param stdin: the executed program's standard input
55 @param stdout: the executed program's stdandrd output
56 '''
57 ps = popen(args, stdin=stdin, stdout=stdout)
58 out = ps.communicate()[0] if stdout == subprocess.PIPE else None
59 wait_and_check_returncode(ps)
60 return out
61
62
63def popen(*args, **kargs):
64 '''Returns a Popen object just as subprocess.Popen does but with the
65 executed command stored in Popen.command.
66 '''
Owen Lin0d65e8a2013-11-28 14:29:54 +080067 # The lock is required for http://crbug.com/323843.
Owen Lin6f3f0022013-12-04 17:57:47 +080068 the_args = args[0] if len(args) > 0 else kargs['args']
69 command = ' '.join(pipes.quote(x) for x in the_args)
70 logging.info('Running: %s', command)
Owen Lin0d65e8a2013-11-28 14:29:54 +080071 with _popen_lock:
72 ps = subprocess.Popen(*args, **kargs)
Owen Lin6f3f0022013-12-04 17:57:47 +080073 ps.command = command
74 logging.info('pid: %d', ps.pid)
Owen Lin9d19b272013-11-28 12:13:24 +080075 return ps