bazel_common.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/usr/bin/env python3
  2. #
  3. # Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
  4. #
  5. # SPDX-License-Identifier: BSD-3-Clause
  6. #
  7. # Common helpers and variables shared across Bazel-related Python scripts.
  8. import argparse
  9. import logging
  10. import os
  11. from pathlib import Path
  12. import shlex
  13. import shutil
  14. import subprocess
  15. import sys
  16. _LOG = logging.getLogger(__file__)
  17. SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
  18. SDK_ROOT = subprocess.run(
  19. (
  20. "git",
  21. "rev-parse",
  22. "--show-toplevel",
  23. ),
  24. cwd=SCRIPT_DIR,
  25. text=True,
  26. check=True,
  27. capture_output=True,
  28. ).stdout.strip()
  29. def parse_common_args():
  30. parser = argparse.ArgumentParser()
  31. add_common_args(parser)
  32. return parser.parse_args()
  33. def add_common_args(parser):
  34. parser.add_argument(
  35. "--picotool-dir",
  36. help="Use a local copy of Picotool rather than the dynamically fetching it",
  37. default=None,
  38. type=Path,
  39. )
  40. def override_picotool_arg(picotool_dir):
  41. return f"--override_module=picotool={picotool_dir.resolve()}"
  42. def bazel_command() -> str:
  43. """Return the path to bazelisk or bazel."""
  44. if shutil.which("bazelisk"):
  45. return shutil.which("bazelisk")
  46. if shutil.which("bazel"):
  47. return "bazel"
  48. raise FileNotFoundError(
  49. "Cannot find 'bazel' or 'bazelisk' in the current system PATH"
  50. )
  51. def run_bazel(args, check=False, **kwargs):
  52. command = (
  53. bazel_command(),
  54. *args,
  55. )
  56. _LOG.info("Running Bazel command: %s", shlex.join(command))
  57. proc = subprocess.run(
  58. command,
  59. cwd=SDK_ROOT,
  60. **kwargs,
  61. )
  62. if proc.returncode != 0:
  63. _LOG.error("Command invocation failed with return code %d!", proc.returncode)
  64. _LOG.error(
  65. "Failing command: %s",
  66. " ".join(shlex.quote(str(arg)) for arg in args),
  67. )
  68. if kwargs.get("capture_output", False):
  69. output = (
  70. proc.stderr if isinstance(proc.stderr, str) else proc.stderr.decode()
  71. )
  72. _LOG.error(
  73. "Output:\n%s",
  74. output,
  75. )
  76. if check:
  77. raise subprocess.CalledProcessError(
  78. returncode=proc.returncode,
  79. cmd=command,
  80. output=proc.stdout,
  81. stderr=proc.stderr,
  82. )
  83. return proc
  84. def print_to_stderr(*args, **kwargs):
  85. print(*args, file=sys.stderr, **kwargs)
  86. def print_framed_string(s):
  87. """Frames a string of text and prints it to highlight script steps."""
  88. header_spacer = "#" * (len(s) + 12)
  89. print_to_stderr(header_spacer)
  90. print_to_stderr("### " + s + " ###")
  91. print_to_stderr(header_spacer)
  92. def setup_logging():
  93. log_levels = [
  94. (logging.ERROR, "\x1b[31m[ERROR]\x1b[0m"),
  95. (logging.WARNING, "\x1b[33m[WARNING]\x1b[0m"),
  96. (logging.INFO, "\x1b[35m[INFO]\x1b[0m"),
  97. (logging.DEBUG, "\x1b[34m[DEBUG]\x1b[0m"),
  98. ]
  99. for level, level_text in log_levels:
  100. logging.addLevelName(level, level_text)
  101. logging.basicConfig(format="%(levelname)s %(message)s", level=logging.DEBUG)