X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=tools%2Fpatman%2Fcommand.py;h=d586f1115866125f5768fe0971cb28474c970685;hb=950a23133d8235778ea29f5d9587edec7d9bbc0a;hp=4b00250c0297c64d4a39d3b51d7b57bee541fc94;hpb=0d24de9d558209fa525f350d1320c343f241c3f5;p=oweals%2Fu-boot.git diff --git a/tools/patman/command.py b/tools/patman/command.py index 4b00250c02..d586f11158 100644 --- a/tools/patman/command.py +++ b/tools/patman/command.py @@ -1,72 +1,123 @@ # Copyright (c) 2011 The Chromium OS Authors. # -# See file CREDITS for list of people who contributed to this -# project. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, -# MA 02111-1307 USA +# SPDX-License-Identifier: GPL-2.0+ # import os -import subprocess +import cros_subprocess """Shell command ease-ups for Python.""" -def RunPipe(pipeline, infile=None, outfile=None, - capture=False, oneline=False, hide_stderr=False): +class CommandResult: + """A class which captures the result of executing a command. + + Members: + stdout: stdout obtained from command, as a string + stderr: stderr obtained from command, as a string + return_code: Return code from command + exception: Exception received, or None if all ok + """ + def __init__(self): + self.stdout = None + self.stderr = None + self.combined = None + self.return_code = None + self.exception = None + + def __init__(self, stdout='', stderr='', combined='', return_code=0, + exception=None): + self.stdout = stdout + self.stderr = stderr + self.combined = combined + self.return_code = return_code + self.exception = exception + + +# This permits interception of RunPipe for test purposes. If it is set to +# a function, then that function is called with the pipe list being +# executed. Otherwise, it is assumed to be a CommandResult object, and is +# returned as the result for every RunPipe() call. +# When this value is None, commands are executed as normal. +test_result = None + +def RunPipe(pipe_list, infile=None, outfile=None, + capture=False, capture_stderr=False, oneline=False, + raise_on_error=True, cwd=None, **kwargs): """ Perform a command pipeline, with optional input/output filenames. - hide_stderr Don't allow output of stderr (default False) + Args: + pipe_list: List of command lines to execute. Each command line is + piped into the next, and is itself a list of strings. For + example [ ['ls', '.git'] ['wc'] ] will pipe the output of + 'ls .git' into 'wc'. + infile: File to provide stdin to the pipeline + outfile: File to store stdout + capture: True to capture output + capture_stderr: True to capture stderr + oneline: True to strip newline chars from output + kwargs: Additional keyword arguments to cros_subprocess.Popen() + Returns: + CommandResult object """ + if test_result: + if hasattr(test_result, '__call__'): + return test_result(pipe_list=pipe_list) + return test_result + result = CommandResult() last_pipe = None + pipeline = list(pipe_list) + user_pipestr = '|'.join([' '.join(pipe) for pipe in pipe_list]) + kwargs['stdout'] = None + kwargs['stderr'] = None while pipeline: cmd = pipeline.pop(0) - kwargs = {} if last_pipe is not None: kwargs['stdin'] = last_pipe.stdout elif infile: kwargs['stdin'] = open(infile, 'rb') if pipeline or capture: - kwargs['stdout'] = subprocess.PIPE + kwargs['stdout'] = cros_subprocess.PIPE elif outfile: kwargs['stdout'] = open(outfile, 'wb') - if hide_stderr: - kwargs['stderr'] = open('/dev/null', 'wb') + if capture_stderr: + kwargs['stderr'] = cros_subprocess.PIPE - last_pipe = subprocess.Popen(cmd, **kwargs) + try: + last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs) + except Exception, err: + result.exception = err + if raise_on_error: + raise Exception("Error running '%s': %s" % (user_pipestr, str)) + result.return_code = 255 + return result if capture: - ret = last_pipe.communicate()[0] - if not ret: - return None - elif oneline: - return ret.rstrip('\r\n') - else: - return ret + result.stdout, result.stderr, result.combined = ( + last_pipe.CommunicateFilter(None)) + if result.stdout and oneline: + result.output = result.stdout.rstrip('\r\n') + result.return_code = last_pipe.wait() else: - return os.waitpid(last_pipe.pid, 0)[1] == 0 + result.return_code = os.waitpid(last_pipe.pid, 0)[1] + if raise_on_error and result.return_code: + raise Exception("Error running '%s'" % user_pipestr) + return result def Output(*cmd): - return RunPipe([cmd], capture=True) + return RunPipe([cmd], capture=True, raise_on_error=False).stdout -def OutputOneLine(*cmd): - return RunPipe([cmd], capture=True, oneline=True) +def OutputOneLine(*cmd, **kwargs): + raise_on_error = kwargs.pop('raise_on_error', True) + return (RunPipe([cmd], capture=True, oneline=True, + raise_on_error=raise_on_error, + **kwargs).stdout.strip()) def Run(*cmd, **kwargs): - return RunPipe([cmd], **kwargs) + return RunPipe([cmd], **kwargs).stdout def RunList(cmd): - return RunPipe([cmd], capture=True) + return RunPipe([cmd], capture=True).stdout + +def StopAll(): + cros_subprocess.stay_alive = False