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
77
78
79
80
81
82
83
84
85
86
87
88
89
|
#!/bin/sh
#_(
exec "$(dirname "$0")/bb" "$0" "$@"
)
;; 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.
(require '[babashka.fs :as fs]
'[cheshire.core :as json]
'[clojure.string :as str])
(def here (fs/parent (fs/canonicalize *file*)))
(def out-file (fs/path (fs/parent here) "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.
(def 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"
;; 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"
"glimmer-vidya"
"android-glue"])
(defn load-manifest [stem]
(let [candidate (->> [(fs/path here (str stem ".dotslash")) (fs/path here stem)]
(filter fs/exists?)
first)]
(when-not candidate
(binding [*out* *err*] (println (str "no DotSlash manifest for " stem)))
(System/exit 1))
(let [text (slurp (str candidate))]
(json/parse-string (subs text (str/index-of text "{"))))))
(defn platform-entry [entry]
(let [;; 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] (str/split (get entry "path") #"/" 2)]
(array-map "url" (get-in entry ["providers" 0 "url"])
"sha256" (get entry "digest")
"strip_prefix" (if rest head "")
"type" (get entry "format"))))
(def dist
(into (array-map)
(for [stem (sort tools)]
[stem (into (array-map)
(for [[platform entry] (sort-by key (get (load-manifest stem) "platforms"))
;; http_archive takes sha256 and nothing else.
:when (= "sha256" (get entry "hash"))]
[platform (platform-entry entry)]))])))
;; Four-space indentation, like the Starlark around it: this file is read by
;; people as often as by buck.
(def pretty
(json/create-pretty-printer
(assoc json/default-pretty-print-options
:indentation " "
:object-field-value-separator ": ")))
(fs/create-dirs (fs/parent out-file))
(spit (str out-file)
(str/join "\n"
["# @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`."
""
(str "DIST = " (json/generate-string dist {:pretty pretty}))
""]))
(println (str "wrote " (fs/relativize (fs/parent here) out-file)))
|