Owen Lin | 9d19b27 | 2013-11-28 12:13:24 +0800 | [diff] [blame] | 1 | #!/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 | |
| 6 | import logging |
| 7 | import pipes |
| 8 | import subprocess |
Owen Lin | 0d65e8a | 2013-11-28 14:29:54 +0800 | [diff] [blame] | 9 | import threading |
| 10 | |
| 11 | _popen_lock = threading.Lock() |
Owen Lin | 9d19b27 | 2013-11-28 12:13:24 +0800 | [diff] [blame] | 12 | |
| 13 | |
Owen Lin | 6513db5 | 2013-12-11 11:06:46 +0800 | [diff] [blame^] | 14 | def kill_or_log_returncode(*popens): |
| 15 | '''Kills all the processes of the given Popens or logs the return code. |
Owen Lin | 7ab45a2 | 2013-11-19 17:26:33 +0800 | [diff] [blame] | 16 | |
| 17 | @param poopens: The Popens to be killed. |
| 18 | ''' |
| 19 | for p in popens: |
Owen Lin | 6513db5 | 2013-12-11 11:06:46 +0800 | [diff] [blame^] | 20 | if p.poll() is None: |
Owen Lin | 7ab45a2 | 2013-11-19 17:26:33 +0800 | [diff] [blame] | 21 | try: |
| 22 | p.kill() |
Owen Lin | 6513db5 | 2013-12-11 11:06:46 +0800 | [diff] [blame^] | 23 | 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 Lin | 7ab45a2 | 2013-11-19 17:26:33 +0800 | [diff] [blame] | 28 | |
| 29 | |
Owen Lin | 9d19b27 | 2013-11-28 12:13:24 +0800 | [diff] [blame] | 30 | def 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 Lin | 7ab45a2 | 2013-11-19 17:26:33 +0800 | [diff] [blame] | 34 | |
| 35 | @param popens: The Popens to be checked. |
Owen Lin | 9d19b27 | 2013-11-28 12:13:24 +0800 | [diff] [blame] | 36 | ''' |
Owen Lin | 7ab45a2 | 2013-11-19 17:26:33 +0800 | [diff] [blame] | 37 | error_message = None |
Owen Lin | 9d19b27 | 2013-11-28 12:13:24 +0800 | [diff] [blame] | 38 | for p in popens: |
| 39 | if p.wait() != 0: |
Owen Lin | 7ab45a2 | 2013-11-19 17:26:33 +0800 | [diff] [blame] | 40 | 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 Lin | 9d19b27 | 2013-11-28 12:13:24 +0800 | [diff] [blame] | 45 | |
| 46 | |
| 47 | def 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 | |
| 63 | def 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 Lin | 0d65e8a | 2013-11-28 14:29:54 +0800 | [diff] [blame] | 67 | # The lock is required for http://crbug.com/323843. |
Owen Lin | 6f3f002 | 2013-12-04 17:57:47 +0800 | [diff] [blame] | 68 | 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 Lin | 0d65e8a | 2013-11-28 14:29:54 +0800 | [diff] [blame] | 71 | with _popen_lock: |
| 72 | ps = subprocess.Popen(*args, **kargs) |
Owen Lin | 6f3f002 | 2013-12-04 17:57:47 +0800 | [diff] [blame] | 73 | ps.command = command |
| 74 | logging.info('pid: %d', ps.pid) |
Owen Lin | 9d19b27 | 2013-11-28 12:13:24 +0800 | [diff] [blame] | 75 | return ps |