| #!/usr/bin/env python3 |
| # |
| # Copyright (c) 2024 Raspberry Pi (Trading) Ltd. |
| # |
| # SPDX-License-Identifier: BSD-3-Clause |
| # |
| # Common helpers and variables shared across Bazel-related Python scripts. |
| |
| import argparse |
| import logging |
| import os |
| from pathlib import Path |
| import shlex |
| import shutil |
| import subprocess |
| |
| |
| _LOG = logging.getLogger(__file__) |
| |
| SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) |
| |
| SDK_ROOT = subprocess.run( |
| ( |
| "git", |
| "rev-parse", |
| "--show-toplevel", |
| ), |
| cwd=SCRIPT_DIR, |
| text=True, |
| check=True, |
| capture_output=True, |
| ).stdout.strip() |
| |
| |
| def parse_common_args(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--picotool-dir", |
| help="Use a local copy of Picotool rather than the dynamically fetching it", |
| default=None, |
| type=Path, |
| ) |
| return parser.parse_args() |
| |
| def override_picotool_arg(picotool_dir): |
| return f"--override_module=picotool={picotool_dir.resolve()}" |
| |
| |
| def bazel_command() -> str: |
| """Return the path to bazelisk or bazel.""" |
| if shutil.which("bazelisk"): |
| return "bazelisk" |
| if shutil.which("bazel"): |
| return "bazel" |
| |
| raise FileNotFoundError( |
| "Cannot find 'bazel' or 'bazelisk' in the current system PATH" |
| ) |
| |
| |
| def run_bazel(args, check=False, **kwargs): |
| command = ( |
| bazel_command(), |
| *args, |
| ) |
| _LOG.info("Running Bazel command: %s", shlex.join(command)) |
| proc = subprocess.run( |
| command, |
| cwd=SDK_ROOT, |
| **kwargs, |
| ) |
| if proc.returncode != 0: |
| _LOG.error("Command invocation failed with return code %d!", proc.returncode) |
| _LOG.error( |
| "Failing command: %s", |
| " ".join(shlex.quote(str(arg)) for arg in args), |
| ) |
| if kwargs.get("capture_output", False): |
| output = ( |
| proc.stderr if isinstance(proc.stderr, str) else proc.stderr.decode() |
| ) |
| _LOG.error( |
| "Output:\n%s", |
| output, |
| ) |
| if check: |
| raise subprocess.CalledProcessError( |
| returncode=proc.returncode, |
| cmd=command, |
| output=proc.stdout, |
| stderr=proc.stderr, |
| ) |
| return proc |
| |
| |
| def print_framed_string(s): |
| """Frames a string of text and prints it to highlight script steps.""" |
| header_spacer = "#" * (len(s) + 12) |
| print(header_spacer) |
| print("### " + s + " ###") |
| print(header_spacer) |
| |
| |
| def setup_logging(): |
| log_levels = [ |
| (logging.ERROR, "\x1b[31m[ERROR]\x1b[0m"), |
| (logging.WARNING, "\x1b[33m[WARNING]\x1b[0m"), |
| (logging.INFO, "\x1b[35m[INFO]\x1b[0m"), |
| (logging.DEBUG, "\x1b[34m[DEBUG]\x1b[0m"), |
| ] |
| for level, level_text in log_levels: |
| logging.addLevelName(level, level_text) |
| logging.basicConfig(format="%(levelname)s %(message)s", level=logging.DEBUG) |