xref: /OK3568_Linux_fs/u-boot/tools/patman/command.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun# Copyright (c) 2011 The Chromium OS Authors.
2*4882a593Smuzhiyun#
3*4882a593Smuzhiyun# SPDX-License-Identifier:	GPL-2.0+
4*4882a593Smuzhiyun#
5*4882a593Smuzhiyun
6*4882a593Smuzhiyunimport os
7*4882a593Smuzhiyunimport cros_subprocess
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun"""Shell command ease-ups for Python."""
10*4882a593Smuzhiyun
11*4882a593Smuzhiyunclass CommandResult:
12*4882a593Smuzhiyun    """A class which captures the result of executing a command.
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun    Members:
15*4882a593Smuzhiyun        stdout: stdout obtained from command, as a string
16*4882a593Smuzhiyun        stderr: stderr obtained from command, as a string
17*4882a593Smuzhiyun        return_code: Return code from command
18*4882a593Smuzhiyun        exception: Exception received, or None if all ok
19*4882a593Smuzhiyun    """
20*4882a593Smuzhiyun    def __init__(self):
21*4882a593Smuzhiyun        self.stdout = None
22*4882a593Smuzhiyun        self.stderr = None
23*4882a593Smuzhiyun        self.combined = None
24*4882a593Smuzhiyun        self.return_code = None
25*4882a593Smuzhiyun        self.exception = None
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun    def __init__(self, stdout='', stderr='', combined='', return_code=0,
28*4882a593Smuzhiyun                 exception=None):
29*4882a593Smuzhiyun        self.stdout = stdout
30*4882a593Smuzhiyun        self.stderr = stderr
31*4882a593Smuzhiyun        self.combined = combined
32*4882a593Smuzhiyun        self.return_code = return_code
33*4882a593Smuzhiyun        self.exception = exception
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun# This permits interception of RunPipe for test purposes. If it is set to
37*4882a593Smuzhiyun# a function, then that function is called with the pipe list being
38*4882a593Smuzhiyun# executed. Otherwise, it is assumed to be a CommandResult object, and is
39*4882a593Smuzhiyun# returned as the result for every RunPipe() call.
40*4882a593Smuzhiyun# When this value is None, commands are executed as normal.
41*4882a593Smuzhiyuntest_result = None
42*4882a593Smuzhiyun
43*4882a593Smuzhiyundef RunPipe(pipe_list, infile=None, outfile=None,
44*4882a593Smuzhiyun            capture=False, capture_stderr=False, oneline=False,
45*4882a593Smuzhiyun            raise_on_error=True, cwd=None, **kwargs):
46*4882a593Smuzhiyun    """
47*4882a593Smuzhiyun    Perform a command pipeline, with optional input/output filenames.
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun    Args:
50*4882a593Smuzhiyun        pipe_list: List of command lines to execute. Each command line is
51*4882a593Smuzhiyun            piped into the next, and is itself a list of strings. For
52*4882a593Smuzhiyun            example [ ['ls', '.git'] ['wc'] ] will pipe the output of
53*4882a593Smuzhiyun            'ls .git' into 'wc'.
54*4882a593Smuzhiyun        infile: File to provide stdin to the pipeline
55*4882a593Smuzhiyun        outfile: File to store stdout
56*4882a593Smuzhiyun        capture: True to capture output
57*4882a593Smuzhiyun        capture_stderr: True to capture stderr
58*4882a593Smuzhiyun        oneline: True to strip newline chars from output
59*4882a593Smuzhiyun        kwargs: Additional keyword arguments to cros_subprocess.Popen()
60*4882a593Smuzhiyun    Returns:
61*4882a593Smuzhiyun        CommandResult object
62*4882a593Smuzhiyun    """
63*4882a593Smuzhiyun    if test_result:
64*4882a593Smuzhiyun        if hasattr(test_result, '__call__'):
65*4882a593Smuzhiyun            return test_result(pipe_list=pipe_list)
66*4882a593Smuzhiyun        return test_result
67*4882a593Smuzhiyun    result = CommandResult()
68*4882a593Smuzhiyun    last_pipe = None
69*4882a593Smuzhiyun    pipeline = list(pipe_list)
70*4882a593Smuzhiyun    user_pipestr =  '|'.join([' '.join(pipe) for pipe in pipe_list])
71*4882a593Smuzhiyun    kwargs['stdout'] = None
72*4882a593Smuzhiyun    kwargs['stderr'] = None
73*4882a593Smuzhiyun    while pipeline:
74*4882a593Smuzhiyun        cmd = pipeline.pop(0)
75*4882a593Smuzhiyun        if last_pipe is not None:
76*4882a593Smuzhiyun            kwargs['stdin'] = last_pipe.stdout
77*4882a593Smuzhiyun        elif infile:
78*4882a593Smuzhiyun            kwargs['stdin'] = open(infile, 'rb')
79*4882a593Smuzhiyun        if pipeline or capture:
80*4882a593Smuzhiyun            kwargs['stdout'] = cros_subprocess.PIPE
81*4882a593Smuzhiyun        elif outfile:
82*4882a593Smuzhiyun            kwargs['stdout'] = open(outfile, 'wb')
83*4882a593Smuzhiyun        if capture_stderr:
84*4882a593Smuzhiyun            kwargs['stderr'] = cros_subprocess.PIPE
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun        try:
87*4882a593Smuzhiyun            last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs)
88*4882a593Smuzhiyun        except Exception as err:
89*4882a593Smuzhiyun            result.exception = err
90*4882a593Smuzhiyun            if raise_on_error:
91*4882a593Smuzhiyun                raise Exception("Error running '%s': %s" % (user_pipestr, str))
92*4882a593Smuzhiyun            result.return_code = 255
93*4882a593Smuzhiyun            return result
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun    if capture:
96*4882a593Smuzhiyun        result.stdout, result.stderr, result.combined = (
97*4882a593Smuzhiyun                last_pipe.CommunicateFilter(None))
98*4882a593Smuzhiyun        if result.stdout and oneline:
99*4882a593Smuzhiyun            result.output = result.stdout.rstrip('\r\n')
100*4882a593Smuzhiyun        result.return_code = last_pipe.wait()
101*4882a593Smuzhiyun    else:
102*4882a593Smuzhiyun        result.return_code = os.waitpid(last_pipe.pid, 0)[1]
103*4882a593Smuzhiyun    if raise_on_error and result.return_code:
104*4882a593Smuzhiyun        raise Exception("Error running '%s'" % user_pipestr)
105*4882a593Smuzhiyun    return result
106*4882a593Smuzhiyun
107*4882a593Smuzhiyundef Output(*cmd, **kwargs):
108*4882a593Smuzhiyun    raise_on_error = kwargs.get('raise_on_error', True)
109*4882a593Smuzhiyun    return RunPipe([cmd], capture=True, raise_on_error=raise_on_error).stdout
110*4882a593Smuzhiyun
111*4882a593Smuzhiyundef OutputOneLine(*cmd, **kwargs):
112*4882a593Smuzhiyun    raise_on_error = kwargs.pop('raise_on_error', True)
113*4882a593Smuzhiyun    return (RunPipe([cmd], capture=True, oneline=True,
114*4882a593Smuzhiyun            raise_on_error=raise_on_error,
115*4882a593Smuzhiyun            **kwargs).stdout.strip())
116*4882a593Smuzhiyun
117*4882a593Smuzhiyundef Run(*cmd, **kwargs):
118*4882a593Smuzhiyun    return RunPipe([cmd], **kwargs).stdout
119*4882a593Smuzhiyun
120*4882a593Smuzhiyundef RunList(cmd):
121*4882a593Smuzhiyun    return RunPipe([cmd], capture=True).stdout
122*4882a593Smuzhiyun
123*4882a593Smuzhiyundef StopAll():
124*4882a593Smuzhiyun    cros_subprocess.stay_alive = False
125