blob: eef5a7694282f87d6a5b0a22f1087f0dea1147c4 [file] [log] [blame]
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00001"""Shell command runner function."""
2# Copyright (c) 2020-2022, ARM Limited.
3# SPDX-License-Identifier: Apache-2.0
4import shlex
5import subprocess
6
7
8class RunShCommandError(Exception):
9 """Exception raised for errors running the shell command.
10
11 Attributes:
12 return_code - non-zero return code from running command
13 full_cmd_esc - command and arguments list (pre-escaped)
14 stderr - (optional) - standard error output
15 """
16
17 def __init__(self, return_code, full_cmd_esc, stderr=None, stdout=None):
18 """Initialize run shell command error."""
19 self.return_code = return_code
20 self.full_cmd_esc = full_cmd_esc
21 self.stderr = stderr
22 self.stdout = stdout
23 self.message = "Error {} running command: {}".format(
24 self.return_code, " ".join(self.full_cmd_esc)
25 )
26 if stdout:
27 self.message = "{}\n{}".format(self.message, self.stdout)
28 if stderr:
29 self.message = "{}\n{}".format(self.message, self.stderr)
30 super().__init__(self.message)
31
32
33def run_sh_command(full_cmd, verbose=False, capture_output=False):
34 """Run an external shell command.
35
36 full_cmd: array containing shell command and its arguments
37 verbose: optional flag that enables verbose output
38 capture_output: optional flag to return captured stdout/stderr
39 """
40 # Quote the command line for printing
41 full_cmd_esc = [shlex.quote(x) for x in full_cmd]
42
43 if verbose:
44 print("### Running {}".format(" ".join(full_cmd_esc)))
45
46 if capture_output:
47 rc = subprocess.run(full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
48 stdout = rc.stdout.decode("utf-8")
49 stderr = rc.stderr.decode("utf-8")
50 if verbose:
51 if stdout:
52 print(stdout, end="")
53 if stderr:
54 print(stderr, end="")
55 else:
56 stdout, stderr = None, None
57 rc = subprocess.run(full_cmd)
58
59 if rc.returncode != 0:
60 raise RunShCommandError(rc.returncode, full_cmd_esc, stderr, stdout)
61 return (stdout, stderr)