| #!/usr/bin/env fuchsia-vendored-python |
| |
| # Copyright 2025 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import argparse |
| import shutil |
| import subprocess |
| import sys |
| import tempfile |
| from pathlib import Path |
| |
| |
| def main() -> int: |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--bazel", |
| type=Path, |
| required=True, |
| help="Path to Bazel executable", |
| ) |
| parser.add_argument( |
| "--workspace", |
| type=Path, |
| required=True, |
| help="Path to Bazel workspace", |
| ) |
| parser.add_argument( |
| "--bazel-vendor-dir", |
| type=Path, |
| required=True, |
| help="Bazel vendor directory to write to", |
| ) |
| parser.add_argument( |
| "--repo", |
| action="append", |
| required=True, |
| help="Bazel repositories to vendor", |
| ) |
| parser.add_argument( |
| "--stub-repo", |
| action="append", |
| required=True, |
| help=( |
| "Bazel repositories that are manually stubbed out, their existing" |
| " content should be preserved after the update" |
| ), |
| ) |
| args = parser.parse_args() |
| |
| # Always do a clean vendor in a temporary directory to drop unwanted repos. |
| with tempfile.TemporaryDirectory() as tmp: |
| temp_dir = Path(tmp) |
| cmd = [ |
| args.bazel, |
| "vendor", |
| f"--vendor_dir={temp_dir}", |
| # Overwrite local-only settings from bazelrc. Allow network access and |
| # enable Bazel Central repository when updating vendor repositories. |
| "--downloader_config=/dev/null", |
| "--registry=https://bcr.bazel.build/", |
| ] |
| cmd += [f"--repo={repo}" for repo in args.repo] |
| |
| print(" ".join(str(s) for s in cmd)) |
| |
| # Remove the existing local Bazel registry to force `bazel vendor` to update |
| # and create a new one. |
| shutil.rmtree(args.bazel_vendor_dir / "_registries", ignore_errors=True) |
| subprocess.check_call( |
| cmd, |
| cwd=args.workspace, |
| ) |
| |
| # Pin all the vendored and stub directories, to make sure Bazel doesn't try |
| # to update any of them when building. |
| with open(temp_dir / "VENDOR.bazel", "w") as f: |
| f.write( |
| """################################################################################ |
| # @generated |
| # DO NOT MODIFY: This file is auto-generated by the following command, instead |
| # of changing this file directly, rerun this command: |
| # |
| # fx update-bazel-vendor-dir |
| ################################################################################ |
| |
| """ |
| ) |
| for repo in sorted(args.repo + args.stub_repo): |
| f.write(f'pin("{repo}")\n') |
| |
| # Vendor again after all repositories are pinned to drop the `.marker` files. |
| # This also verifies the VENDOR.bazel file re-written above is valid. |
| subprocess.check_call( |
| cmd, |
| cwd=args.workspace, |
| # Suppress stdout and stderr to avoid user confusion. |
| stdout=subprocess.DEVNULL, |
| stderr=subprocess.DEVNULL, |
| ) |
| |
| # Persist manually stubbed repos from the existing vendor dir. |
| for repo in args.stub_repo: |
| repo_name = repo.lstrip("@") |
| shutil.copytree( |
| args.bazel_vendor_dir / repo_name, temp_dir / repo_name |
| ) |
| shutil.move(args.bazel_vendor_dir / "README.md", temp_dir / "README.md") |
| shutil.move(args.bazel_vendor_dir / "OWNERS", temp_dir / "OWNERS") |
| |
| shutil.rmtree(args.bazel_vendor_dir) |
| shutil.move(temp_dir, args.bazel_vendor_dir) |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |