| # Copyright 2026 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Common Bazel utilities for conversion scripts.""" |
| |
| from pathlib import Path |
| import subprocess |
| |
| |
| def find_workspace_root(start_path: Path) -> Path: |
| """Finds the Bazel workspace root by looking for WORKSPACE or MODULE.bazel.""" |
| curr = start_path.resolve() |
| while curr != curr.parent: |
| if ( |
| (curr / "WORKSPACE").exists() |
| or (curr / "MODULE.bazel").exists() |
| or (curr / ".git").exists() |
| ): |
| return curr |
| curr = curr.parent |
| # Fallback to CWD |
| return Path.cwd().resolve() |
| |
| |
| def get_bazel_package_prefix(output_dir: Path) -> str: |
| """Determines the Bazel package prefix for the output directory. |
| |
| Returns something like '//third_party/zephyr' or '//'. |
| """ |
| workspace_root = find_workspace_root(output_dir) |
| abs_output_dir = output_dir.resolve() |
| try: |
| rel_path = abs_output_dir.relative_to(workspace_root) |
| if str(rel_path) == ".": |
| return "//" |
| |
| return f"//{rel_path}" |
| except ValueError: |
| print( |
| f"Warning: Output directory {abs_output_dir} is not under workspace root {workspace_root}." |
| ) |
| return "" |
| |
| |
| def expose_files(build_file: Path, files: list[str], comment: str = ""): |
| """Appends exports_files to a BUILD.bazel file.""" |
| if not build_file.exists(): |
| print(f"Warning: {build_file} not found, skipping.") |
| return |
| |
| content = "\n" |
| if comment: |
| content += f"# {comment}\n" |
| files_str = ", ".join(f'"{f}"' for f in files) |
| content += f'exports_files([{files_str}], visibility = ["//visibility:public"])\n' |
| |
| with open(build_file, "a", encoding="utf-8") as f: |
| f.write(content) |
| print(f"Exposed {files} in {build_file}") |
| |
| |
| def run_buildozer(instructions: list[str], target: str) -> bool: |
| """Runs buildozer with the given instructions on the target.""" |
| cmd = ["buildozer"] + instructions + [target] |
| try: |
| result = subprocess.run( |
| cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True |
| ) |
| if result.returncode not in (0, 3): |
| print(f"Error running buildozer: {result.stderr.strip()}") |
| print(f"Command was: {' '.join(cmd)}") |
| return False |
| elif result.returncode == 0: |
| print(f"Buildozer: Applied changes to {target}") |
| elif result.returncode == 3: |
| print(f"Buildozer: No changes needed for {target}") |
| return True |
| except FileNotFoundError: |
| print( |
| "Error: 'buildozer' command not found. Please install buildozer to apply all fixups." |
| ) |
| print(f"Failed to apply to {target}: {instructions}") |
| return False |