10d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors. 20d24de9dSSimon Glass# 31a459660SWolfgang Denk# SPDX-License-Identifier: GPL-2.0+ 40d24de9dSSimon Glass# 50d24de9dSSimon Glass 60d24de9dSSimon Glassimport os 7a10fd93cSSimon Glassimport cros_subprocess 80d24de9dSSimon Glass 90d24de9dSSimon Glass"""Shell command ease-ups for Python.""" 100d24de9dSSimon Glass 11a10fd93cSSimon Glassclass CommandResult: 12a10fd93cSSimon Glass """A class which captures the result of executing a command. 13a10fd93cSSimon Glass 14a10fd93cSSimon Glass Members: 15a10fd93cSSimon Glass stdout: stdout obtained from command, as a string 16a10fd93cSSimon Glass stderr: stderr obtained from command, as a string 17a10fd93cSSimon Glass return_code: Return code from command 18a10fd93cSSimon Glass exception: Exception received, or None if all ok 19a10fd93cSSimon Glass """ 20a10fd93cSSimon Glass def __init__(self): 21a10fd93cSSimon Glass self.stdout = None 22a10fd93cSSimon Glass self.stderr = None 23a10fd93cSSimon Glass self.return_code = None 24a10fd93cSSimon Glass self.exception = None 25a10fd93cSSimon Glass 26a10fd93cSSimon Glass 27a10fd93cSSimon Glassdef RunPipe(pipe_list, infile=None, outfile=None, 28a10fd93cSSimon Glass capture=False, capture_stderr=False, oneline=False, 29dc191505SSimon Glass raise_on_error=True, cwd=None, **kwargs): 300d24de9dSSimon Glass """ 310d24de9dSSimon Glass Perform a command pipeline, with optional input/output filenames. 320d24de9dSSimon Glass 33a10fd93cSSimon Glass Args: 34a10fd93cSSimon Glass pipe_list: List of command lines to execute. Each command line is 35a10fd93cSSimon Glass piped into the next, and is itself a list of strings. For 36a10fd93cSSimon Glass example [ ['ls', '.git'] ['wc'] ] will pipe the output of 37a10fd93cSSimon Glass 'ls .git' into 'wc'. 38a10fd93cSSimon Glass infile: File to provide stdin to the pipeline 39a10fd93cSSimon Glass outfile: File to store stdout 40a10fd93cSSimon Glass capture: True to capture output 41a10fd93cSSimon Glass capture_stderr: True to capture stderr 42a10fd93cSSimon Glass oneline: True to strip newline chars from output 43a10fd93cSSimon Glass kwargs: Additional keyword arguments to cros_subprocess.Popen() 44a10fd93cSSimon Glass Returns: 45a10fd93cSSimon Glass CommandResult object 460d24de9dSSimon Glass """ 47a10fd93cSSimon Glass result = CommandResult() 480d24de9dSSimon Glass last_pipe = None 49a10fd93cSSimon Glass pipeline = list(pipe_list) 50dc191505SSimon Glass user_pipestr = '|'.join([' '.join(pipe) for pipe in pipe_list]) 51*ddaf5c8fSSimon Glass kwargs['stdout'] = None 52*ddaf5c8fSSimon Glass kwargs['stderr'] = None 530d24de9dSSimon Glass while pipeline: 540d24de9dSSimon Glass cmd = pipeline.pop(0) 550d24de9dSSimon Glass if last_pipe is not None: 560d24de9dSSimon Glass kwargs['stdin'] = last_pipe.stdout 570d24de9dSSimon Glass elif infile: 580d24de9dSSimon Glass kwargs['stdin'] = open(infile, 'rb') 590d24de9dSSimon Glass if pipeline or capture: 60a10fd93cSSimon Glass kwargs['stdout'] = cros_subprocess.PIPE 610d24de9dSSimon Glass elif outfile: 620d24de9dSSimon Glass kwargs['stdout'] = open(outfile, 'wb') 63a10fd93cSSimon Glass if capture_stderr: 64a10fd93cSSimon Glass kwargs['stderr'] = cros_subprocess.PIPE 650d24de9dSSimon Glass 66a10fd93cSSimon Glass try: 67a10fd93cSSimon Glass last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs) 68a10fd93cSSimon Glass except Exception, err: 69a10fd93cSSimon Glass result.exception = err 70dc191505SSimon Glass if raise_on_error: 71dc191505SSimon Glass raise Exception("Error running '%s': %s" % (user_pipestr, str)) 72dc191505SSimon Glass result.return_code = 255 73dc191505SSimon Glass return result 740d24de9dSSimon Glass 750d24de9dSSimon Glass if capture: 76a10fd93cSSimon Glass result.stdout, result.stderr, result.combined = ( 77a10fd93cSSimon Glass last_pipe.CommunicateFilter(None)) 78a10fd93cSSimon Glass if result.stdout and oneline: 79a10fd93cSSimon Glass result.output = result.stdout.rstrip('\r\n') 80a10fd93cSSimon Glass result.return_code = last_pipe.wait() 810d24de9dSSimon Glass else: 82a10fd93cSSimon Glass result.return_code = os.waitpid(last_pipe.pid, 0)[1] 83dc191505SSimon Glass if raise_on_error and result.return_code: 84dc191505SSimon Glass raise Exception("Error running '%s'" % user_pipestr) 85a10fd93cSSimon Glass return result 860d24de9dSSimon Glass 870d24de9dSSimon Glassdef Output(*cmd): 88dc191505SSimon Glass return RunPipe([cmd], capture=True, raise_on_error=False).stdout 890d24de9dSSimon Glass 90a10fd93cSSimon Glassdef OutputOneLine(*cmd, **kwargs): 91dc191505SSimon Glass raise_on_error = kwargs.pop('raise_on_error', True) 92a10fd93cSSimon Glass return (RunPipe([cmd], capture=True, oneline=True, 93dc191505SSimon Glass raise_on_error=raise_on_error, 94a10fd93cSSimon Glass **kwargs).stdout.strip()) 950d24de9dSSimon Glass 960d24de9dSSimon Glassdef Run(*cmd, **kwargs): 97a10fd93cSSimon Glass return RunPipe([cmd], **kwargs).stdout 980d24de9dSSimon Glass 990d24de9dSSimon Glassdef RunList(cmd): 100a10fd93cSSimon Glass return RunPipe([cmd], capture=True).stdout 101a10fd93cSSimon Glass 102a10fd93cSSimon Glassdef StopAll(): 103a10fd93cSSimon Glass cros_subprocess.stay_alive = False 104