1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
#!/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, and dotslash is how a human gets it.
TOOLS = {"zig": "zig", "rustc": "rust"}
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.
platforms[platform] = {
"url": url,
"sha256": entry["digest"],
"strip_prefix": entry["path"].split("/")[0],
"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()
|