blob: 43fde14ffdb46c8608cf8139c3277b6050200b57 [file] [log] [blame] [edit]
#!/usr/bin/env python3
# Copyright 2024 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.
"""Update or generate Bazel workspace for a minimalist build.
This script is intended to be run outside of any build workflow,
for the purposes of testing bazel features and capabilities
such as remote execution. This workflow should remain host-agnostic,
and toolchain-agnostic.
This does not require any Fuchsia SDK.
The TOPDIR directory argument will be populated with the following
files:
$TOPDIR/
workspace/ Bazel workspace directory.
The workspace/ sub-directory will be populated with:
* a generated `.bazelrc`
"""
import argparse
import sys
from pathlib import Path
from typing import Any, Sequence
import build_utils
import remote_services_utils
_THIS_SCRIPT = Path(__file__)
_SCRIPT_DIR = _THIS_SCRIPT.resolve().parent
def _main_arg_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument(
"--fuchsia-dir",
help="Path to the Fuchsia source tree, auto-detected by default.",
type=Path,
)
parser.add_argument(
"--bazel-bin",
help="Path to bazel binary, defaults to $FUCHSIA_DIR/prebuilt/third_party/bazel/${host_platform}/bazel",
type=Path,
)
parser.add_argument(
"--topdir",
help="Top output directory. Defaults to out/_bazel_rbe_test",
type=Path,
)
parser.add_argument(
"--verbose", action="count", default=1, help="Increase verbosity"
)
parser.add_argument(
"--quiet", action="count", default=0, help="Reduce verbosity"
)
return parser
_MAIN_ARG_PARSER = _main_arg_parser()
def force_symlink(src: Path, dest: Path) -> None:
if src.exists() or src.is_symlink():
src.unlink()
src.symlink_to(dest)
def write_file(dest: Path, content: str) -> None:
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_text(content)
def main(argv: Sequence[str]) -> int:
args = _MAIN_ARG_PARSER.parse_args()
verbosity = args.verbose - args.quiet
if args.fuchsia_dir:
fuchsia_dir = args.fuchsia_dir
else:
# Assume this script is in 'build/bazel/scripts/'
# //tools/devshell/rbe always sets this argument,
# this feature is a convenience when calling this script manually.
fuchsia_dir = _SCRIPT_DIR.parent.parent.parent
if args.topdir:
topdir = args.topdir.resolve()
else:
topdir = fuchsia_dir / "out" / "_bazel_rbe_test"
logs_dir = topdir / "logs"
host_tag = build_utils.get_host_tag()
workspace_dir = topdir / "workspace"
workspace_dir.mkdir(parents=True, exist_ok=True)
if args.bazel_bin:
bazel_bin = args.bazel_bin
else:
bazel_bin = (
fuchsia_dir
/ "prebuilt"
/ "third_party"
/ "bazel"
/ host_tag
/ "bazel"
)
def log(message: str, level: int = 1) -> None:
if verbosity >= level:
print(message)
def log2(message: str) -> None:
log(message, 2)
log2(
f"""Using directories and files:
Fuchsia checkout: {fuchsia_dir}
Bazel binary: {bazel_bin}
Topdir: {topdir}
Logs directory: {logs_dir}
Bazel workspace: {workspace_dir}
"""
)
# Create bazel symlink
force_symlink(topdir / "bazel", bazel_bin)
# top-level symlink to //build/...
# We only need a small subset of subdirs under //build.
force_symlink(workspace_dir / "build", fuchsia_dir / "build")
# symlink to vendored //third_party/bazel_skylib
(workspace_dir / "third_party").mkdir(parents=True, exist_ok=True)
force_symlink(
workspace_dir / "third_party" / "bazel_skylib",
fuchsia_dir / "third_party" / "bazel_vendor/bazel_skylib+",
)
# copy/link over build files (no template expansion needed)
force_symlink(
workspace_dir / "BUILD.bazel",
_SCRIPT_DIR / "minimal_workspace.BUILD.bazel",
)
force_symlink(
workspace_dir / "WORKSPACE.bazel",
_SCRIPT_DIR / "minimal_workspace.WORKSPACE.bazel",
)
write_file(workspace_dir / "MODULE.bazel", "\n") # for bzlmod, can be empty
force_symlink(
workspace_dir / "expect_pwd.txt",
_SCRIPT_DIR / "expect_pwd.txt",
)
# Generate args.json expected by fuchsia_platform_build.bzl
write_file(workspace_dir / "fuchsia_build_generated" / "args.json", "{}")
# Generate remote_services.bazelrc
remote_services_utils.generate_remote_services_bazelrc(
fuchsia_dir=fuchsia_dir,
output_path=workspace_dir / "remote_services.bazelrc",
download_outputs="all", # does not matter here.
)
# Generate the content of .bazelrc
fuchsia_dir / "build" / "bazel" / "templates"
def expand_template_file(template_file: Path, **kwargs: Any) -> str:
return template_file.read_text().format(**kwargs)
bazelrc_content: str = ""
# platform excerpt from template.bazelrc
bazelrc_content += """
common --enable_bzlmod=false --enable_workspace=true
build --platforms=//build/bazel/platforms:{default_platform}
build --host_platform=//build/bazel/platforms:{host_platform}
import remote_services.bazelrc
""".format(
default_platform="common", # see build/bazel/platforms/BUILD.bazel
host_platform="host",
)
bazelrc_dest = workspace_dir / ".bazelrc"
bazelrc_dest.write_text(bazelrc_content)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))