#!/usr/bin/env python3 """Generate buck2 http_archive data from the DotSlash files beside this script. DotSlash is where a tool's version, URL and digest are written down. buck needs the same three facts to fetch that tool itself — it cannot use the shim, which resolves on the machine at run time and so is neither an action input nor anything a remote worker could be given. Rather than write them twice and let them drift, this reads the manifests and emits the table buck reads. just sync-dist # after editing any scripts/*.dotslash The DotSlash format is JSON with a `//` shebang line on top: one entry per platform, each with a url, a size, a digest and the path of the binary inside the archive. Only the archive itself is wanted here; the path inside it is the shim's business, and the toolchain rules name what they need. """ import json import pathlib import sys HERE = pathlib.Path(__file__).resolve().parent OUT = HERE.parent / "toolchains" / "dist" / "generated.bzl" # The tools buck fetches for itself. buck2 is not among them: it is the thing # doing the fetching. jolt is not either — it is fetched by DotSlash on the # machine that runs the boot image compile, which may not be this one. TOOLS = { # DotSlash itself, so an action can fetch what it needs where it runs # rather than being handed it from here. See android/BUCK. "dotslash": "dotslash", # jolt-native's release, so the APK's UI half and the Jolt side of the # tree ABI are fetched rather than built out of a second checkout. "libvidya-android": "libvidya-android", "glimmer-vidya": "glimmer-vidya", "android-glue": "android-glue", } def load(path): text = path.read_text() return json.loads(text[text.index("{") :]) def main(): entries = {} for stem, name in sorted(TOOLS.items()): for candidate in (HERE / f"{stem}.dotslash", HERE / stem): if candidate.exists(): manifest = load(candidate) break else: sys.exit(f"no DotSlash manifest for {stem}") platforms = {} for platform, entry in sorted(manifest["platforms"].items()): if entry["hash"] != "sha256": # http_archive takes sha256 and nothing else. continue url = entry["providers"][0]["url"] # The path of the binary inside the archive starts with the # directory the tarball unpacks into, which is what to strip. # A flat archive — one binary, no directory around it — has # nothing to strip, and naming the binary would strip the whole # payload. head, _, rest = entry["path"].partition("/") platforms[platform] = { "url": url, "sha256": entry["digest"], "strip_prefix": head if rest else "", "type": entry["format"], } entries[name] = platforms lines = [ "# @generated by scripts/dotslash-to-buck — do not edit.", "#", "# The same archives scripts/*.dotslash pins, as facts buck can act on.", "# Bump the DotSlash file and run `just sync-dist`.", "", "DIST = " + json.dumps(entries, indent=4).replace(": true", ": True"), "", ] OUT.parent.mkdir(parents=True, exist_ok=True) OUT.write_text("\n".join(lines)) print(f"wrote {OUT.relative_to(HERE.parent)}") if __name__ == "__main__": main()