1# Copyright (c) 2011 The Chromium OS Authors. 2# 3# See file CREDITS for list of people who contributed to this 4# project. 5# 6# This program is free software; you can redistribute it and/or 7# modify it under the terms of the GNU General Public License as 8# published by the Free Software Foundation; either version 2 of 9# the License, or (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with this program; if not, write to the Free Software 18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, 19# MA 02111-1307 USA 20# 21 22import os 23import cros_subprocess 24 25"""Shell command ease-ups for Python.""" 26 27class CommandResult: 28 """A class which captures the result of executing a command. 29 30 Members: 31 stdout: stdout obtained from command, as a string 32 stderr: stderr obtained from command, as a string 33 return_code: Return code from command 34 exception: Exception received, or None if all ok 35 """ 36 def __init__(self): 37 self.stdout = None 38 self.stderr = None 39 self.return_code = None 40 self.exception = None 41 42 43def RunPipe(pipe_list, infile=None, outfile=None, 44 capture=False, capture_stderr=False, oneline=False, 45 raise_on_error=True, cwd=None, **kwargs): 46 """ 47 Perform a command pipeline, with optional input/output filenames. 48 49 Args: 50 pipe_list: List of command lines to execute. Each command line is 51 piped into the next, and is itself a list of strings. For 52 example [ ['ls', '.git'] ['wc'] ] will pipe the output of 53 'ls .git' into 'wc'. 54 infile: File to provide stdin to the pipeline 55 outfile: File to store stdout 56 capture: True to capture output 57 capture_stderr: True to capture stderr 58 oneline: True to strip newline chars from output 59 kwargs: Additional keyword arguments to cros_subprocess.Popen() 60 Returns: 61 CommandResult object 62 """ 63 result = CommandResult() 64 last_pipe = None 65 pipeline = list(pipe_list) 66 user_pipestr = '|'.join([' '.join(pipe) for pipe in pipe_list]) 67 while pipeline: 68 cmd = pipeline.pop(0) 69 if last_pipe is not None: 70 kwargs['stdin'] = last_pipe.stdout 71 elif infile: 72 kwargs['stdin'] = open(infile, 'rb') 73 if pipeline or capture: 74 kwargs['stdout'] = cros_subprocess.PIPE 75 elif outfile: 76 kwargs['stdout'] = open(outfile, 'wb') 77 if capture_stderr: 78 kwargs['stderr'] = cros_subprocess.PIPE 79 80 try: 81 last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs) 82 except Exception, err: 83 result.exception = err 84 if raise_on_error: 85 raise Exception("Error running '%s': %s" % (user_pipestr, str)) 86 result.return_code = 255 87 return result 88 89 if capture: 90 result.stdout, result.stderr, result.combined = ( 91 last_pipe.CommunicateFilter(None)) 92 if result.stdout and oneline: 93 result.output = result.stdout.rstrip('\r\n') 94 result.return_code = last_pipe.wait() 95 else: 96 result.return_code = os.waitpid(last_pipe.pid, 0)[1] 97 if raise_on_error and result.return_code: 98 raise Exception("Error running '%s'" % user_pipestr) 99 return result 100 101def Output(*cmd): 102 return RunPipe([cmd], capture=True, raise_on_error=False).stdout 103 104def OutputOneLine(*cmd, **kwargs): 105 raise_on_error = kwargs.pop('raise_on_error', True) 106 return (RunPipe([cmd], capture=True, oneline=True, 107 raise_on_error=raise_on_error, 108 **kwargs).stdout.strip()) 109 110def Run(*cmd, **kwargs): 111 return RunPipe([cmd], **kwargs).stdout 112 113def RunList(cmd): 114 return RunPipe([cmd], capture=True).stdout 115 116def StopAll(): 117 cros_subprocess.stay_alive = False 118