| """Shell command runner function.""" |
| # Copyright (c) 2020-2022, ARM Limited. |
| # SPDX-License-Identifier: Apache-2.0 |
| import shlex |
| import subprocess |
| |
| |
| class RunShCommandError(Exception): |
| """Exception raised for errors running the shell command. |
| |
| Attributes: |
| return_code - non-zero return code from running command |
| full_cmd_esc - command and arguments list (pre-escaped) |
| stderr - (optional) - standard error output |
| """ |
| |
| def __init__(self, return_code, full_cmd_esc, stderr=None, stdout=None): |
| """Initialize run shell command error.""" |
| self.return_code = return_code |
| self.full_cmd_esc = full_cmd_esc |
| self.stderr = stderr |
| self.stdout = stdout |
| self.message = "Error {} running command: {}".format( |
| self.return_code, " ".join(self.full_cmd_esc) |
| ) |
| if stdout: |
| self.message = "{}\n{}".format(self.message, self.stdout) |
| if stderr: |
| self.message = "{}\n{}".format(self.message, self.stderr) |
| super().__init__(self.message) |
| |
| |
| def run_sh_command(full_cmd, verbose=False, capture_output=False): |
| """Run an external shell command. |
| |
| full_cmd: array containing shell command and its arguments |
| verbose: optional flag that enables verbose output |
| capture_output: optional flag to return captured stdout/stderr |
| """ |
| # Quote the command line for printing |
| full_cmd_esc = [shlex.quote(x) for x in full_cmd] |
| |
| if verbose: |
| print("### Running {}".format(" ".join(full_cmd_esc))) |
| |
| if capture_output: |
| rc = subprocess.run(full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| stdout = rc.stdout.decode("utf-8") |
| stderr = rc.stderr.decode("utf-8") |
| if verbose: |
| if stdout: |
| print(stdout, end="") |
| if stderr: |
| print(stderr, end="") |
| else: |
| stdout, stderr = None, None |
| rc = subprocess.run(full_cmd) |
| |
| if rc.returncode != 0: |
| raise RunShCommandError(rc.returncode, full_cmd_esc, stderr, stdout) |
| return (stdout, stderr) |