nandi/frqpublic Fork 0
1e8b590
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Merge origin/main, and let one jolt-native answer for both backends

The terminal backend was a second input at a second rev, because it lived on a
branch and the window half was pinned to a release. Both halves of that are
gone: it is on jolt-native's main now, and this tree builds jolt-native out of
the flake rather than fetching a release, so there is one input again and the
window and the terminal are the same library either way.

Which makes scripts/tui.bb run.bb with the other backend under it, in the shape
run.bb has taken here: the frq source is the files on disk, everything under it
is the dev shell's, and the shell names both Jolt sides. No checkout beside the
tree, no JOLT_NATIVE, no object fetched by digest — and no nixGL, because a
terminal wants nothing from the host's GL driver, which is the reason this
output exists on the machines that have none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandi committed 2026-09-02T20:33:33-07:00 Browse files
1e8b590 parents: 8a86eb3 00b5f93
deleted .buckconfig +0 -32
deleted file mode 100644
@@ -1,32 +0,0 @@
1-[cells]
2- root = .
3- prelude = prelude
4- toolchains = toolchains
5- none = none
6-
7-[cell_aliases]
8- config = prelude
9- ovr_config = prelude
10- fbcode = none
11- fbsource = none
12- fbcode_macros = none
13- buck = none
14-
15-# The prelude bundled with the buck2 binary, so the only pinned thing is
16-# scripts/buck2 itself.
17-[external_cells]
18- prelude = bundled
19-
20-# Both of these name the cache-enabled platform, and both are needed: the
21-# second registers it, the first is what actually routes toolchain-owned
22-# actions onto it.
23-[parser]
24- target_platform_detector_spec = target:root//...->root//platforms:cache \
25- target:prelude//...->root//platforms:cache \
26- target:toolchains//...->root//platforms:cache
27-
28-[build]
29- execution_platforms = root//platforms:cache
30-
31-[project]
32- ignore = .git,android/build,build,buck-out
deleted file mode 100644
@@ -1,32 +0,0 @@
1-[cells]
2- root = .
3- prelude = prelude
4- toolchains = toolchains
5- none = none
6-
7-[cell_aliases]
8- config = prelude
9- ovr_config = prelude
10- fbcode = none
11- fbsource = none
12- fbcode_macros = none
13- buck = none
14-
15-# The prelude bundled with the buck2 binary, so the only pinned thing is
16-# scripts/buck2 itself.
17-[external_cells]
18- prelude = bundled
19-
20-# Both of these name the cache-enabled platform, and both are needed: the
21-# second registers it, the first is what actually routes toolchain-owned
22-# actions onto it.
23-[parser]
24- target_platform_detector_spec = target:root//...->root//platforms:cache \
25- target:prelude//...->root//platforms:cache \
26- target:toolchains//...->root//platforms:cache
27-
28-[build]
29- execution_platforms = root//platforms:cache
30-
31-[project]
32- ignore = .git,android/build,build,buck-out
added .buckconfig.local +7 -0
new file mode 100644
@@ -0,0 +1,7 @@
1+[frq]
2+ jolt_native = /var/home/nandi/code/jolt-native
3+ android_home = /var/home/nandi/.local/share/android-sdk
4+ chez_android = /var/home/nandi/.cache/vidya-chez-android
5+ openssl_android = /var/home/nandi/.cache/frq-openssl-android/lib
6+ libvidya = checkout
7+ boot_stamp = 99766f8764e29cdb652b6841cd8949f8815d17e836f4949d17991a67e0e38096
new file mode 100644
@@ -0,0 +1,7 @@
1+[frq]
2+ jolt_native = /var/home/nandi/code/jolt-native
3+ android_home = /var/home/nandi/.local/share/android-sdk
4+ chez_android = /var/home/nandi/.cache/vidya-chez-android
5+ openssl_android = /var/home/nandi/.cache/frq-openssl-android/lib
6+ libvidya = checkout
7+ boot_stamp = 99766f8764e29cdb652b6841cd8949f8815d17e836f4949d17991a67e0e38096
deleted .buckroot +0 -0
deleted file mode 100644
deleted file mode 100644
modified .gitignore +0 -8
@@ -1,14 +1,6 @@
1-# Build outputs: the boot image and the APK.
2-/android/build/
3-
41 # The native libraries `just lib` links out of the DotSlash cache.
52 /build/
63
7-# buck2 output tree.
8-/buck-out
9-# Written by the `buck` recipe: this machine's paths, not a shared setting.
10-/.buckconfig.local
11-
124 # Tool caches.
135 /.cpcache/
146 /.jolt/
@@ -1,14 +1,6 @@
1-# Build outputs: the boot image and the APK.
2-/android/build/
3-
4 # The native libraries `just lib` links out of the DotSlash cache.1 # The native libraries `just lib` links out of the DotSlash cache.
5 /build/2 /build/
6 3
7-# buck2 output tree.
8-/buck-out
9-# Written by the `buck` recipe: this machine's paths, not a shared setting.
10-/.buckconfig.local
11-
12 # Tool caches.4 # Tool caches.
13 /.cpcache/5 /.cpcache/
14 /.jolt/6 /.jolt/
deleted BUCK +0 -15
deleted file mode 100644
@@ -1,15 +0,0 @@
1-# The Jolt sources the boot image is compiled from. Named as a target so that
2-# editing a screen invalidates the image: the compile itself reads the tree
3-# through deps.edn paths rather than through these, but buck only reruns it
4-# when something here changes.
5-filegroup(
6- name = "jolt-sources",
7- srcs = glob(["src/**/*.jolt", "src/**/*.edn"]) + ["deps.edn"],
8- visibility = ["PUBLIC"],
9-)
10-
11-alias(
12- name = "apk",
13- actual = "//android:apk",
14- visibility = ["PUBLIC"],
15-)
deleted file mode 100644
@@ -1,15 +0,0 @@
1-# The Jolt sources the boot image is compiled from. Named as a target so that
2-# editing a screen invalidates the image: the compile itself reads the tree
3-# through deps.edn paths rather than through these, but buck only reruns it
4-# when something here changes.
5-filegroup(
6- name = "jolt-sources",
7- srcs = glob(["src/**/*.jolt", "src/**/*.edn"]) + ["deps.edn"],
8- visibility = ["PUBLIC"],
9-)
10-
11-alias(
12- name = "apk",
13- actual = "//android:apk",
14- visibility = ["PUBLIC"],
15-)
modified CLAUDE.md +8 -9
@@ -2,19 +2,18 @@
22
33 ## Nix
44
5-`nix` is not installed on the host. It lives in the Arch distrobox, so run every
6-nix command through that:
5+You are already running inside the Arch distrobox, where `nix` lives, so run
6+nix commands directly — do not wrap them in `distrobox enter`:
77
88 ```bash
9-distrobox enter arch -- bash -lc 'cd <this directory> && nix build .#frq'
9+nix build .#frq
1010 ```
1111
12-The worktree path is the same inside the container as outside, so `cd "$PWD"`
13-works. A remote builder (`eu.nixbuild.net`) is already configured there; the
14-Android outputs want `--store ssh-ng://eu.nixbuild.net --eval-store auto`, for
15-the reason nix/android.nix gives at the top.
12+A remote builder (`eu.nixbuild.net`) is already configured here; the Android
13+outputs want `--store ssh-ng://eu.nixbuild.net --eval-store auto`, for the
14+reason nix/android.nix gives at the top.
1615
17-One thing that container is *not* representative of: `/etc/localtime` is a
18-regular file there rather than a symlink, so anything that reads the zone out
16+One thing this container is *not* representative of: `/etc/localtime` is a
17+regular file here rather than a symlink, so anything that reads the zone out
1918 of its path sees nothing. That is a real deployment shape, not an artefact —
2019 frq.clock handles it.
@@ -2,19 +2,18 @@
2 2
3 ## Nix3 ## Nix
4 4
5-`nix` is not installed on the host. It lives in the Arch distrobox, so run every5+You are already running inside the Arch distrobox, where `nix` lives, so run
6-nix command through that:6+nix commands directly — do not wrap them in `distrobox enter`:
7 7
8 ```bash8 ```bash
9-distrobox enter arch -- bash -lc 'cd <this directory> && nix build .#frq'9+nix build .#frq
10 ```10 ```
11 11
12-The worktree path is the same inside the container as outside, so `cd "$PWD"`12+A remote builder (`eu.nixbuild.net`) is already configured here; the Android
13-works. A remote builder (`eu.nixbuild.net`) is already configured there; the13+outputs want `--store ssh-ng://eu.nixbuild.net --eval-store auto`, for the
14-Android outputs want `--store ssh-ng://eu.nixbuild.net --eval-store auto`, for14+reason nix/android.nix gives at the top.
15-the reason nix/android.nix gives at the top.
16 15
17-One thing that container is *not* representative of: `/etc/localtime` is a16+One thing this container is *not* representative of: `/etc/localtime` is a
18-regular file there rather than a symlink, so anything that reads the zone out17+regular file here rather than a symlink, so anything that reads the zone out
19 of its path sees nothing. That is a real deployment shape, not an artefact —18 of its path sees nothing. That is a real deployment shape, not an artefact —
20 frq.clock handles it.19 frq.clock handles it.
modified README.md +19 -11
@@ -41,6 +41,11 @@ just lib
4141 just run
4242 ```
4343
44+The scripts under `scripts/` are babashka, reached through `scripts/bb`: a bb
45+on `PATH` if there is one — the dev shell puts one there — and otherwise the
46+flake's `.#bb`, built once and kept under `build/`. Nothing has to be installed
47+for that but Nix.
48+
4449 `just lib` fetches both shared objects this client loads —
4550 [jolt-native](https://gitlab.com/nandithebull/jolt-native)'s `libvidya`, the
4651 retained-tree ABI glimmer paints through, and `libjoltmoq`, the AV media plane
@@ -105,12 +110,11 @@ answer, because they are counted in rows of chrome rather than in lengths: a
105110 window's row is 34 points and a terminal's is one cell. `chrome-row` is where
106111 that is said, and `frq.tui` sets it.
107112
108-Two things are unpinned, because the terminal backend is not in a jolt-native
109-release yet: `libjolttui.so` comes out of a jolt-native checkout's target
110-directory (`JOLT_NATIVE=…`, or beside this tree) for `just tui`, and the flake
111-carries a second `jolt-native-tui` input at the rev that has it — its own input
112-rather than a bump, so the window half stays on the release the rest of the
113-tree names. Both become one pin when it ships.
113+`just tui` is `just run`'s two halves with the other backend under them: this
114+tree's source on the flake's everything-else, in the dev shell. jolt-native
115+carries both native libraries and both Jolt sides — glimmer-vidya for the
116+window, glimmer-tui for the terminal — so one input answers for either, and
117+nothing here needs a checkout beside the tree.
114118
115119 ## Signing in
116120
@@ -152,13 +156,17 @@ NativeActivity's own library), `libjoltmoq.so` (the media plane) and
152156 `libjoltapp.so` (frq compiled to a Chez boot image, linked against both).
153157
154158 ```bash
155-./android/build-apk.bb run # build, install, launch on a connected device
156-./android/build-apk.bb log # logcat, filtered
159+just apk run # build, install, launch on a connected device
160+just apk log # logcat, filtered
157161 ```
158162
159-Needs an SDK and a cross-built Chez in `~/.cache/vidya-chez-android`; the NDK
160-comes down through `scripts/android-ndk.dotslash`. `just apk` builds the same
161-APK as a buck2 graph, which is the incremental way in.
163+Needs nothing on the machine but Nix and an `adb`: the build is
164+[`nix/android.nix`](nix/android.nix), and the SDK, the NDK, the arm64 Chez
165+cross target and the OpenSSL the app carries are all built or fetched there.
166+`nix build .#apk` is the same thing without adb; on a machine with a remote
167+builder, hand it the store rather than a `builders` entry —
168+`FRQ_NIX_STORE=ssh-ng://eu.nixbuild.net just apk`, and see the header of
169+`nix/android.nix` for why.
162170
163171 TLS does not work there: jolt reaches OpenSSL through the dynamic loader, and
164172 Android has no public `libssl` to load. The connect screen falls back to the
@@ -41,6 +41,11 @@ just lib
41 just run41 just run
42 ```42 ```
43 43
44+The scripts under `scripts/` are babashka, reached through `scripts/bb`: a bb
45+on `PATH` if there is one — the dev shell puts one there — and otherwise the
46+flake's `.#bb`, built once and kept under `build/`. Nothing has to be installed
47+for that but Nix.
48+
44 `just lib` fetches both shared objects this client loads —49 `just lib` fetches both shared objects this client loads —
45 [jolt-native](https://gitlab.com/nandithebull/jolt-native)'s `libvidya`, the50 [jolt-native](https://gitlab.com/nandithebull/jolt-native)'s `libvidya`, the
46 retained-tree ABI glimmer paints through, and `libjoltmoq`, the AV media plane51 retained-tree ABI glimmer paints through, and `libjoltmoq`, the AV media plane
@@ -105,12 +110,11 @@ answer, because they are counted in rows of chrome rather than in lengths: a
105 window's row is 34 points and a terminal's is one cell. `chrome-row` is where110 window's row is 34 points and a terminal's is one cell. `chrome-row` is where
106 that is said, and `frq.tui` sets it.111 that is said, and `frq.tui` sets it.
107 112
108-Two things are unpinned, because the terminal backend is not in a jolt-native113+`just tui` is `just run`'s two halves with the other backend under them: this
109-release yet: `libjolttui.so` comes out of a jolt-native checkout's target114+tree's source on the flake's everything-else, in the dev shell. jolt-native
110-directory (`JOLT_NATIVE=…`, or beside this tree) for `just tui`, and the flake115+carries both native libraries and both Jolt sides — glimmer-vidya for the
111-carries a second `jolt-native-tui` input at the rev that has it — its own input116+window, glimmer-tui for the terminal — so one input answers for either, and
112-rather than a bump, so the window half stays on the release the rest of the117+nothing here needs a checkout beside the tree.
113-tree names. Both become one pin when it ships.
114 118
115 ## Signing in119 ## Signing in
116 120
@@ -152,13 +156,17 @@ NativeActivity's own library), `libjoltmoq.so` (the media plane) and
152 `libjoltapp.so` (frq compiled to a Chez boot image, linked against both).156 `libjoltapp.so` (frq compiled to a Chez boot image, linked against both).
153 157
154 ```bash158 ```bash
155-./android/build-apk.bb run # build, install, launch on a connected device159+just apk run # build, install, launch on a connected device
156-./android/build-apk.bb log # logcat, filtered160+just apk log # logcat, filtered
157 ```161 ```
158 162
159-Needs an SDK and a cross-built Chez in `~/.cache/vidya-chez-android`; the NDK163+Needs nothing on the machine but Nix and an `adb`: the build is
160-comes down through `scripts/android-ndk.dotslash`. `just apk` builds the same164+[`nix/android.nix`](nix/android.nix), and the SDK, the NDK, the arm64 Chez
161-APK as a buck2 graph, which is the incremental way in.165+cross target and the OpenSSL the app carries are all built or fetched there.
166+`nix build .#apk` is the same thing without adb; on a machine with a remote
167+builder, hand it the store rather than a `builders` entry —
168+`FRQ_NIX_STORE=ssh-ng://eu.nixbuild.net just apk`, and see the header of
169+`nix/android.nix` for why.
162 170
163 TLS does not work there: jolt reaches OpenSSL through the dynamic loader, and171 TLS does not work there: jolt reaches OpenSSL through the dynamic loader, and
164 Android has no public `libssl` to load. The connect screen falls back to the172 Android has no public `libssl` to load. The connect screen falls back to the
deleted android/BUCK +0 -254
deleted file mode 100644
@@ -1,254 +0,0 @@
1-# The APK, as a graph rather than a script.
2-#
3-# Every step the old build-apk script ran in sequence is a target here, so a change
4-# to one screen rebuilds the boot image and repackages, and touches neither the
5-# Rust nor the Java. The two native halves and the glue come out of jolt-native's
6-# release, fetched by digest through scripts/*.dotslash; the rest is this repo's.
7-# Nothing here is built out of a jolt-native checkout, and none is needed.
8-#
9-# The machine-specific paths are read from .buckconfig.local, which the `buck`
10-# recipe in the justfile writes. Nothing here is found by looking around the
11-# machine; if a path is missing the recipe says which.
12-_ANDROID_HOME = read_root_config("frq", "android_home", "")
13-_CHEZ = read_root_config("frq", "chez_android", "")
14-_OPENSSL = read_root_config("frq", "openssl_android", "")
15-
16-_API = "28"
17-_TOOLS = _ANDROID_HOME + "/build-tools/36.0.0"
18-_ANDROID_JAR = _ANDROID_HOME + "/platforms/android-36/android.jar"
19-# `$(...)` in a genrule cmd is a buck macro, not the shell's substitution, so
20-# everything this file runs at command time uses backticks.
21-# This repo's own: an APK build needs a clang and an llvm-objcopy, and neither
22-# is jolt-native's to supply. Both resolve the NDK through
23-# scripts/android-ndk.dotslash, downloading it once.
24-_NDK_BIN = "ndk=`$(location //scripts:android-ndk-bin)`"
25-_CC = "$(location //scripts:android-cc)"
26-
27-# An absolute path for $OUT, so a command may cd without losing it. buck has
28-# already made the parent directory. Spelled out step by step because backticks
29-# do not nest.
30-# The archive's top directory is what strip_prefix took off, so `src` is
31-# directly inside it. Absolute, because the script is handed this and does its
32-# own directory changing.
33-_GLIMMER_VIDYA = "GLIMMER_VIDYA=`realpath $(location toolchains//dist:glimmer-vidya)/src` "
34-
35-# jolt_main.c and the ABI's headers, as targets rather than bare paths — see
36-# the rules below.
37-_GLUE_C = "`realpath $(location :glue-c)`"
38-_GLUE_INCLUDE = "`realpath $(location :glue-include)`"
39-
40-_ABS_OUT = 'd=`dirname "$OUT"` && b=`basename "$OUT"` && d=`cd "$d" && pwd` && out="$d/$b"'
41-
42-# Somewhere to assemble in. Removed by the command that made it, on success;
43-# buck's own scratch space is not this.
44-_TMP = 'tmp=`mktemp -d`'
45-
46-# A babashka script, run in place: it loads scripts/frq/paths.clj beside it and
47-# resolves its own interpreter through scripts/bb, the DotSlash pin. Referenced
48-# rather than copied for exactly that reason — the tree around it is part of it.
49-export_file(
50- name = "build-jolt-boot.bb",
51- mode = "reference",
52-)
53-
54-# --- the UI half ------------------------------------------------------------
55-# The .so out of jolt-native's release, fetched by digest — which is what makes
56-# an APK buildable with no jolt-native checkout and no NDK anywhere on the
57-# machine. A genrule rather than a path, so the library's bytes are an input to
58-# what reads them: an action that shelled out to build it would have nothing to
59-# invalidate on and would serve the same stale object forever.
60-genrule(
61- name = "libvidya",
62- out = "libvidya.so",
63- cmd = "cp $(location toolchains//dist:libvidya-android)/libvidya.so \"$OUT\"",
64-)
65-
66-# The media plane, out of the same archive. Necessarily the same release:
67-# libjoltapp links both, and pairing one release's media plane with another's
68-# UI is a combination nothing has tested.
69-genrule(
70- name = "libjoltmoq",
71- out = "libjoltmoq.so",
72- cmd = "cp $(location toolchains//dist:libjoltmoq-android)/libjoltmoq.so \"$OUT\"",
73-)
74-
75-# jolt_main.c and the ABI's headers, from the glue archive of the same release.
76-# Targets rather than paths for the reason above — an input is the only thing
77-# buck can notice a change in.
78-genrule(
79- name = "glue-c",
80- out = "jolt_main.c",
81- cmd = "cp $(location toolchains//dist:android-glue)/android/jolt_main.c \"$OUT\"",
82-)
83-
84-# A directory of headers rather than a filegroup: a filegroup keeps each file
85-# at its own path inside the output, so `-I` would have to name the staging
86-# directory again.
87-genrule(
88- name = "glue-include",
89- out = "include",
90- cmd = "cp -r $(location toolchains//dist:android-glue)/include \"$OUT\"",
91-)
92-
93-# The C++ runtime, out of the same NDK the glue is compiled with.
94-#
95-# openh264 is C++, and its build script asks to be linked against
96-# `libc++_shared.so` by name — so libjoltmoq carries that as a DT_NEEDED. An
97-# app's linker namespace will not hand out the platform's own copy (there is no
98-# stable one to hand out), so the APK has to carry it, exactly as it carries
99-# OpenSSL below and for the same reason.
100-#
101-# Only when the media plane is packaged: nothing else here is C++.
102-genrule(
103- name = "libcxx",
104- out = "libc++_shared.so",
105- cmd = _ABS_OUT + " && " + _NDK_BIN + " && " +
106- "cp \"$ndk\"/../sysroot/usr/lib/aarch64-linux-android/libc++_shared.so \"$out\"",
107-)
108-
109-# --- the Jolt half ----------------------------------------------------------
110-# The boot image: frq's Scheme, cross-compiled to arm64 by Chez. The sources
111-# are an input so that editing one rebuilds this; the compile itself reads them
112-# through the deps.edn the script writes.
113-# The sources here are frq's own. The other two roots the image is compiled
114-# from — glimmer and glimmer-vidya, both out of the jolt cache — are outside
115-# this cell, and so are Chez's cross boot files and the pinned
116-# jolt itself. None of them can be an input, so the `buck` recipe hashes them
117-# and writes the digest below; naming it in the command is what puts them in
118-# this action's identity.
119-# jolt reaches this action as a manifest and a fetcher rather than as a
120-# program: both are inputs, so nothing here depends on what is installed where
121-# the compile runs, and a remote worker resolves the same pin — by the same
122-# digest — from the same place this machine would.
123-genrule(
124- name = "jolt-boot",
125- out = "boot",
126- srcs = ["//:jolt-sources"],
127- cmd = "# sources outside this cell: " + read_root_config("frq", "boot_stamp", "unknown") + "\n" +
128- "DOTSLASH=$(location toolchains//dist:dotslash)/dotslash " +
129- "JOLT_MANIFEST=$(location //scripts:jolt) " +
130- # The one source root the script cannot find for itself: the jolt
131- # cache is not an action input, and this is. A new release recompiles
132- # the image because of it.
133- _GLIMMER_VIDYA +
134- "$(location :build-jolt-boot.bb) \"$OUT\" >&2",
135-)
136-
137-# The image travels as a blob in an object file's data section; the
138-# _binary_jolt_boot_{start,end} symbols jolt_main.c reads are named after the
139-# input *path*, which is why this copies the file somewhere it can be called
140-# exactly `jolt.boot` before converting it.
141-genrule(
142- name = "jolt-boot-obj",
143- out = "jolt_boot.o",
144- cmd = _ABS_OUT + " && " +
145- _TMP + " && " + _NDK_BIN + " && " +
146- "cp $(location :jolt-boot)/jolt.boot \"$tmp/jolt.boot\" && " +
147- "( cd \"$tmp\" && \"$ndk\"/llvm-objcopy " +
148- "--input-target=binary --output-target=elf64-littleaarch64 " +
149- "--binary-architecture=aarch64 jolt.boot jolt_boot.o ) && " +
150- "cp \"$tmp/jolt_boot.o\" \"$out\" && rm -rf \"$tmp\"",
151-)
152-
153-# The glue: jolt-native's android/jolt_main.c over the boot image, linked
154-# against libvidya by name. --no-undefined is what makes a symbol the Scheme
155-# side registers but the ABI no longer exports a build failure here rather than
156-# a crash on the phone.
157-genrule(
158- name = "libjoltapp",
159- out = "libjoltapp.so",
160- cmd = _ABS_OUT + " && lib=`mktemp -d` && " +
161- "cp $(location :libvidya) \"$lib/libvidya.so\" && " +
162- "cp $(location :libjoltmoq) \"$lib/libjoltmoq.so\" && " +
163- _CC + " -shared -fPIC -O2 -o \"$out\" " +
164- _GLUE_C + " " +
165- "$(location :jolt-boot-obj) " +
166- "-I$(location :jolt-boot) " +
167- "-I" + _GLUE_INCLUDE + " " +
168- "-L\"$lib\" " +
169- _CHEZ + "/tarm64le/boot/tarm64le/libkernel.a " +
170- _CHEZ + "/lz4/lib/liblz4.a " +
171- "-lvidya -ljoltmoq -landroid -llog -lz -ldl -lm -Wl,--no-undefined && " +
172- "rm -rf \"$lib\"",
173-)
174-
175-# --- the Java half ----------------------------------------------------------
176-# Two classes: the photo chooser's result has to land somewhere and native code
177-# is not somewhere, and Camera2 has no C API worth the name — CameraCapture
178-# opens the camera in Java and pushes NV12 planes down to libjoltmoq over JNI.
179-# android.jar on the class path is where every android.* type comes from; the
180-# JDK's own java.* is what is left.
181-genrule(
182- name = "classes-dex",
183- out = "classes.dex",
184- srcs = glob(["java/**/*.java"]),
185- cmd = _ABS_OUT + " && " + _TMP + " && " +
186- "javac --release 17 --class-path " + _ANDROID_JAR + " -d \"$tmp/classes\" $SRCS && " +
187- "classes=`find \"$tmp/classes\" -name '*.class'` && " +
188- _TOOLS + "/d8 --min-api " + _API + " --output \"$tmp\" $classes && " +
189- "cp \"$tmp/classes.dex\" \"$out\" && rm -rf \"$tmp\"",
190-)
191-
192-# --- the package ------------------------------------------------------------
193-# The libraries are stored rather than deflated: the loader maps them straight
194-# out of the APK. The dex is read rather than mapped, so it may as well
195-# compress. OpenSSL travels with the app because the platform's own is not ours
196-# to load — an app's linker namespace refuses /system/lib64/libssl.so, and
197-# without one there is no TLS on the phone at all.
198-genrule(
199- name = "apk-unsigned",
200- out = "frq-unsigned.apk",
201- srcs = ["AndroidManifest.xml"],
202- cmd = _ABS_OUT + " && stage=`mktemp -d` && " +
203- "mkdir -p \"$stage/lib/arm64-v8a\" && " +
204- "cp $(location :libvidya) \"$stage/lib/arm64-v8a/libvidya.so\" && " +
205- "cp $(location :libjoltapp) \"$stage/lib/arm64-v8a/libjoltapp.so\" && " +
206- "cp $(location :libjoltmoq) \"$stage/lib/arm64-v8a/libjoltmoq.so\" && " +
207- "cp $(location :libcxx) \"$stage/lib/arm64-v8a/libc++_shared.so\" && " +
208- "cp " + _OPENSSL + "/libssl.so " + _OPENSSL + "/libcrypto.so \"$stage/lib/arm64-v8a/\" && " +
209- "cp $(location :classes-dex) \"$stage/classes.dex\" && " +
210- _TOOLS + "/aapt2 link -o \"$out\" -I " + _ANDROID_JAR + " " +
211- "--manifest $SRCS --min-sdk-version " + _API + " --target-sdk-version 36 " +
212- "--version-code 1 --version-name 0.1.0 >&2 && " +
213- "( cd \"$stage\" && zip -q -0 \"$out\" lib/arm64-v8a/libvidya.so " +
214- "lib/arm64-v8a/libjoltmoq.so lib/arm64-v8a/libc++_shared.so " +
215- "lib/arm64-v8a/libjoltapp.so lib/arm64-v8a/libssl.so lib/arm64-v8a/libcrypto.so && " +
216- "zip -q \"$out\" classes.dex ) && rm -rf \"$stage\"",
217-)
218-
219-# Aligned and signed with the debug key, which is generated on first use the
220-# way the SDK's own tools generate it.
221-genrule(
222- name = "apk",
223- out = "frq.apk",
224- cmd = _ABS_OUT + " && " + _TMP + " && " +
225- "ks=\"$HOME/.android/debug.keystore\" && " +
226- "if [ ! -f \"$ks\" ]; then mkdir -p \"$HOME/.android\" && " +
227- "keytool -genkeypair -v -keystore \"$ks\" -storepass android -keypass android " +
228- "-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 " +
229- "-dname 'CN=Android Debug,O=Android,C=US' >&2; fi && " +
230- _TOOLS + "/zipalign -f -p 4 $(location :apk-unsigned) \"$tmp/aligned.apk\" && " +
231- _TOOLS + "/apksigner sign --ks \"$ks\" --ks-key-alias androiddebugkey " +
232- "--ks-pass pass:android --key-pass pass:android --out \"$out\" \"$tmp/aligned.apk\" && " +
233- _TOOLS + "/apksigner verify \"$out\" >/dev/null && rm -rf \"$tmp\"",
234- visibility = ["PUBLIC"],
235-)
236-
237-# Does the pin resolve where the action runs, and does what it resolves to run
238-# there? Nothing depends on this; it is here to be asked by hand.
239-#
240-# buck2 build //android:jolt-fetch-check --remote-only --materializations=all \
241-# -c build.execution_platforms=root//platforms:remote -c "parser...->root//platforms:remote"
242-#
243-# It is what found the glibc floor: jolt needs 2.38, and the rbe-ubuntu22-04
244-# image this platform used to name ships 2.35, so the fetch succeeded and the
245-# binary would not start. The answer was the newer image, not a different pin.
246-genrule(
247- name = "jolt-fetch-check",
248- out = "report",
249- cmd = "jolt=`$(location toolchains//dist:dotslash)/dotslash -- fetch $(location //scripts:jolt)`; " +
250- "{ echo \"fetched: $jolt\"; " +
251- "cat /etc/os-release 2>/dev/null | head -1 || true; " +
252- "ldd --version 2>&1 | head -1 || true; " +
253- "echo '--- run ---'; \"$jolt\" --version; echo \"rc=$?\"; } > \"$OUT\" 2>&1 || true",
254-)
deleted file mode 100644
@@ -1,254 +0,0 @@
1-# The APK, as a graph rather than a script.
2-#
3-# Every step the old build-apk script ran in sequence is a target here, so a change
4-# to one screen rebuilds the boot image and repackages, and touches neither the
5-# Rust nor the Java. The two native halves and the glue come out of jolt-native's
6-# release, fetched by digest through scripts/*.dotslash; the rest is this repo's.
7-# Nothing here is built out of a jolt-native checkout, and none is needed.
8-#
9-# The machine-specific paths are read from .buckconfig.local, which the `buck`
10-# recipe in the justfile writes. Nothing here is found by looking around the
11-# machine; if a path is missing the recipe says which.
12-_ANDROID_HOME = read_root_config("frq", "android_home", "")
13-_CHEZ = read_root_config("frq", "chez_android", "")
14-_OPENSSL = read_root_config("frq", "openssl_android", "")
15-
16-_API = "28"
17-_TOOLS = _ANDROID_HOME + "/build-tools/36.0.0"
18-_ANDROID_JAR = _ANDROID_HOME + "/platforms/android-36/android.jar"
19-# `$(...)` in a genrule cmd is a buck macro, not the shell's substitution, so
20-# everything this file runs at command time uses backticks.
21-# This repo's own: an APK build needs a clang and an llvm-objcopy, and neither
22-# is jolt-native's to supply. Both resolve the NDK through
23-# scripts/android-ndk.dotslash, downloading it once.
24-_NDK_BIN = "ndk=`$(location //scripts:android-ndk-bin)`"
25-_CC = "$(location //scripts:android-cc)"
26-
27-# An absolute path for $OUT, so a command may cd without losing it. buck has
28-# already made the parent directory. Spelled out step by step because backticks
29-# do not nest.
30-# The archive's top directory is what strip_prefix took off, so `src` is
31-# directly inside it. Absolute, because the script is handed this and does its
32-# own directory changing.
33-_GLIMMER_VIDYA = "GLIMMER_VIDYA=`realpath $(location toolchains//dist:glimmer-vidya)/src` "
34-
35-# jolt_main.c and the ABI's headers, as targets rather than bare paths — see
36-# the rules below.
37-_GLUE_C = "`realpath $(location :glue-c)`"
38-_GLUE_INCLUDE = "`realpath $(location :glue-include)`"
39-
40-_ABS_OUT = 'd=`dirname "$OUT"` && b=`basename "$OUT"` && d=`cd "$d" && pwd` && out="$d/$b"'
41-
42-# Somewhere to assemble in. Removed by the command that made it, on success;
43-# buck's own scratch space is not this.
44-_TMP = 'tmp=`mktemp -d`'
45-
46-# A babashka script, run in place: it loads scripts/frq/paths.clj beside it and
47-# resolves its own interpreter through scripts/bb, the DotSlash pin. Referenced
48-# rather than copied for exactly that reason — the tree around it is part of it.
49-export_file(
50- name = "build-jolt-boot.bb",
51- mode = "reference",
52-)
53-
54-# --- the UI half ------------------------------------------------------------
55-# The .so out of jolt-native's release, fetched by digest — which is what makes
56-# an APK buildable with no jolt-native checkout and no NDK anywhere on the
57-# machine. A genrule rather than a path, so the library's bytes are an input to
58-# what reads them: an action that shelled out to build it would have nothing to
59-# invalidate on and would serve the same stale object forever.
60-genrule(
61- name = "libvidya",
62- out = "libvidya.so",
63- cmd = "cp $(location toolchains//dist:libvidya-android)/libvidya.so \"$OUT\"",
64-)
65-
66-# The media plane, out of the same archive. Necessarily the same release:
67-# libjoltapp links both, and pairing one release's media plane with another's
68-# UI is a combination nothing has tested.
69-genrule(
70- name = "libjoltmoq",
71- out = "libjoltmoq.so",
72- cmd = "cp $(location toolchains//dist:libjoltmoq-android)/libjoltmoq.so \"$OUT\"",
73-)
74-
75-# jolt_main.c and the ABI's headers, from the glue archive of the same release.
76-# Targets rather than paths for the reason above — an input is the only thing
77-# buck can notice a change in.
78-genrule(
79- name = "glue-c",
80- out = "jolt_main.c",
81- cmd = "cp $(location toolchains//dist:android-glue)/android/jolt_main.c \"$OUT\"",
82-)
83-
84-# A directory of headers rather than a filegroup: a filegroup keeps each file
85-# at its own path inside the output, so `-I` would have to name the staging
86-# directory again.
87-genrule(
88- name = "glue-include",
89- out = "include",
90- cmd = "cp -r $(location toolchains//dist:android-glue)/include \"$OUT\"",
91-)
92-
93-# The C++ runtime, out of the same NDK the glue is compiled with.
94-#
95-# openh264 is C++, and its build script asks to be linked against
96-# `libc++_shared.so` by name — so libjoltmoq carries that as a DT_NEEDED. An
97-# app's linker namespace will not hand out the platform's own copy (there is no
98-# stable one to hand out), so the APK has to carry it, exactly as it carries
99-# OpenSSL below and for the same reason.
100-#
101-# Only when the media plane is packaged: nothing else here is C++.
102-genrule(
103- name = "libcxx",
104- out = "libc++_shared.so",
105- cmd = _ABS_OUT + " && " + _NDK_BIN + " && " +
106- "cp \"$ndk\"/../sysroot/usr/lib/aarch64-linux-android/libc++_shared.so \"$out\"",
107-)
108-
109-# --- the Jolt half ----------------------------------------------------------
110-# The boot image: frq's Scheme, cross-compiled to arm64 by Chez. The sources
111-# are an input so that editing one rebuilds this; the compile itself reads them
112-# through the deps.edn the script writes.
113-# The sources here are frq's own. The other two roots the image is compiled
114-# from — glimmer and glimmer-vidya, both out of the jolt cache — are outside
115-# this cell, and so are Chez's cross boot files and the pinned
116-# jolt itself. None of them can be an input, so the `buck` recipe hashes them
117-# and writes the digest below; naming it in the command is what puts them in
118-# this action's identity.
119-# jolt reaches this action as a manifest and a fetcher rather than as a
120-# program: both are inputs, so nothing here depends on what is installed where
121-# the compile runs, and a remote worker resolves the same pin — by the same
122-# digest — from the same place this machine would.
123-genrule(
124- name = "jolt-boot",
125- out = "boot",
126- srcs = ["//:jolt-sources"],
127- cmd = "# sources outside this cell: " + read_root_config("frq", "boot_stamp", "unknown") + "\n" +
128- "DOTSLASH=$(location toolchains//dist:dotslash)/dotslash " +
129- "JOLT_MANIFEST=$(location //scripts:jolt) " +
130- # The one source root the script cannot find for itself: the jolt
131- # cache is not an action input, and this is. A new release recompiles
132- # the image because of it.
133- _GLIMMER_VIDYA +
134- "$(location :build-jolt-boot.bb) \"$OUT\" >&2",
135-)
136-
137-# The image travels as a blob in an object file's data section; the
138-# _binary_jolt_boot_{start,end} symbols jolt_main.c reads are named after the
139-# input *path*, which is why this copies the file somewhere it can be called
140-# exactly `jolt.boot` before converting it.
141-genrule(
142- name = "jolt-boot-obj",
143- out = "jolt_boot.o",
144- cmd = _ABS_OUT + " && " +
145- _TMP + " && " + _NDK_BIN + " && " +
146- "cp $(location :jolt-boot)/jolt.boot \"$tmp/jolt.boot\" && " +
147- "( cd \"$tmp\" && \"$ndk\"/llvm-objcopy " +
148- "--input-target=binary --output-target=elf64-littleaarch64 " +
149- "--binary-architecture=aarch64 jolt.boot jolt_boot.o ) && " +
150- "cp \"$tmp/jolt_boot.o\" \"$out\" && rm -rf \"$tmp\"",
151-)
152-
153-# The glue: jolt-native's android/jolt_main.c over the boot image, linked
154-# against libvidya by name. --no-undefined is what makes a symbol the Scheme
155-# side registers but the ABI no longer exports a build failure here rather than
156-# a crash on the phone.
157-genrule(
158- name = "libjoltapp",
159- out = "libjoltapp.so",
160- cmd = _ABS_OUT + " && lib=`mktemp -d` && " +
161- "cp $(location :libvidya) \"$lib/libvidya.so\" && " +
162- "cp $(location :libjoltmoq) \"$lib/libjoltmoq.so\" && " +
163- _CC + " -shared -fPIC -O2 -o \"$out\" " +
164- _GLUE_C + " " +
165- "$(location :jolt-boot-obj) " +
166- "-I$(location :jolt-boot) " +
167- "-I" + _GLUE_INCLUDE + " " +
168- "-L\"$lib\" " +
169- _CHEZ + "/tarm64le/boot/tarm64le/libkernel.a " +
170- _CHEZ + "/lz4/lib/liblz4.a " +
171- "-lvidya -ljoltmoq -landroid -llog -lz -ldl -lm -Wl,--no-undefined && " +
172- "rm -rf \"$lib\"",
173-)
174-
175-# --- the Java half ----------------------------------------------------------
176-# Two classes: the photo chooser's result has to land somewhere and native code
177-# is not somewhere, and Camera2 has no C API worth the name — CameraCapture
178-# opens the camera in Java and pushes NV12 planes down to libjoltmoq over JNI.
179-# android.jar on the class path is where every android.* type comes from; the
180-# JDK's own java.* is what is left.
181-genrule(
182- name = "classes-dex",
183- out = "classes.dex",
184- srcs = glob(["java/**/*.java"]),
185- cmd = _ABS_OUT + " && " + _TMP + " && " +
186- "javac --release 17 --class-path " + _ANDROID_JAR + " -d \"$tmp/classes\" $SRCS && " +
187- "classes=`find \"$tmp/classes\" -name '*.class'` && " +
188- _TOOLS + "/d8 --min-api " + _API + " --output \"$tmp\" $classes && " +
189- "cp \"$tmp/classes.dex\" \"$out\" && rm -rf \"$tmp\"",
190-)
191-
192-# --- the package ------------------------------------------------------------
193-# The libraries are stored rather than deflated: the loader maps them straight
194-# out of the APK. The dex is read rather than mapped, so it may as well
195-# compress. OpenSSL travels with the app because the platform's own is not ours
196-# to load — an app's linker namespace refuses /system/lib64/libssl.so, and
197-# without one there is no TLS on the phone at all.
198-genrule(
199- name = "apk-unsigned",
200- out = "frq-unsigned.apk",
201- srcs = ["AndroidManifest.xml"],
202- cmd = _ABS_OUT + " && stage=`mktemp -d` && " +
203- "mkdir -p \"$stage/lib/arm64-v8a\" && " +
204- "cp $(location :libvidya) \"$stage/lib/arm64-v8a/libvidya.so\" && " +
205- "cp $(location :libjoltapp) \"$stage/lib/arm64-v8a/libjoltapp.so\" && " +
206- "cp $(location :libjoltmoq) \"$stage/lib/arm64-v8a/libjoltmoq.so\" && " +
207- "cp $(location :libcxx) \"$stage/lib/arm64-v8a/libc++_shared.so\" && " +
208- "cp " + _OPENSSL + "/libssl.so " + _OPENSSL + "/libcrypto.so \"$stage/lib/arm64-v8a/\" && " +
209- "cp $(location :classes-dex) \"$stage/classes.dex\" && " +
210- _TOOLS + "/aapt2 link -o \"$out\" -I " + _ANDROID_JAR + " " +
211- "--manifest $SRCS --min-sdk-version " + _API + " --target-sdk-version 36 " +
212- "--version-code 1 --version-name 0.1.0 >&2 && " +
213- "( cd \"$stage\" && zip -q -0 \"$out\" lib/arm64-v8a/libvidya.so " +
214- "lib/arm64-v8a/libjoltmoq.so lib/arm64-v8a/libc++_shared.so " +
215- "lib/arm64-v8a/libjoltapp.so lib/arm64-v8a/libssl.so lib/arm64-v8a/libcrypto.so && " +
216- "zip -q \"$out\" classes.dex ) && rm -rf \"$stage\"",
217-)
218-
219-# Aligned and signed with the debug key, which is generated on first use the
220-# way the SDK's own tools generate it.
221-genrule(
222- name = "apk",
223- out = "frq.apk",
224- cmd = _ABS_OUT + " && " + _TMP + " && " +
225- "ks=\"$HOME/.android/debug.keystore\" && " +
226- "if [ ! -f \"$ks\" ]; then mkdir -p \"$HOME/.android\" && " +
227- "keytool -genkeypair -v -keystore \"$ks\" -storepass android -keypass android " +
228- "-alias androiddebugkey -keyalg RSA -keysize 2048 -validity 10000 " +
229- "-dname 'CN=Android Debug,O=Android,C=US' >&2; fi && " +
230- _TOOLS + "/zipalign -f -p 4 $(location :apk-unsigned) \"$tmp/aligned.apk\" && " +
231- _TOOLS + "/apksigner sign --ks \"$ks\" --ks-key-alias androiddebugkey " +
232- "--ks-pass pass:android --key-pass pass:android --out \"$out\" \"$tmp/aligned.apk\" && " +
233- _TOOLS + "/apksigner verify \"$out\" >/dev/null && rm -rf \"$tmp\"",
234- visibility = ["PUBLIC"],
235-)
236-
237-# Does the pin resolve where the action runs, and does what it resolves to run
238-# there? Nothing depends on this; it is here to be asked by hand.
239-#
240-# buck2 build //android:jolt-fetch-check --remote-only --materializations=all \
241-# -c build.execution_platforms=root//platforms:remote -c "parser...->root//platforms:remote"
242-#
243-# It is what found the glibc floor: jolt needs 2.38, and the rbe-ubuntu22-04
244-# image this platform used to name ships 2.35, so the fetch succeeded and the
245-# binary would not start. The answer was the newer image, not a different pin.
246-genrule(
247- name = "jolt-fetch-check",
248- out = "report",
249- cmd = "jolt=`$(location toolchains//dist:dotslash)/dotslash -- fetch $(location //scripts:jolt)`; " +
250- "{ echo \"fetched: $jolt\"; " +
251- "cat /etc/os-release 2>/dev/null | head -1 || true; " +
252- "ldd --version 2>&1 | head -1 || true; " +
253- "echo '--- run ---'; \"$jolt\" --version; echo \"rc=$?\"; } > \"$OUT\" 2>&1 || true",
254-)
deleted android/build-apk.bb +0 -177
deleted file mode 100755
@@ -1,177 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/../scripts/bb" "$0" "$@"
4-)
5-
6-;; Glue the two halves of the frq Android app into an APK.
7-;;
8-;; libvidya.so the C ABI on Rust/egui, out of the pinned release, and the
9-;; NativeActivity's own library (it holds android-activity's
10-;; glue, so it owns the event loop)
11-;; libjoltmoq.so the AV media plane — MoQ over QUIC, Opus, H.264, Camera2
12-;; libjoltapp.so jolt-native's android/jolt_main.c plus frq's Jolt boot
13-;; image, dlopened by the above
14-;; libc++_shared.so the NDK's C++ runtime, which libjoltmoq names
15-;; classes.dex two Java classes: a picture chooser answers through
16-;; onActivityResult and a NativeActivity has nowhere to
17-;; deliver that, and Camera2 has no C API worth the name
18-;; libssl.so OpenSSL, because the platform's own is not ours to load: an
19-;; libcrypto.so app's linker namespace refuses /system/lib64/libssl.so, and
20-;; without one there is no TLS at all on the phone
21-;;
22-;; Neither half is built here beyond that last link: the UI library and the glue
23-;; come out of jolt-native's release, fetched by digest through the DotSlash
24-;; pins in scripts/, and the boot image from build-jolt-boot.bb. Both native
25-;; pieces are jolt-native's — only the boot image is frq's.
26-;;
27-;; build-apk.bb [build|install|run|log]
28-(require '[babashka.classpath :as cp])
29-(cp/add-classpath (str (babashka.fs/path (babashka.fs/parent *file*) ".." "scripts")))
30-(require '[frq.paths :as paths]
31- '[babashka.fs :as fs]
32- '[babashka.process :as p])
33-
34-(def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
35-(def action (or (first *command-line-args*) "build"))
36-
37-(def android-home (paths/env "ANDROID_HOME" (str (fs/path (fs/home) ".local" "share" "android-sdk"))))
38-(def ndk-home (paths/env "ANDROID_NDK_HOME" (str (fs/path (fs/home) ".local" "share" "android-ndk-r29"))))
39-(def chez (paths/env "CHEZ_ANDROID" (str (fs/path (fs/home) ".cache" "vidya-chez-android"))))
40-(def openssl (paths/env "OPENSSL_ANDROID" (str (fs/path (fs/home) ".cache" "frq-openssl-android" "lib"))))
41-(def build (fs/path root "android" "build"))
42-(def jolt-build (fs/path build "jolt"))
43-(def stage (fs/path build "stage"))
44-(def tools (fs/path android-home "build-tools" "36.0.0"))
45-(def android-jar (fs/path android-home "platforms" "android-36" "android.jar"))
46-(def adb (paths/env "ADB" (str (fs/path android-home "platform-tools" "adb"))))
47-(def ndk-bin (fs/path ndk-home "toolchains" "llvm" "prebuilt" "linux-x86_64" "bin"))
48-(def package "uk.nandi.frq")
49-(def activity (str package "/.FrqActivity"))
50-(def api "28")
51-(def clang (str (fs/path ndk-bin (str "aarch64-linux-android" api "-clang"))))
52-(def arm-lib (fs/path stage "lib" "arm64-v8a"))
53-
54-(paths/require-paths! "Android tool"
55- [clang android-jar
56- (fs/path tools "aapt2") (fs/path tools "zipalign")
57- (fs/path tools "apksigner") (fs/path tools "d8")
58- (fs/path openssl "libssl.so") (fs/path openssl "libcrypto.so")])
59-
60-;; --- the UI half -----------------------------------------------------------
61-;; The release's own object, and the glue beside it, both by digest: this build
62-;; compiles no Rust and needs no jolt-native checkout, exactly as the graph in
63-;; android/BUCK needs none.
64-(def vidya-so (paths/dist root "libvidya-android"))
65-;; The media plane, out of the same archive. The glue registers its symbols and
66-;; includes its header, so this is not optional beside that jolt_main.c: link
67-;; without it and --no-undefined says so.
68-(def joltmoq-so (paths/dist root "libjoltmoq-android"))
69-(def glue-c (paths/dist root "android-glue"))
70-(def glue-include (fs/path (fs/parent (fs/parent glue-c)) "include"))
71-(paths/require-paths! "library" [vidya-so joltmoq-so glue-c glue-include])
72-
73-;; --- the Jolt half ---------------------------------------------------------
74-(p/shell (str (fs/path root "android" "build-jolt-boot.bb")) (str jolt-build))
75-;; The boot image travels as a blob in the object file's data section; the
76-;; _binary_jolt_boot_{start,end} symbols jolt_main.c reads come from this.
77-(p/shell {:dir (str jolt-build)}
78- (str (fs/path ndk-bin "llvm-objcopy"))
79- "--input-target=binary"
80- "--output-target=elf64-littleaarch64"
81- "--binary-architecture=aarch64"
82- "jolt.boot" "jolt_boot.o")
83-
84-;; --- the Java half ---------------------------------------------------------
85-;; Two classes: the photo chooser's result has to land somewhere and native
86-;; code is not somewhere, and Camera2 has no C API worth the name. d8 turns
87-;; them into the classes.dex the runtime loads.
88-(def java-build (fs/path build "java"))
89-(fs/delete-tree java-build)
90-(fs/create-dirs (fs/path java-build "classes"))
91-;; android.jar on the class path is where every android.* type comes from; the
92-;; JDK's own java.* is what is left, and neither class uses anything of it that
93-;; Android does not have. (`-bootclasspath` would be the stricter way to say
94-;; that, and javac refuses it for a release this recent.)
95-;;
96-;; Every class under android/java, the way android/BUCK globs them: naming one
97-;; here left CameraCapture out of the dex, and libjoltmoq looks that class up
98-;; by name over JNI the moment a call starts the camera.
99-(apply p/shell "javac" "--release" "17"
100- "--class-path" (str android-jar)
101- "-d" (str (fs/path java-build "classes"))
102- (map str (fs/glob (fs/path root "android" "java") "**.java")))
103-(apply p/shell (str (fs/path tools "d8")) "--min-api" api "--output" (str java-build)
104- (map str (fs/glob (fs/path java-build "classes") "**.class")))
105-
106-(fs/delete-tree stage)
107-(fs/create-dirs arm-lib)
108-(fs/copy (fs/path java-build "classes.dex") (fs/path stage "classes.dex"))
109-(fs/copy vidya-so (fs/path arm-lib "libvidya.so"))
110-(fs/copy joltmoq-so (fs/path arm-lib "libjoltmoq.so"))
111-;; openh264 is C++ and asks to be linked against libc++_shared.so by name, so
112-;; libjoltmoq carries it as a DT_NEEDED and the APK has to carry the object —
113-;; an app's linker namespace will not hand out the platform's own.
114-(fs/copy (fs/path ndk-bin ".." "sysroot" "usr" "lib" "aarch64-linux-android"
115- "libc++_shared.so")
116- (fs/path arm-lib "libc++_shared.so"))
117-;; jolt.mvn-http dlopens these by name at first use; beside the app's own
118-;; libraries is where an app's namespace will answer for that name.
119-(doseq [lib ["libssl.so" "libcrypto.so"]]
120- (fs/copy (fs/path openssl lib) (fs/path arm-lib lib)))
121-
122-(p/shell clang "-shared" "-fPIC" "-O2"
123- "-o" (str (fs/path arm-lib "libjoltapp.so"))
124- (str glue-c)
125- (str (fs/path jolt-build "jolt_boot.o"))
126- (str "-I" jolt-build)
127- (str "-I" glue-include)
128- (str "-L" arm-lib)
129- (str (fs/path chez "tarm64le" "boot" "tarm64le" "libkernel.a"))
130- (str (fs/path chez "lz4" "lib" "liblz4.a"))
131- "-lvidya" "-ljoltmoq" "-landroid" "-llog" "-lz" "-ldl" "-lm"
132- "-Wl,--no-undefined")
133-
134-;; --- the APK ---------------------------------------------------------------
135-(def unaligned (fs/path build "frq-unaligned.apk"))
136-(def aligned (fs/path build "frq-aligned.apk"))
137-(def apk (fs/path build "frq.apk"))
138-(run! fs/delete-if-exists [unaligned aligned apk])
139-(p/shell (str (fs/path tools "aapt2")) "link"
140- "-o" (str unaligned)
141- "-I" (str android-jar)
142- "--manifest" (str (fs/path root "android" "AndroidManifest.xml"))
143- "--min-sdk-version" api
144- "--target-sdk-version" "36"
145- "--version-code" "1"
146- "--version-name" "0.1.0")
147-;; Stored, not deflated: the loader maps these straight out of the APK.
148-(p/shell {:dir (str stage)} "zip" "-q" "-0" (str unaligned)
149- "lib/arm64-v8a/libvidya.so" "lib/arm64-v8a/libjoltmoq.so"
150- "lib/arm64-v8a/libc++_shared.so" "lib/arm64-v8a/libjoltapp.so"
151- "lib/arm64-v8a/libssl.so" "lib/arm64-v8a/libcrypto.so")
152-;; The dex is read by the runtime rather than mapped, so it may as well deflate.
153-(p/shell {:dir (str stage)} "zip" "-q" (str unaligned) "classes.dex")
154-(p/shell (str (fs/path tools "zipalign")) "-f" "-p" "4" (str unaligned) (str aligned))
155-
156-(def keystore (fs/path (fs/home) ".android" "debug.keystore"))
157-(when-not (fs/exists? keystore)
158- (fs/create-dirs (fs/parent keystore))
159- (p/shell "keytool" "-genkeypair" "-v"
160- "-keystore" (str keystore) "-storepass" "android" "-keypass" "android"
161- "-alias" "androiddebugkey" "-keyalg" "RSA" "-keysize" "2048"
162- "-validity" "10000"
163- "-dname" "CN=Android Debug,O=Android,C=US"))
164-(p/shell (str (fs/path tools "apksigner")) "sign"
165- "--ks" (str keystore) "--ks-key-alias" "androiddebugkey"
166- "--ks-pass" "pass:android" "--key-pass" "pass:android"
167- "--out" (str apk) (str aligned))
168-(p/shell {:out :string} (str (fs/path tools "apksigner")) "verify" (str apk))
169-
170-(case action
171- "build" (println (str apk))
172- "install" (p/shell adb "install" "-r" (str apk))
173- "run" (do (p/shell adb "install" "-r" (str apk))
174- (p/shell adb "shell" "am" "force-stop" package)
175- (p/shell adb "shell" "am" "start" "-n" activity))
176- "log" (p/shell adb "logcat" "-s" "VidyaJolt" "Vidya")
177- (paths/die "usage: build-apk.bb [build|install|run|log]"))
deleted file mode 100755
@@ -1,177 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/../scripts/bb" "$0" "$@"
4-)
5-
6-;; Glue the two halves of the frq Android app into an APK.
7-;;
8-;; libvidya.so the C ABI on Rust/egui, out of the pinned release, and the
9-;; NativeActivity's own library (it holds android-activity's
10-;; glue, so it owns the event loop)
11-;; libjoltmoq.so the AV media plane — MoQ over QUIC, Opus, H.264, Camera2
12-;; libjoltapp.so jolt-native's android/jolt_main.c plus frq's Jolt boot
13-;; image, dlopened by the above
14-;; libc++_shared.so the NDK's C++ runtime, which libjoltmoq names
15-;; classes.dex two Java classes: a picture chooser answers through
16-;; onActivityResult and a NativeActivity has nowhere to
17-;; deliver that, and Camera2 has no C API worth the name
18-;; libssl.so OpenSSL, because the platform's own is not ours to load: an
19-;; libcrypto.so app's linker namespace refuses /system/lib64/libssl.so, and
20-;; without one there is no TLS at all on the phone
21-;;
22-;; Neither half is built here beyond that last link: the UI library and the glue
23-;; come out of jolt-native's release, fetched by digest through the DotSlash
24-;; pins in scripts/, and the boot image from build-jolt-boot.bb. Both native
25-;; pieces are jolt-native's — only the boot image is frq's.
26-;;
27-;; build-apk.bb [build|install|run|log]
28-(require '[babashka.classpath :as cp])
29-(cp/add-classpath (str (babashka.fs/path (babashka.fs/parent *file*) ".." "scripts")))
30-(require '[frq.paths :as paths]
31- '[babashka.fs :as fs]
32- '[babashka.process :as p])
33-
34-(def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
35-(def action (or (first *command-line-args*) "build"))
36-
37-(def android-home (paths/env "ANDROID_HOME" (str (fs/path (fs/home) ".local" "share" "android-sdk"))))
38-(def ndk-home (paths/env "ANDROID_NDK_HOME" (str (fs/path (fs/home) ".local" "share" "android-ndk-r29"))))
39-(def chez (paths/env "CHEZ_ANDROID" (str (fs/path (fs/home) ".cache" "vidya-chez-android"))))
40-(def openssl (paths/env "OPENSSL_ANDROID" (str (fs/path (fs/home) ".cache" "frq-openssl-android" "lib"))))
41-(def build (fs/path root "android" "build"))
42-(def jolt-build (fs/path build "jolt"))
43-(def stage (fs/path build "stage"))
44-(def tools (fs/path android-home "build-tools" "36.0.0"))
45-(def android-jar (fs/path android-home "platforms" "android-36" "android.jar"))
46-(def adb (paths/env "ADB" (str (fs/path android-home "platform-tools" "adb"))))
47-(def ndk-bin (fs/path ndk-home "toolchains" "llvm" "prebuilt" "linux-x86_64" "bin"))
48-(def package "uk.nandi.frq")
49-(def activity (str package "/.FrqActivity"))
50-(def api "28")
51-(def clang (str (fs/path ndk-bin (str "aarch64-linux-android" api "-clang"))))
52-(def arm-lib (fs/path stage "lib" "arm64-v8a"))
53-
54-(paths/require-paths! "Android tool"
55- [clang android-jar
56- (fs/path tools "aapt2") (fs/path tools "zipalign")
57- (fs/path tools "apksigner") (fs/path tools "d8")
58- (fs/path openssl "libssl.so") (fs/path openssl "libcrypto.so")])
59-
60-;; --- the UI half -----------------------------------------------------------
61-;; The release's own object, and the glue beside it, both by digest: this build
62-;; compiles no Rust and needs no jolt-native checkout, exactly as the graph in
63-;; android/BUCK needs none.
64-(def vidya-so (paths/dist root "libvidya-android"))
65-;; The media plane, out of the same archive. The glue registers its symbols and
66-;; includes its header, so this is not optional beside that jolt_main.c: link
67-;; without it and --no-undefined says so.
68-(def joltmoq-so (paths/dist root "libjoltmoq-android"))
69-(def glue-c (paths/dist root "android-glue"))
70-(def glue-include (fs/path (fs/parent (fs/parent glue-c)) "include"))
71-(paths/require-paths! "library" [vidya-so joltmoq-so glue-c glue-include])
72-
73-;; --- the Jolt half ---------------------------------------------------------
74-(p/shell (str (fs/path root "android" "build-jolt-boot.bb")) (str jolt-build))
75-;; The boot image travels as a blob in the object file's data section; the
76-;; _binary_jolt_boot_{start,end} symbols jolt_main.c reads come from this.
77-(p/shell {:dir (str jolt-build)}
78- (str (fs/path ndk-bin "llvm-objcopy"))
79- "--input-target=binary"
80- "--output-target=elf64-littleaarch64"
81- "--binary-architecture=aarch64"
82- "jolt.boot" "jolt_boot.o")
83-
84-;; --- the Java half ---------------------------------------------------------
85-;; Two classes: the photo chooser's result has to land somewhere and native
86-;; code is not somewhere, and Camera2 has no C API worth the name. d8 turns
87-;; them into the classes.dex the runtime loads.
88-(def java-build (fs/path build "java"))
89-(fs/delete-tree java-build)
90-(fs/create-dirs (fs/path java-build "classes"))
91-;; android.jar on the class path is where every android.* type comes from; the
92-;; JDK's own java.* is what is left, and neither class uses anything of it that
93-;; Android does not have. (`-bootclasspath` would be the stricter way to say
94-;; that, and javac refuses it for a release this recent.)
95-;;
96-;; Every class under android/java, the way android/BUCK globs them: naming one
97-;; here left CameraCapture out of the dex, and libjoltmoq looks that class up
98-;; by name over JNI the moment a call starts the camera.
99-(apply p/shell "javac" "--release" "17"
100- "--class-path" (str android-jar)
101- "-d" (str (fs/path java-build "classes"))
102- (map str (fs/glob (fs/path root "android" "java") "**.java")))
103-(apply p/shell (str (fs/path tools "d8")) "--min-api" api "--output" (str java-build)
104- (map str (fs/glob (fs/path java-build "classes") "**.class")))
105-
106-(fs/delete-tree stage)
107-(fs/create-dirs arm-lib)
108-(fs/copy (fs/path java-build "classes.dex") (fs/path stage "classes.dex"))
109-(fs/copy vidya-so (fs/path arm-lib "libvidya.so"))
110-(fs/copy joltmoq-so (fs/path arm-lib "libjoltmoq.so"))
111-;; openh264 is C++ and asks to be linked against libc++_shared.so by name, so
112-;; libjoltmoq carries it as a DT_NEEDED and the APK has to carry the object —
113-;; an app's linker namespace will not hand out the platform's own.
114-(fs/copy (fs/path ndk-bin ".." "sysroot" "usr" "lib" "aarch64-linux-android"
115- "libc++_shared.so")
116- (fs/path arm-lib "libc++_shared.so"))
117-;; jolt.mvn-http dlopens these by name at first use; beside the app's own
118-;; libraries is where an app's namespace will answer for that name.
119-(doseq [lib ["libssl.so" "libcrypto.so"]]
120- (fs/copy (fs/path openssl lib) (fs/path arm-lib lib)))
121-
122-(p/shell clang "-shared" "-fPIC" "-O2"
123- "-o" (str (fs/path arm-lib "libjoltapp.so"))
124- (str glue-c)
125- (str (fs/path jolt-build "jolt_boot.o"))
126- (str "-I" jolt-build)
127- (str "-I" glue-include)
128- (str "-L" arm-lib)
129- (str (fs/path chez "tarm64le" "boot" "tarm64le" "libkernel.a"))
130- (str (fs/path chez "lz4" "lib" "liblz4.a"))
131- "-lvidya" "-ljoltmoq" "-landroid" "-llog" "-lz" "-ldl" "-lm"
132- "-Wl,--no-undefined")
133-
134-;; --- the APK ---------------------------------------------------------------
135-(def unaligned (fs/path build "frq-unaligned.apk"))
136-(def aligned (fs/path build "frq-aligned.apk"))
137-(def apk (fs/path build "frq.apk"))
138-(run! fs/delete-if-exists [unaligned aligned apk])
139-(p/shell (str (fs/path tools "aapt2")) "link"
140- "-o" (str unaligned)
141- "-I" (str android-jar)
142- "--manifest" (str (fs/path root "android" "AndroidManifest.xml"))
143- "--min-sdk-version" api
144- "--target-sdk-version" "36"
145- "--version-code" "1"
146- "--version-name" "0.1.0")
147-;; Stored, not deflated: the loader maps these straight out of the APK.
148-(p/shell {:dir (str stage)} "zip" "-q" "-0" (str unaligned)
149- "lib/arm64-v8a/libvidya.so" "lib/arm64-v8a/libjoltmoq.so"
150- "lib/arm64-v8a/libc++_shared.so" "lib/arm64-v8a/libjoltapp.so"
151- "lib/arm64-v8a/libssl.so" "lib/arm64-v8a/libcrypto.so")
152-;; The dex is read by the runtime rather than mapped, so it may as well deflate.
153-(p/shell {:dir (str stage)} "zip" "-q" (str unaligned) "classes.dex")
154-(p/shell (str (fs/path tools "zipalign")) "-f" "-p" "4" (str unaligned) (str aligned))
155-
156-(def keystore (fs/path (fs/home) ".android" "debug.keystore"))
157-(when-not (fs/exists? keystore)
158- (fs/create-dirs (fs/parent keystore))
159- (p/shell "keytool" "-genkeypair" "-v"
160- "-keystore" (str keystore) "-storepass" "android" "-keypass" "android"
161- "-alias" "androiddebugkey" "-keyalg" "RSA" "-keysize" "2048"
162- "-validity" "10000"
163- "-dname" "CN=Android Debug,O=Android,C=US"))
164-(p/shell (str (fs/path tools "apksigner")) "sign"
165- "--ks" (str keystore) "--ks-key-alias" "androiddebugkey"
166- "--ks-pass" "pass:android" "--key-pass" "pass:android"
167- "--out" (str apk) (str aligned))
168-(p/shell {:out :string} (str (fs/path tools "apksigner")) "verify" (str apk))
169-
170-(case action
171- "build" (println (str apk))
172- "install" (p/shell adb "install" "-r" (str apk))
173- "run" (do (p/shell adb "install" "-r" (str apk))
174- (p/shell adb "shell" "am" "force-stop" package)
175- (p/shell adb "shell" "am" "start" "-n" activity))
176- "log" (p/shell adb "logcat" "-s" "VidyaJolt" "Vidya")
177- (paths/die "usage: build-apk.bb [build|install|run|log]"))
deleted android/build-jolt-boot.bb +0 -180
deleted file mode 100755
@@ -1,180 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/../scripts/bb" "$0" "$@"
4-)
5-
6-;; frq's Scheme, cross-compiled to an arm64 Chez boot image.
7-;;
8-;; build-jolt-boot.bb OUTPUT_DIRECTORY build the image
9-;; build-jolt-boot.bb --stamp print what it would be built from
10-;;
11-;; The image is built from :paths alone — there is no dependency resolution
12-;; inside a cross compile — so every source root deps.edn would have resolved
13-;; is named here instead. Two of them are git dependencies, which means the
14-;; jolt cache rather than a checkout; the shas come out of deps.edn so there is
15-;; one place to bump them.
16-(require '[babashka.classpath :as cp])
17-(cp/add-classpath (str (babashka.fs/path (babashka.fs/parent *file*) ".." "scripts")))
18-(require '[frq.paths :as paths]
19- '[babashka.fs :as fs]
20- '[babashka.process :as p]
21- '[clojure.string :as str])
22-
23-(def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
24-(def args *command-line-args*)
25-(def stamp-only? (= "--stamp" (first args)))
26-
27-;; The DotSlash-pinned jolt, not whatever is on PATH: an upstream jolt cannot
28-;; open a TLS connection on Android — it reads the socket address out of
29-;; `struct addrinfo` at glibc's offset, which is Bionic's `ai_canonname` — so a
30-;; build made with one produces an APK that cannot sign in or send a picture.
31-;; Override with JOLT= to use another.
32-;;
33-;; DOTSLASH and JOLT_MANIFEST are set when buck runs this: the manifest and the
34-;; fetcher are inputs to that action, so the machine running it needs neither
35-;; jolt nor DotSlash installed, and a remote worker resolves the same pin
36-;; against the same digest. Without them the shim beside this script answers,
37-;; which is what a person at a terminal gets.
38-(def jolt
39- (or (paths/env "JOLT" nil)
40- (let [dotslash (paths/env "DOTSLASH" nil)
41- manifest (paths/env "JOLT_MANIFEST" nil)]
42- (if (and dotslash manifest)
43- (paths/out dotslash "--" "fetch" manifest)
44- (str (fs/path root "scripts" "jolt"))))))
45-
46-;; The two source roots that are not this repo's, asked of jolt rather than
47-;; guessed at. `jolt path` prints what it resolved deps.edn to, which is the
48-;; only thing that knows where a git dependency landed: a plain :git/sha goes
49-;; to one cache layout and one with :deps/root to another, and glimmer and
50-;; glimmer-vidya are one of each.
51-;;
52-;; GLIMMER and GLIMMER_VIDYA name them instead when a caller already knows.
53-;; buck sets the second: the jolt cache cannot be an action input, so that
54-;; build hands over the release archive it fetched by digest, and with both set
55-;; nothing here shells out at all.
56-(def roots
57- (delay
58- ;; From this tree, whatever directory the caller was in: deps.edn is what
59- ;; `path` reads.
60- (str/split (str/trim (:out (p/shell {:out :string :dir root} jolt "path"))) #":")))
61-
62-(defn root-of [k env pred]
63- (or (paths/env env nil)
64- (first (filter pred @roots))
65- (paths/die (str "jolt resolved no " (name k) " source root")
66- "check the :deps in deps.edn")))
67-
68-;; Matched by name rather than by shape: a cache path carries the repo, the sha
69-;; and — for a dependency with a :deps/root — the root inside it, and which of
70-;; those it ends with is jolt's business, not this script's.
71-(defn names? [root s] (str/includes? root s))
72-
73-(def glimmer-vidya
74- (root-of :glimmer-vidya "GLIMMER_VIDYA" #(names? % "glimmer-vidya")))
75-(def glimmer
76- (root-of :glimmer "GLIMMER" #(and (names? % "glimmer")
77- (not (names? % "glimmer-vidya")))))
78-
79-(paths/require-paths! "Jolt source root" [glimmer glimmer-vidya])
80-
81-(def module (paths/env "MODULE" "frq.app"))
82-(def chez (paths/env "CHEZ_ANDROID" (str (fs/path (fs/home) ".cache" "vidya-chez-android"))))
83-(def host-scheme (str (fs/path chez "ta6le" "bin" "ta6le" "scheme")))
84-(def target-boot (fs/path chez "boot" "tarm64le"))
85-(def xpatch (str (fs/path chez "xc-tarm64le" "s" "xpatch")))
86-
87-(paths/require-paths! "Android Chez artifact"
88- [host-scheme (fs/path target-boot "petite.boot")
89- (fs/path target-boot "scheme.boot")
90- (fs/path target-boot "scheme.h") xpatch]
91- "Build Chez's tarm64le cross target first.")
92-
93-(when-not (or (fs/executable? jolt) (fs/which jolt))
94- (paths/die (str "Jolt executable not found: " jolt)))
95-
96-;; The boot image is a pure function of the Scheme sources, the module name,
97-;; the flat-split flag and Chez's own boot files — all static. Hash them, and
98-;; skip the whole thing when the stamp still matches: a Rust-only APK rebuild
99-;; has no reason to spend fifteen single-threaded seconds recompiling Scheme.
100-;;
101-;; The flag is part of the stamp on purpose. JOLT_NO_FLAT_SPLIT changes the
102-;; shape of what `jolt build` emits, so an app.build/ left by an ordinary build
103-;; is not reusable here; a stamp miss wipes the tree below, which is what the
104-;; unconditional delete used to be defending against.
105-
106-;; The hash itself. Every input is hashed here rather than shelled out to
107-;; sha256sum, so the stamp is one function to read.
108-(defn sha256 [^bytes bs]
109- (->> (.digest (java.security.MessageDigest/getInstance "SHA-256") bs)
110- (map #(format "%02x" (bit-and % 0xff)))
111- (apply str)))
112-
113-(defn file-line [f]
114- (str (sha256 (fs/read-all-bytes (str f))) " " f))
115-
116-(defn stamp []
117- (let [sources (->> [(fs/path root "src") glimmer glimmer-vidya]
118- (mapcat #(fs/glob % "**.{jolt,edn}"))
119- (map str)
120- sort)
121- lines (concat [module "JOLT_NO_FLAT_SPLIT=1"
122- (try (paths/out jolt "--version") (catch Exception _ ""))]
123- (map file-line sources)
124- (map file-line [(fs/path target-boot "petite.boot")
125- (fs/path target-boot "scheme.boot")
126- xpatch]))]
127- (sha256 (.getBytes (str/join "\n" lines) "UTF-8"))))
128-
129-;; buck needs this before the work rather than after: the sources it hashes
130-;; live in the jolt cache and in jolt-native, outside this cell, so nothing
131-;; else makes them reach an action's digest. See the `buck` recipe in the
132-;; justfile.
133-(when stamp-only?
134- (println (stamp))
135- (System/exit 0))
136-
137-(def out-dir (or (first args)
138- (paths/die "usage: build-jolt-boot.bb OUTPUT_DIRECTORY | --stamp")))
139-(def stamp-file (fs/path out-dir "jolt.boot.stamp"))
140-(def want (stamp))
141-
142-(when (and (fs/exists? (fs/path out-dir "jolt.boot"))
143- (fs/exists? (fs/path out-dir "scheme.h"))
144- (fs/exists? stamp-file)
145- (= want (str/trim (slurp (str stamp-file)))))
146- (binding [*out* *err*] (println "jolt boot image up to date"))
147- (System/exit 0))
148-
149-(fs/delete-if-exists stamp-file)
150-(fs/delete-tree (fs/path out-dir "project"))
151-(fs/delete-tree (fs/path out-dir "cross"))
152-(fs/create-dirs (fs/path out-dir "project"))
153-(fs/create-dirs (fs/path out-dir "cross"))
154-(spit (str (fs/path out-dir "project" "deps.edn"))
155- (str "{:paths [\"" (fs/path root "src") "\" \"" glimmer "\" \"" glimmer-vidya "\"]}\n"))
156-
157-(p/shell {:dir (str (fs/path out-dir "project"))
158- :extra-env {"JOLT_NO_FLAT_SPLIT" "1"}}
159- jolt "build" "-m" module "-o" "app")
160-
161-(spit (str (fs/path out-dir "cross" "compile.ss"))
162- (str "(import (chezscheme))\n"
163- "(load \"" xpatch "\")\n"
164- "(optimize-level 2)\n"
165- "(generate-inspector-information #f)\n"
166- "(compile-file \"" (fs/path out-dir "project" "app.build" "flat.ss") "\""
167- " \"" (fs/path out-dir "cross" "flat.so") "\")\n"
168- "(make-boot-file \"" (fs/path out-dir "jolt.boot") "\" '()\n"
169- " \"" (fs/path target-boot "petite.boot") "\"\n"
170- " \"" (fs/path target-boot "scheme.boot") "\"\n"
171- " \"" (fs/path out-dir "cross" "flat.so") "\")\n"))
172-
173-(p/shell {:extra-env {"SCHEMEHEAPDIRS" (str (fs/path chez "ta6le" "boot" "ta6le"))}}
174- host-scheme "--script" (str (fs/path out-dir "cross" "compile.ss")))
175-
176-(fs/copy (fs/path target-boot "scheme.h") (fs/path out-dir "scheme.h")
177- {:replace-existing true})
178-
179-;; Last, so an interrupted build leaves no stamp and the next run redoes it.
180-(spit (str stamp-file) (str want "\n"))
deleted file mode 100755
@@ -1,180 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/../scripts/bb" "$0" "$@"
4-)
5-
6-;; frq's Scheme, cross-compiled to an arm64 Chez boot image.
7-;;
8-;; build-jolt-boot.bb OUTPUT_DIRECTORY build the image
9-;; build-jolt-boot.bb --stamp print what it would be built from
10-;;
11-;; The image is built from :paths alone — there is no dependency resolution
12-;; inside a cross compile — so every source root deps.edn would have resolved
13-;; is named here instead. Two of them are git dependencies, which means the
14-;; jolt cache rather than a checkout; the shas come out of deps.edn so there is
15-;; one place to bump them.
16-(require '[babashka.classpath :as cp])
17-(cp/add-classpath (str (babashka.fs/path (babashka.fs/parent *file*) ".." "scripts")))
18-(require '[frq.paths :as paths]
19- '[babashka.fs :as fs]
20- '[babashka.process :as p]
21- '[clojure.string :as str])
22-
23-(def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
24-(def args *command-line-args*)
25-(def stamp-only? (= "--stamp" (first args)))
26-
27-;; The DotSlash-pinned jolt, not whatever is on PATH: an upstream jolt cannot
28-;; open a TLS connection on Android — it reads the socket address out of
29-;; `struct addrinfo` at glibc's offset, which is Bionic's `ai_canonname` — so a
30-;; build made with one produces an APK that cannot sign in or send a picture.
31-;; Override with JOLT= to use another.
32-;;
33-;; DOTSLASH and JOLT_MANIFEST are set when buck runs this: the manifest and the
34-;; fetcher are inputs to that action, so the machine running it needs neither
35-;; jolt nor DotSlash installed, and a remote worker resolves the same pin
36-;; against the same digest. Without them the shim beside this script answers,
37-;; which is what a person at a terminal gets.
38-(def jolt
39- (or (paths/env "JOLT" nil)
40- (let [dotslash (paths/env "DOTSLASH" nil)
41- manifest (paths/env "JOLT_MANIFEST" nil)]
42- (if (and dotslash manifest)
43- (paths/out dotslash "--" "fetch" manifest)
44- (str (fs/path root "scripts" "jolt"))))))
45-
46-;; The two source roots that are not this repo's, asked of jolt rather than
47-;; guessed at. `jolt path` prints what it resolved deps.edn to, which is the
48-;; only thing that knows where a git dependency landed: a plain :git/sha goes
49-;; to one cache layout and one with :deps/root to another, and glimmer and
50-;; glimmer-vidya are one of each.
51-;;
52-;; GLIMMER and GLIMMER_VIDYA name them instead when a caller already knows.
53-;; buck sets the second: the jolt cache cannot be an action input, so that
54-;; build hands over the release archive it fetched by digest, and with both set
55-;; nothing here shells out at all.
56-(def roots
57- (delay
58- ;; From this tree, whatever directory the caller was in: deps.edn is what
59- ;; `path` reads.
60- (str/split (str/trim (:out (p/shell {:out :string :dir root} jolt "path"))) #":")))
61-
62-(defn root-of [k env pred]
63- (or (paths/env env nil)
64- (first (filter pred @roots))
65- (paths/die (str "jolt resolved no " (name k) " source root")
66- "check the :deps in deps.edn")))
67-
68-;; Matched by name rather than by shape: a cache path carries the repo, the sha
69-;; and — for a dependency with a :deps/root — the root inside it, and which of
70-;; those it ends with is jolt's business, not this script's.
71-(defn names? [root s] (str/includes? root s))
72-
73-(def glimmer-vidya
74- (root-of :glimmer-vidya "GLIMMER_VIDYA" #(names? % "glimmer-vidya")))
75-(def glimmer
76- (root-of :glimmer "GLIMMER" #(and (names? % "glimmer")
77- (not (names? % "glimmer-vidya")))))
78-
79-(paths/require-paths! "Jolt source root" [glimmer glimmer-vidya])
80-
81-(def module (paths/env "MODULE" "frq.app"))
82-(def chez (paths/env "CHEZ_ANDROID" (str (fs/path (fs/home) ".cache" "vidya-chez-android"))))
83-(def host-scheme (str (fs/path chez "ta6le" "bin" "ta6le" "scheme")))
84-(def target-boot (fs/path chez "boot" "tarm64le"))
85-(def xpatch (str (fs/path chez "xc-tarm64le" "s" "xpatch")))
86-
87-(paths/require-paths! "Android Chez artifact"
88- [host-scheme (fs/path target-boot "petite.boot")
89- (fs/path target-boot "scheme.boot")
90- (fs/path target-boot "scheme.h") xpatch]
91- "Build Chez's tarm64le cross target first.")
92-
93-(when-not (or (fs/executable? jolt) (fs/which jolt))
94- (paths/die (str "Jolt executable not found: " jolt)))
95-
96-;; The boot image is a pure function of the Scheme sources, the module name,
97-;; the flat-split flag and Chez's own boot files — all static. Hash them, and
98-;; skip the whole thing when the stamp still matches: a Rust-only APK rebuild
99-;; has no reason to spend fifteen single-threaded seconds recompiling Scheme.
100-;;
101-;; The flag is part of the stamp on purpose. JOLT_NO_FLAT_SPLIT changes the
102-;; shape of what `jolt build` emits, so an app.build/ left by an ordinary build
103-;; is not reusable here; a stamp miss wipes the tree below, which is what the
104-;; unconditional delete used to be defending against.
105-
106-;; The hash itself. Every input is hashed here rather than shelled out to
107-;; sha256sum, so the stamp is one function to read.
108-(defn sha256 [^bytes bs]
109- (->> (.digest (java.security.MessageDigest/getInstance "SHA-256") bs)
110- (map #(format "%02x" (bit-and % 0xff)))
111- (apply str)))
112-
113-(defn file-line [f]
114- (str (sha256 (fs/read-all-bytes (str f))) " " f))
115-
116-(defn stamp []
117- (let [sources (->> [(fs/path root "src") glimmer glimmer-vidya]
118- (mapcat #(fs/glob % "**.{jolt,edn}"))
119- (map str)
120- sort)
121- lines (concat [module "JOLT_NO_FLAT_SPLIT=1"
122- (try (paths/out jolt "--version") (catch Exception _ ""))]
123- (map file-line sources)
124- (map file-line [(fs/path target-boot "petite.boot")
125- (fs/path target-boot "scheme.boot")
126- xpatch]))]
127- (sha256 (.getBytes (str/join "\n" lines) "UTF-8"))))
128-
129-;; buck needs this before the work rather than after: the sources it hashes
130-;; live in the jolt cache and in jolt-native, outside this cell, so nothing
131-;; else makes them reach an action's digest. See the `buck` recipe in the
132-;; justfile.
133-(when stamp-only?
134- (println (stamp))
135- (System/exit 0))
136-
137-(def out-dir (or (first args)
138- (paths/die "usage: build-jolt-boot.bb OUTPUT_DIRECTORY | --stamp")))
139-(def stamp-file (fs/path out-dir "jolt.boot.stamp"))
140-(def want (stamp))
141-
142-(when (and (fs/exists? (fs/path out-dir "jolt.boot"))
143- (fs/exists? (fs/path out-dir "scheme.h"))
144- (fs/exists? stamp-file)
145- (= want (str/trim (slurp (str stamp-file)))))
146- (binding [*out* *err*] (println "jolt boot image up to date"))
147- (System/exit 0))
148-
149-(fs/delete-if-exists stamp-file)
150-(fs/delete-tree (fs/path out-dir "project"))
151-(fs/delete-tree (fs/path out-dir "cross"))
152-(fs/create-dirs (fs/path out-dir "project"))
153-(fs/create-dirs (fs/path out-dir "cross"))
154-(spit (str (fs/path out-dir "project" "deps.edn"))
155- (str "{:paths [\"" (fs/path root "src") "\" \"" glimmer "\" \"" glimmer-vidya "\"]}\n"))
156-
157-(p/shell {:dir (str (fs/path out-dir "project"))
158- :extra-env {"JOLT_NO_FLAT_SPLIT" "1"}}
159- jolt "build" "-m" module "-o" "app")
160-
161-(spit (str (fs/path out-dir "cross" "compile.ss"))
162- (str "(import (chezscheme))\n"
163- "(load \"" xpatch "\")\n"
164- "(optimize-level 2)\n"
165- "(generate-inspector-information #f)\n"
166- "(compile-file \"" (fs/path out-dir "project" "app.build" "flat.ss") "\""
167- " \"" (fs/path out-dir "cross" "flat.so") "\")\n"
168- "(make-boot-file \"" (fs/path out-dir "jolt.boot") "\" '()\n"
169- " \"" (fs/path target-boot "petite.boot") "\"\n"
170- " \"" (fs/path target-boot "scheme.boot") "\"\n"
171- " \"" (fs/path out-dir "cross" "flat.so") "\")\n"))
172-
173-(p/shell {:extra-env {"SCHEMEHEAPDIRS" (str (fs/path chez "ta6le" "boot" "ta6le"))}}
174- host-scheme "--script" (str (fs/path out-dir "cross" "compile.ss")))
175-
176-(fs/copy (fs/path target-boot "scheme.h") (fs/path out-dir "scheme.h")
177- {:replace-existing true})
178-
179-;; Last, so an interrupted build leaves no stamp and the next run redoes it.
180-(spit (str stamp-file) (str want "\n"))
modified deps.edn +4 -3
@@ -41,9 +41,10 @@
4141 ;; with cells under it — so `frq.tui` requires it after `frq.app`
4242 ;; and renders the hiccup that is already written.
4343 ;;
44- ;; A path rather than a sha because the backend is not in a
45- ;; jolt-native release yet; it wants the checkout beside this one,
46- ;; and `libjolttui.so` on the library path:
44+ ;; A path rather than a sha, like glimmer-vidya's would be if this
45+ ;; alias were the way in: `just tui` builds jolt-native out of the
46+ ;; flake and hands both Jolt halves over with -Sdeps, so this is for
47+ ;; a checkout beside the tree and nothing else reads it.
4748 ;;
4849 ;; just tui
4950 :tui {:extra-deps {nandi/glimmer-tui
@@ -41,9 +41,10 @@
41 ;; with cells under it — so `frq.tui` requires it after `frq.app`41 ;; with cells under it — so `frq.tui` requires it after `frq.app`
42 ;; and renders the hiccup that is already written.42 ;; and renders the hiccup that is already written.
43 ;;43 ;;
44- ;; A path rather than a sha because the backend is not in a44+ ;; A path rather than a sha, like glimmer-vidya's would be if this
45- ;; jolt-native release yet; it wants the checkout beside this one,45+ ;; alias were the way in: `just tui` builds jolt-native out of the
46- ;; and `libjolttui.so` on the library path:46+ ;; flake and hands both Jolt halves over with -Sdeps, so this is for
47+ ;; a checkout beside the tree and nothing else reads it.
47 ;;48 ;;
48 ;; just tui49 ;; just tui
49 :tui {:extra-deps {nandi/glimmer-tui50 :tui {:extra-deps {nandi/glimmer-tui
modified flake.lock +5 -23
@@ -110,33 +110,16 @@
110110 "jolt-native": {
111111 "flake": false,
112112 "locked": {
113- "lastModified": 1788237272,
114- "narHash": "sha256-JdiPynqnCGSlQ7IBB9eMyLwk5WHiLSCDBLcMu7I156o=",
113+ "lastModified": 1788405941,
114+ "narHash": "sha256-aVMj/9IAX7szfmI0Awx8oHVU5/87sJ2V+w7MuBGHYmc=",
115115 "ref": "refs/heads/main",
116- "rev": "fd0e21a6c5d745ff9d134f92f909665454a7a1c9",
117- "revCount": 25,
116+ "rev": "258bbc5161b93d580a4c84363acabe63b0624e88",
117+ "revCount": 37,
118118 "type": "git",
119119 "url": "https://gitlab.com/nandithebull/jolt-native"
120120 },
121121 "original": {
122- "rev": "fd0e21a6c5d745ff9d134f92f909665454a7a1c9",
123- "type": "git",
124- "url": "https://gitlab.com/nandithebull/jolt-native"
125- }
126- },
127- "jolt-native-tui": {
128- "flake": false,
129- "locked": {
130- "lastModified": 1788332109,
131- "narHash": "sha256-sS9ruxMwMmpESDVNpDGjdHb37DZRayB0qoJbvYfOp1A=",
132- "ref": "refs/heads/main",
133- "rev": "c4f56b0a96ecb29336e2cf16c522b794ae62ad3f",
134- "revCount": 35,
135- "type": "git",
136- "url": "https://gitlab.com/nandithebull/jolt-native"
137- },
138- "original": {
139- "rev": "c4f56b0a96ecb29336e2cf16c522b794ae62ad3f",
122+ "rev": "258bbc5161b93d580a4c84363acabe63b0624e88",
140123 "type": "git",
141124 "url": "https://gitlab.com/nandithebull/jolt-native"
142125 }
@@ -224,7 +207,6 @@
224207 "glimmer": "glimmer",
225208 "jolt-android-src": "jolt-android-src",
226209 "jolt-native": "jolt-native",
227- "jolt-native-tui": "jolt-native-tui",
228210 "jolt-src": "jolt-src",
229211 "nix-appimage": "nix-appimage",
230212 "nixgl": "nixgl",
@@ -110,33 +110,16 @@
110 "jolt-native": {110 "jolt-native": {
111 "flake": false,111 "flake": false,
112 "locked": {112 "locked": {
113- "lastModified": 1788237272,113+ "lastModified": 1788405941,
114- "narHash": "sha256-JdiPynqnCGSlQ7IBB9eMyLwk5WHiLSCDBLcMu7I156o=",114+ "narHash": "sha256-aVMj/9IAX7szfmI0Awx8oHVU5/87sJ2V+w7MuBGHYmc=",
115 "ref": "refs/heads/main",115 "ref": "refs/heads/main",
116- "rev": "fd0e21a6c5d745ff9d134f92f909665454a7a1c9",116+ "rev": "258bbc5161b93d580a4c84363acabe63b0624e88",
117- "revCount": 25,117+ "revCount": 37,
118 "type": "git",118 "type": "git",
119 "url": "https://gitlab.com/nandithebull/jolt-native"119 "url": "https://gitlab.com/nandithebull/jolt-native"
120 },120 },
121 "original": {121 "original": {
122- "rev": "fd0e21a6c5d745ff9d134f92f909665454a7a1c9",122+ "rev": "258bbc5161b93d580a4c84363acabe63b0624e88",
123- "type": "git",
124- "url": "https://gitlab.com/nandithebull/jolt-native"
125- }
126- },
127- "jolt-native-tui": {
128- "flake": false,
129- "locked": {
130- "lastModified": 1788332109,
131- "narHash": "sha256-sS9ruxMwMmpESDVNpDGjdHb37DZRayB0qoJbvYfOp1A=",
132- "ref": "refs/heads/main",
133- "rev": "c4f56b0a96ecb29336e2cf16c522b794ae62ad3f",
134- "revCount": 35,
135- "type": "git",
136- "url": "https://gitlab.com/nandithebull/jolt-native"
137- },
138- "original": {
139- "rev": "c4f56b0a96ecb29336e2cf16c522b794ae62ad3f",
140 "type": "git",123 "type": "git",
141 "url": "https://gitlab.com/nandithebull/jolt-native"124 "url": "https://gitlab.com/nandithebull/jolt-native"
142 }125 }
@@ -224,7 +207,6 @@
224 "glimmer": "glimmer",207 "glimmer": "glimmer",
225 "jolt-android-src": "jolt-android-src",208 "jolt-android-src": "jolt-android-src",
226 "jolt-native": "jolt-native",209 "jolt-native": "jolt-native",
227- "jolt-native-tui": "jolt-native-tui",
228 "jolt-src": "jolt-src",210 "jolt-src": "jolt-src",
229 "nix-appimage": "nix-appimage",211 "nix-appimage": "nix-appimage",
230 "nixgl": "nixgl",212 "nixgl": "nixgl",
modified flake.nix +124 -83
@@ -29,29 +29,24 @@
2929 flake = false;
3030 };
3131
32- # v0.1.3, which is the rev deps.edn and the scripts/*.dotslash pins both
33- # name. Pinned, and pinned to that: this input carries both halves of
32+ # Ahead of v0.1.3, which is what deps.edn and the scripts/*.dotslash pins
33+ # name — and deliberately: the pins are the last release, and this is what
34+ # `just run` builds, so a change to jolt-native can be run before there is
35+ # a release to fetch. The two meet again at `just bump`.
36+ #
37+ # Pinned all the same, and pinned to a rev: this input carries both halves of
3438 # glimmer-vidya — libvidya, and the Jolt side that binds it — so an
3539 # unpinned `main` is a build whose native half is free to sit at a
3640 # different commit from the tree that talks to it. It did, and what the
3741 # drift cost was silence: the Jolt half sent a reaction pill's hover card
3842 # to a libvidya with no handler for one, and the pill said nothing.
43+ # It also carries the terminal backend — crates/jolt-tui, the same tree ABI
44+ # over a grid of cells, and jolt/glimmer-tui beside glimmer-vidya. That was
45+ # a second input at a second rev while it lived on a branch, which is the
46+ # drift this comment warns about wearing a different hat: one input, and
47+ # the window and the terminal are the same library either way.
3948 jolt-native = {
40- url = "git+https://gitlab.com/nandithebull/jolt-native?rev=fd0e21a6c5d745ff9d134f92f909665454a7a1c9";
41- flake = false;
42- };
43-
44- # The terminal backend, which v0.1.3 has not got: crates/jolt-tui (the tree
45- # ABI over a grid of cells) and jolt/glimmer-tui (the jolt side that binds
46- # it). On a branch rather than a tag because the backend is still being
47- # fixed against this client — the last bump was a box that painted its
48- # first child and dropped the rest, which is what the chats list here was
49- # showing. Its own input rather than a bump of the one above, deliberately —
50- # the window half stays pinned to the release the rest of the tree names,
51- # and only `tui` evaluates this. When the backend ships in a release the
52- # two become one pin again.
53- jolt-native-tui = {
54- url = "git+https://gitlab.com/nandithebull/jolt-native?rev=c4f56b0a96ecb29336e2cf16c522b794ae62ad3f";
49+ url = "git+https://gitlab.com/nandithebull/jolt-native?rev=258bbc5161b93d580a4c84363acabe63b0624e88";
5550 flake = false;
5651 };
5752
@@ -95,21 +90,54 @@
9590 };
9691 };
9792
98- outputs = { self, nixpkgs, jolt-src, jolt-native, jolt-native-tui, glimmer, chez-src, jolt-android-src, nixgl, nix-appimage }:
93+ outputs = { self, nixpkgs, jolt-src, jolt-native, glimmer, chez-src, jolt-android-src, nixgl, nix-appimage }:
9994 let
10095 systems = [ "x86_64-linux" "aarch64-linux" ];
10196 forEachSystem = f:
10297 nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
98+
99+ # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA
100+ # wrappers are the ones that need --impure (they read the host kernel
101+ # module's version), which is why this only ever reaches for Intel.
102+ #
103+ # Built from nixGL's default.nix rather than taken from its flake
104+ # outputs, for the one argument the flake hardcodes on: `enable32bits`,
105+ # which on x86_64 puts a second, i686 copy of mesa, its LLVM, and
106+ # intel-media-driver into the wrapper. frq is 64-bit on both halves —
107+ # the Rust cdylibs and the Chez runtime — so nothing here ever opens the
108+ # 32-bit driver, and carrying it is most of the dev shell's closure.
109+ nixGLFor = pkgs: (import nixgl {
110+ inherit pkgs;
111+ enable32bits = false;
112+ }).nixGLIntel;
113+
114+ # egui reaches for these with dlopen rather than linking them, so being
115+ # in the cdylib's buildInputs is not enough — whatever starts frq has to
116+ # put them on the loader path itself. Without libx11 here, vidya reports
117+ # "X11 unavailable", falls back to Wayland, and winit refuses to build a
118+ # second event loop after the failed first one.
119+ #
120+ # Out here rather than beside the package that first needed them: the
121+ # dev shell starts frq too, on this tree's source rather than the store's
122+ # copy of it, and a second copy of this list is a second chance for the
123+ # two ways of running to disagree about what the window needs.
124+ runtimeLibsFor = pkgs: with pkgs; [
125+ libGL
126+ libxkbcommon
127+ wayland
128+ libx11
129+ libxcursor
130+ libxi
131+ libxrandr
132+ vulkan-loader
133+ ];
103134 in
104135 {
105136 packages = forEachSystem (pkgs:
106137 let
107138 inherit (pkgs) lib;
108139
109- # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA
110- # wrappers are the ones that need --impure (they read the host kernel
111- # module's version), which is why this only ever reaches for Intel.
112- nixGL = nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel;
140+ nixGL = nixGLFor pkgs;
113141
114142 # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and
115143 # libjoltmoq (the AV media plane). One workspace, two cdylibs.
@@ -162,44 +190,6 @@
162190 '';
163191 };
164192
165- # libjolttui alone, out of the tui input's workspace. One crate
166- # rather than the whole of it: the terminal backend's dependencies
167- # are crossterm and a width table, where libvidya's and libjoltmoq's
168- # are egui, openh264 and v4l none of which a terminal needs, and
169- # all of which this would otherwise build a second time at a second
170- # rev.
171- nativeTui = pkgs.rustPlatform.buildRustPackage {
172- pname = "jolt-tui";
173- version = "0.1.0";
174- src = jolt-native-tui;
175-
176- cargoLock = {
177- lockFile = "${jolt-native-tui}/Cargo.lock";
178- allowBuiltinFetchGit = true;
179- };
180-
181- nativeBuildInputs = with pkgs; [ pkg-config cmake rustPlatform.bindgenHook ];
182- buildInputs = with pkgs; [ alsa-lib pipewire openssl libxkbcommon wayland libGL ];
183-
184- cargoBuildFlags = [ "-p" "jolt-tui" ];
185-
186- # As above: upstream's .cargo/config.toml drives the build through
187- # DotSlash, which a sandbox has no network for.
188- postPatch = ''
189- rm -f .cargo/config.toml
190- '';
191-
192- V4L2R_VIDEODEV2_H_PATH = "${pkgs.linuxHeaders}/include";
193- doCheck = false;
194-
195- installPhase = ''
196- runHook preInstall
197- mkdir -p "$out/lib"
198- install -m644 target/*/release/libjolttui.so "$out/lib/"
199- runHook postInstall
200- '';
201- };
202-
203193 # Jolt itself: Clojure on Chez, built the way its own flake builds it.
204194 # A function, because there are two of them upstream for the
205195 # desktop, and the Bionic-addrinfo fork for the boot image the APK
@@ -230,7 +220,10 @@
230220 '';
231221
232222 # jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens
233- # OpenSSL through the JOLT_OPENSSL_LIBDIR seam.
223+ # OpenSSL through the JOLT_OPENSSL_LIBDIR seam. gitMinimal rather
224+ # than git: all jolt.deps asks for is clone/fetch/rev-parse, and
225+ # the full package carries Perl and Python for the subcommands
226+ # written in them a quarter of a gigabyte for git-send-email.
234227 #
235228 # TZDIR so a zone *name* resolves wherever this runs: frq.clock
236229 # hands one to tzset, and glibc then looks for the tzfile under
@@ -239,7 +232,7 @@
239232 # machine. --set-default, so a TZDIR the user set still wins.
240233 postFixup = ''
241234 wrapProgram "$out/bin/jolt" \
242- --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.git pkgs.unzip ]}" \
235+ --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.gitMinimal pkgs.unzip ]}" \
243236 --set-default JOLT_OPENSSL_LIBDIR "${pkgs.lib.makeLibraryPath [ pkgs.openssl ]}" \
244237 --set-default TZDIR "${pkgs.tzdata}/share/zoneinfo" \
245238 --set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
@@ -253,23 +246,9 @@
253246 # deps.edn asks for glimmer by git the top-level override below
254247 # answers for both.
255248 glimmerVidya = "${jolt-native}/jolt/glimmer-vidya";
256- glimmerTui = "${jolt-native-tui}/jolt/glimmer-tui";
257-
258- # egui reaches for these with dlopen rather than linking them, so
259- # being in the cdylib's buildInputs is not enough the launcher has
260- # to put them on the loader path itself. Without libX11 here, vidya
261- # reports "X11 unavailable", falls back to Wayland, and winit refuses
262- # to build a second event loop after the failed first one.
263- runtimeLibs = with pkgs; [
264- libGL
265- libxkbcommon
266- wayland
267- xorg.libX11
268- xorg.libXcursor
269- xorg.libXi
270- xorg.libXrandr
271- vulkan-loader
272- ];
249+ glimmerTui = "${jolt-native}/jolt/glimmer-tui";
250+
251+ runtimeLibs = runtimeLibsFor pkgs;
273252
274253 # The project as jolt sees it: source, deps.edn, nothing else.
275254 frqSource = pkgs.runCommand "frq-source" { } ''
@@ -300,7 +279,7 @@
300279 # a terminal is the one surface that needs nothing from the host but
301280 # a terminal, which is the reason this output exists.
302281 tuiScript = pkgs.writeShellScript "frq-tui" ''
303- export LD_LIBRARY_PATH="${nativeTui}/lib:${native}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
282+ export LD_LIBRARY_PATH="${native}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
304283 cd ${frqSource}
305284
306285 exec ${joltRuntime}/bin/jolt \
@@ -339,8 +318,8 @@
339318 # `legacyPackages` everything above uses. Confined to the Android
340319 # outputs: `nix build` of frq itself never evaluates it.
341320 #
342- # The NDK here is r29, which is the version scripts/android-ndk.dotslash
343- # pins and the one the pinned libvidya was built with.
321+ # The NDK here is r29, which is the one the pinned libvidya was
322+ # built with.
344323 androidPkgs = import nixpkgs {
345324 inherit (pkgs.stdenv.hostPlatform) system;
346325 config = {
@@ -364,10 +343,16 @@
364343 in
365344 {
366345 inherit native frq;
367- inherit nativeTui tui;
346+ inherit tui;
368347 jolt = joltRuntime;
369348 default = frq;
370349
350+ # The interpreter scripts/ is written in, named here so that
351+ # scripts/bb can build it. Nothing else in this flake uses it: it is
352+ # an output because a shell script cannot ask for `nixpkgs#babashka`
353+ # at the version this tree pins, and `.#bb` is exactly that.
354+ bb = pkgs.babashka;
355+
371356 # frq and everything it loads, squashed into one runnable file for
372357 # hosts without Nix. The whole closure rides along Mesa included,
373358 # which is not waste: off NixOS the launcher goes through nixGL, and
@@ -383,6 +368,62 @@
383368 apk-unsigned = android.apk-unsigned;
384369 });
385370
371+ # Where `just run` runs, and because entering it realises what it
372+ # names what builds the half of frq that is not this working tree.
373+ #
374+ # The two halves, and the split is the whole point of the shell. The frq
375+ # source is the files on disk, uncommitted edits and all. Everything
376+ # under it jolt, glimmer, glimmer-vidya, both native objects is the
377+ # flake's, at the revs flake.lock names, so a run says what it ran
378+ # against and both halves of glimmer-vidya move together. That is the
379+ # drift the `jolt-native` input's comment is about, and a pin frq can
380+ # answer for is worth more here than the convenience of a checkout.
381+ #
382+ # `native` is the cargo build of that input rather than jolt-native's own
383+ # buck2 graph, which is a compromise and not a free one: buck2 is what
384+ # its CI runs and what makes its releases, and its cpal has the pipewire
385+ # feature this one does not, so device *names* in a call come out as ALSA
386+ # PCMs. What it buys is a derivation one thing nixbuild.net can be
387+ # handed. The buck2 build fetches its rustc, zig and every third-party
388+ # crate as it goes and writes buck-out into the tree it builds; a sandbox
389+ # with no network and a read-only store is the one place it cannot run,
390+ # so on a remote builder it is not a slower option but no option at all.
391+ #
392+ # Nothing here says "nixbuild", though: it is a plain derivation, and
393+ # where it gets built is the machine's business. scripts/run.bb asks for
394+ # the shell with --max-jobs 0, which is what sends it to the `builders`
395+ # entry rather than compiling egui on a laptop.
396+ devShells = forEachSystem (pkgs:
397+ let
398+ inherit (pkgs) lib;
399+ inherit (self.packages.${pkgs.stdenv.hostPlatform.system}) jolt native;
400+ in
401+ {
402+ default = pkgs.mkShellNoCC {
403+ name = "frq";
404+
405+ # jolt, because the runtime frq is run by should be the flake's
406+ # too. nixGL for the same reason the launcher reaches for it see
407+ # frqScript. babashka because scripts/bb prefers one on PATH, and
408+ # inside here that should be this one rather than a second copy
409+ # built through `.#bb`. just so the recipe runner comes from here
410+ # too rather than the host `nix develop` and then `just run` is
411+ # the whole of what a machine with nix needs.
412+ packages = [ jolt pkgs.babashka pkgs.just (nixGLFor pkgs) ];
413+
414+ # Read by scripts/run.bb rather than baked into a wrapper: the frq
415+ # source `just run` runs is the working tree, so the launcher has
416+ # to be a script in that tree and the shell has to hand it its
417+ # answers. Naming these is also what makes the shell build them.
418+ JOLT_NATIVE_LIB = "${native}/lib";
419+ GLIMMER_SRC = glimmer;
420+ GLIMMER_VIDYA_SRC = "${jolt-native}/jolt/glimmer-vidya";
421+ GLIMMER_TUI_SRC = "${jolt-native}/jolt/glimmer-tui";
422+ FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs);
423+ NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel";
424+ };
425+ });
426+
386427 apps = forEachSystem (pkgs: {
387428 default = {
388429 type = "app";
@@ -29,29 +29,24 @@
29 flake = false;29 flake = false;
30 };30 };
31 31
32- # v0.1.3, which is the rev deps.edn and the scripts/*.dotslash pins both32+ # Ahead of v0.1.3, which is what deps.edn and the scripts/*.dotslash pins
33- # name. Pinned, and pinned to that: this input carries both halves of33+ # name — and deliberately: the pins are the last release, and this is what
34+ # `just run` builds, so a change to jolt-native can be run before there is
35+ # a release to fetch. The two meet again at `just bump`.
36+ #
37+ # Pinned all the same, and pinned to a rev: this input carries both halves of
34 # glimmer-vidya — libvidya, and the Jolt side that binds it — so an38 # glimmer-vidya — libvidya, and the Jolt side that binds it — so an
35 # unpinned `main` is a build whose native half is free to sit at a39 # unpinned `main` is a build whose native half is free to sit at a
36 # different commit from the tree that talks to it. It did, and what the40 # different commit from the tree that talks to it. It did, and what the
37 # drift cost was silence: the Jolt half sent a reaction pill's hover card41 # drift cost was silence: the Jolt half sent a reaction pill's hover card
38 # to a libvidya with no handler for one, and the pill said nothing.42 # to a libvidya with no handler for one, and the pill said nothing.
43+ # It also carries the terminal backend — crates/jolt-tui, the same tree ABI
44+ # over a grid of cells, and jolt/glimmer-tui beside glimmer-vidya. That was
45+ # a second input at a second rev while it lived on a branch, which is the
46+ # drift this comment warns about wearing a different hat: one input, and
47+ # the window and the terminal are the same library either way.
39 jolt-native = {48 jolt-native = {
40- url = "git+https://gitlab.com/nandithebull/jolt-native?rev=fd0e21a6c5d745ff9d134f92f909665454a7a1c9";49+ url = "git+https://gitlab.com/nandithebull/jolt-native?rev=258bbc5161b93d580a4c84363acabe63b0624e88";
41- flake = false;
42- };
43-
44- # The terminal backend, which v0.1.3 has not got: crates/jolt-tui (the tree
45- # ABI over a grid of cells) and jolt/glimmer-tui (the jolt side that binds
46- # it). On a branch rather than a tag because the backend is still being
47- # fixed against this client — the last bump was a box that painted its
48- # first child and dropped the rest, which is what the chats list here was
49- # showing. Its own input rather than a bump of the one above, deliberately —
50- # the window half stays pinned to the release the rest of the tree names,
51- # and only `tui` evaluates this. When the backend ships in a release the
52- # two become one pin again.
53- jolt-native-tui = {
54- url = "git+https://gitlab.com/nandithebull/jolt-native?rev=c4f56b0a96ecb29336e2cf16c522b794ae62ad3f";
55 flake = false;50 flake = false;
56 };51 };
57 52
@@ -95,21 +90,54 @@
95 };90 };
96 };91 };
97 92
98- outputs = { self, nixpkgs, jolt-src, jolt-native, jolt-native-tui, glimmer, chez-src, jolt-android-src, nixgl, nix-appimage }:93+ outputs = { self, nixpkgs, jolt-src, jolt-native, glimmer, chez-src, jolt-android-src, nixgl, nix-appimage }:
99 let94 let
100 systems = [ "x86_64-linux" "aarch64-linux" ];95 systems = [ "x86_64-linux" "aarch64-linux" ];
101 forEachSystem = f:96 forEachSystem = f:
102 nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});97 nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
98+
99+ # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA
100+ # wrappers are the ones that need --impure (they read the host kernel
101+ # module's version), which is why this only ever reaches for Intel.
102+ #
103+ # Built from nixGL's default.nix rather than taken from its flake
104+ # outputs, for the one argument the flake hardcodes on: `enable32bits`,
105+ # which on x86_64 puts a second, i686 copy of mesa, its LLVM, and
106+ # intel-media-driver into the wrapper. frq is 64-bit on both halves —
107+ # the Rust cdylibs and the Chez runtime — so nothing here ever opens the
108+ # 32-bit driver, and carrying it is most of the dev shell's closure.
109+ nixGLFor = pkgs: (import nixgl {
110+ inherit pkgs;
111+ enable32bits = false;
112+ }).nixGLIntel;
113+
114+ # egui reaches for these with dlopen rather than linking them, so being
115+ # in the cdylib's buildInputs is not enough — whatever starts frq has to
116+ # put them on the loader path itself. Without libx11 here, vidya reports
117+ # "X11 unavailable", falls back to Wayland, and winit refuses to build a
118+ # second event loop after the failed first one.
119+ #
120+ # Out here rather than beside the package that first needed them: the
121+ # dev shell starts frq too, on this tree's source rather than the store's
122+ # copy of it, and a second copy of this list is a second chance for the
123+ # two ways of running to disagree about what the window needs.
124+ runtimeLibsFor = pkgs: with pkgs; [
125+ libGL
126+ libxkbcommon
127+ wayland
128+ libx11
129+ libxcursor
130+ libxi
131+ libxrandr
132+ vulkan-loader
133+ ];
103 in134 in
104 {135 {
105 packages = forEachSystem (pkgs:136 packages = forEachSystem (pkgs:
106 let137 let
107 inherit (pkgs) lib;138 inherit (pkgs) lib;
108 139
109- # Mesa, despite the name: it covers Intel and AMD alike. The NVIDIA140+ nixGL = nixGLFor pkgs;
110- # wrappers are the ones that need --impure (they read the host kernel
111- # module's version), which is why this only ever reaches for Intel.
112- nixGL = nixgl.packages.${pkgs.stdenv.hostPlatform.system}.nixGLIntel;
113 141
114 # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and142 # libvidya (the retained-tree ABI glimmer-vidya binds, on egui) and
115 # libjoltmoq (the AV media plane). One workspace, two cdylibs.143 # libjoltmoq (the AV media plane). One workspace, two cdylibs.
@@ -162,44 +190,6 @@
162 '';190 '';
163 };191 };
164 192
165- # libjolttui alone, out of the tui input's workspace. One crate
166- # rather than the whole of it: the terminal backend's dependencies
167- # are crossterm and a width table, where libvidya's and libjoltmoq's
168- # are egui, openh264 and v4l none of which a terminal needs, and
169- # all of which this would otherwise build a second time at a second
170- # rev.
171- nativeTui = pkgs.rustPlatform.buildRustPackage {
172- pname = "jolt-tui";
173- version = "0.1.0";
174- src = jolt-native-tui;
175-
176- cargoLock = {
177- lockFile = "${jolt-native-tui}/Cargo.lock";
178- allowBuiltinFetchGit = true;
179- };
180-
181- nativeBuildInputs = with pkgs; [ pkg-config cmake rustPlatform.bindgenHook ];
182- buildInputs = with pkgs; [ alsa-lib pipewire openssl libxkbcommon wayland libGL ];
183-
184- cargoBuildFlags = [ "-p" "jolt-tui" ];
185-
186- # As above: upstream's .cargo/config.toml drives the build through
187- # DotSlash, which a sandbox has no network for.
188- postPatch = ''
189- rm -f .cargo/config.toml
190- '';
191-
192- V4L2R_VIDEODEV2_H_PATH = "${pkgs.linuxHeaders}/include";
193- doCheck = false;
194-
195- installPhase = ''
196- runHook preInstall
197- mkdir -p "$out/lib"
198- install -m644 target/*/release/libjolttui.so "$out/lib/"
199- runHook postInstall
200- '';
201- };
202-
203 # Jolt itself: Clojure on Chez, built the way its own flake builds it.193 # Jolt itself: Clojure on Chez, built the way its own flake builds it.
204 # A function, because there are two of them upstream for the194 # A function, because there are two of them upstream for the
205 # desktop, and the Bionic-addrinfo fork for the boot image the APK195 # desktop, and the Bionic-addrinfo fork for the boot image the APK
@@ -230,7 +220,10 @@
230 '';220 '';
231 221
232 # jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens222 # jolt.deps shells out to git and unzip, and jolt.mvn-http dlopens
233- # OpenSSL through the JOLT_OPENSSL_LIBDIR seam.223+ # OpenSSL through the JOLT_OPENSSL_LIBDIR seam. gitMinimal rather
224+ # than git: all jolt.deps asks for is clone/fetch/rev-parse, and
225+ # the full package carries Perl and Python for the subcommands
226+ # written in them a quarter of a gigabyte for git-send-email.
234 #227 #
235 # TZDIR so a zone *name* resolves wherever this runs: frq.clock228 # TZDIR so a zone *name* resolves wherever this runs: frq.clock
236 # hands one to tzset, and glibc then looks for the tzfile under229 # hands one to tzset, and glibc then looks for the tzfile under
@@ -239,7 +232,7 @@
239 # machine. --set-default, so a TZDIR the user set still wins.232 # machine. --set-default, so a TZDIR the user set still wins.
240 postFixup = ''233 postFixup = ''
241 wrapProgram "$out/bin/jolt" \234 wrapProgram "$out/bin/jolt" \
242- --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.git pkgs.unzip ]}" \235+ --prefix PATH : "${pkgs.lib.makeBinPath [ pkgs.gitMinimal pkgs.unzip ]}" \
243 --set-default JOLT_OPENSSL_LIBDIR "${pkgs.lib.makeLibraryPath [ pkgs.openssl ]}" \236 --set-default JOLT_OPENSSL_LIBDIR "${pkgs.lib.makeLibraryPath [ pkgs.openssl ]}" \
244 --set-default TZDIR "${pkgs.tzdata}/share/zoneinfo" \237 --set-default TZDIR "${pkgs.tzdata}/share/zoneinfo" \
245 --set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"238 --set-default SSL_CERT_FILE "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
@@ -253,23 +246,9 @@
253 # deps.edn asks for glimmer by git the top-level override below246 # deps.edn asks for glimmer by git the top-level override below
254 # answers for both.247 # answers for both.
255 glimmerVidya = "${jolt-native}/jolt/glimmer-vidya";248 glimmerVidya = "${jolt-native}/jolt/glimmer-vidya";
256- glimmerTui = "${jolt-native-tui}/jolt/glimmer-tui";249+ glimmerTui = "${jolt-native}/jolt/glimmer-tui";
257-250+
258- # egui reaches for these with dlopen rather than linking them, so251+ runtimeLibs = runtimeLibsFor pkgs;
259- # being in the cdylib's buildInputs is not enough the launcher has
260- # to put them on the loader path itself. Without libX11 here, vidya
261- # reports "X11 unavailable", falls back to Wayland, and winit refuses
262- # to build a second event loop after the failed first one.
263- runtimeLibs = with pkgs; [
264- libGL
265- libxkbcommon
266- wayland
267- xorg.libX11
268- xorg.libXcursor
269- xorg.libXi
270- xorg.libXrandr
271- vulkan-loader
272- ];
273 252
274 # The project as jolt sees it: source, deps.edn, nothing else.253 # The project as jolt sees it: source, deps.edn, nothing else.
275 frqSource = pkgs.runCommand "frq-source" { } ''254 frqSource = pkgs.runCommand "frq-source" { } ''
@@ -300,7 +279,7 @@
300 # a terminal is the one surface that needs nothing from the host but279 # a terminal is the one surface that needs nothing from the host but
301 # a terminal, which is the reason this output exists.280 # a terminal, which is the reason this output exists.
302 tuiScript = pkgs.writeShellScript "frq-tui" ''281 tuiScript = pkgs.writeShellScript "frq-tui" ''
303- export LD_LIBRARY_PATH="${nativeTui}/lib:${native}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"282+ export LD_LIBRARY_PATH="${native}/lib''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
304 cd ${frqSource}283 cd ${frqSource}
305 284
306 exec ${joltRuntime}/bin/jolt \285 exec ${joltRuntime}/bin/jolt \
@@ -339,8 +318,8 @@
339 # `legacyPackages` everything above uses. Confined to the Android318 # `legacyPackages` everything above uses. Confined to the Android
340 # outputs: `nix build` of frq itself never evaluates it.319 # outputs: `nix build` of frq itself never evaluates it.
341 #320 #
342- # The NDK here is r29, which is the version scripts/android-ndk.dotslash321+ # The NDK here is r29, which is the one the pinned libvidya was
343- # pins and the one the pinned libvidya was built with.322+ # built with.
344 androidPkgs = import nixpkgs {323 androidPkgs = import nixpkgs {
345 inherit (pkgs.stdenv.hostPlatform) system;324 inherit (pkgs.stdenv.hostPlatform) system;
346 config = {325 config = {
@@ -364,10 +343,16 @@
364 in343 in
365 {344 {
366 inherit native frq;345 inherit native frq;
367- inherit nativeTui tui;346+ inherit tui;
368 jolt = joltRuntime;347 jolt = joltRuntime;
369 default = frq;348 default = frq;
370 349
350+ # The interpreter scripts/ is written in, named here so that
351+ # scripts/bb can build it. Nothing else in this flake uses it: it is
352+ # an output because a shell script cannot ask for `nixpkgs#babashka`
353+ # at the version this tree pins, and `.#bb` is exactly that.
354+ bb = pkgs.babashka;
355+
371 # frq and everything it loads, squashed into one runnable file for356 # frq and everything it loads, squashed into one runnable file for
372 # hosts without Nix. The whole closure rides along Mesa included,357 # hosts without Nix. The whole closure rides along Mesa included,
373 # which is not waste: off NixOS the launcher goes through nixGL, and358 # which is not waste: off NixOS the launcher goes through nixGL, and
@@ -383,6 +368,62 @@
383 apk-unsigned = android.apk-unsigned;368 apk-unsigned = android.apk-unsigned;
384 });369 });
385 370
371+ # Where `just run` runs, and because entering it realises what it
372+ # names what builds the half of frq that is not this working tree.
373+ #
374+ # The two halves, and the split is the whole point of the shell. The frq
375+ # source is the files on disk, uncommitted edits and all. Everything
376+ # under it jolt, glimmer, glimmer-vidya, both native objects is the
377+ # flake's, at the revs flake.lock names, so a run says what it ran
378+ # against and both halves of glimmer-vidya move together. That is the
379+ # drift the `jolt-native` input's comment is about, and a pin frq can
380+ # answer for is worth more here than the convenience of a checkout.
381+ #
382+ # `native` is the cargo build of that input rather than jolt-native's own
383+ # buck2 graph, which is a compromise and not a free one: buck2 is what
384+ # its CI runs and what makes its releases, and its cpal has the pipewire
385+ # feature this one does not, so device *names* in a call come out as ALSA
386+ # PCMs. What it buys is a derivation one thing nixbuild.net can be
387+ # handed. The buck2 build fetches its rustc, zig and every third-party
388+ # crate as it goes and writes buck-out into the tree it builds; a sandbox
389+ # with no network and a read-only store is the one place it cannot run,
390+ # so on a remote builder it is not a slower option but no option at all.
391+ #
392+ # Nothing here says "nixbuild", though: it is a plain derivation, and
393+ # where it gets built is the machine's business. scripts/run.bb asks for
394+ # the shell with --max-jobs 0, which is what sends it to the `builders`
395+ # entry rather than compiling egui on a laptop.
396+ devShells = forEachSystem (pkgs:
397+ let
398+ inherit (pkgs) lib;
399+ inherit (self.packages.${pkgs.stdenv.hostPlatform.system}) jolt native;
400+ in
401+ {
402+ default = pkgs.mkShellNoCC {
403+ name = "frq";
404+
405+ # jolt, because the runtime frq is run by should be the flake's
406+ # too. nixGL for the same reason the launcher reaches for it see
407+ # frqScript. babashka because scripts/bb prefers one on PATH, and
408+ # inside here that should be this one rather than a second copy
409+ # built through `.#bb`. just so the recipe runner comes from here
410+ # too rather than the host `nix develop` and then `just run` is
411+ # the whole of what a machine with nix needs.
412+ packages = [ jolt pkgs.babashka pkgs.just (nixGLFor pkgs) ];
413+
414+ # Read by scripts/run.bb rather than baked into a wrapper: the frq
415+ # source `just run` runs is the working tree, so the launcher has
416+ # to be a script in that tree and the shell has to hand it its
417+ # answers. Naming these is also what makes the shell build them.
418+ JOLT_NATIVE_LIB = "${native}/lib";
419+ GLIMMER_SRC = glimmer;
420+ GLIMMER_VIDYA_SRC = "${jolt-native}/jolt/glimmer-vidya";
421+ GLIMMER_TUI_SRC = "${jolt-native}/jolt/glimmer-tui";
422+ FRQ_LIB_PATH = lib.makeLibraryPath (runtimeLibsFor pkgs);
423+ NIXGL = "${nixGLFor pkgs}/bin/nixGLIntel";
424+ };
425+ });
426+
386 apps = forEachSystem (pkgs: {427 apps = forEachSystem (pkgs: {
387 default = {428 default = {
388 type = "app";429 type = "app";
modified justfile +7 -15
@@ -1,34 +1,26 @@
11 # Every recipe here is one line, because the work is in scripts/ — babashka
2-# scripts, run through the pin in scripts/bb. A recipe body is a shell script
3-# nobody can run on its own; a script in scripts/ is a script, and buck runs
4-# two of them as actions.
2+# scripts, run through scripts/bb, which finds a bb the way this tree finds
3+# everything else. A recipe body is a shell script nobody can run on its own;
4+# a script in scripts/ is a script.
55
66 set shell := ["bash", "-euo", "pipefail", "-c"]
77
88 default:
99 @just --list
1010
11-# Both native libraries, cloning jolt-native at the pinned commit if needed.
11+# Both native libraries, out of the release pins. `run` builds them instead.
1212 lib:
1313 scripts/lib.bb
1414
15-# buck2, with the machine's paths written where the BUCK files can read them.
16-buck *args:
17- scripts/buck.bb {{args}}
18-
19-# The APK. `just apk install` puts it on the device.
15+# The APK, out of the flake. `just apk install` puts it on the device.
2016 apk action="build":
2117 scripts/apk.bb {{action}}
2218
23-# Every jolt-native pin — manifests, deps.edn, the buck table — at a release.
19+# Every jolt-native pin — the manifests, deps.edn, nix/android.nix — at a release.
2420 bump tag="":
2521 scripts/bump-jolt-native.bb {{tag}}
2622
27-# The archives scripts/*.dotslash pins, as the table buck reads.
28-sync-dist:
29- scripts/dotslash-to-buck
30-
31-# The app.
23+# The app: this tree's source on the flake's everything-else, in the dev shell.
3224 run *args:
3325 scripts/run.bb {{args}}
3426
@@ -1,34 +1,26 @@
1 # Every recipe here is one line, because the work is in scripts/ — babashka1 # Every recipe here is one line, because the work is in scripts/ — babashka
2-# scripts, run through the pin in scripts/bb. A recipe body is a shell script2+# scripts, run through scripts/bb, which finds a bb the way this tree finds
3-# nobody can run on its own; a script in scripts/ is a script, and buck runs3+# everything else. A recipe body is a shell script nobody can run on its own;
4-# two of them as actions.4+# a script in scripts/ is a script.
5 5
6 set shell := ["bash", "-euo", "pipefail", "-c"]6 set shell := ["bash", "-euo", "pipefail", "-c"]
7 7
8 default:8 default:
9 @just --list9 @just --list
10 10
11-# Both native libraries, cloning jolt-native at the pinned commit if needed.11+# Both native libraries, out of the release pins. `run` builds them instead.
12 lib:12 lib:
13 scripts/lib.bb13 scripts/lib.bb
14 14
15-# buck2, with the machine's paths written where the BUCK files can read them.15+# The APK, out of the flake. `just apk install` puts it on the device.
16-buck *args:
17- scripts/buck.bb {{args}}
18-
19-# The APK. `just apk install` puts it on the device.
20 apk action="build":16 apk action="build":
21 scripts/apk.bb {{action}}17 scripts/apk.bb {{action}}
22 18
23-# Every jolt-native pin — manifests, deps.edn, the buck table — at a release.19+# Every jolt-native pin — the manifests, deps.edn, nix/android.nix — at a release.
24 bump tag="":20 bump tag="":
25 scripts/bump-jolt-native.bb {{tag}}21 scripts/bump-jolt-native.bb {{tag}}
26 22
27-# The archives scripts/*.dotslash pins, as the table buck reads.23+# The app: this tree's source on the flake's everything-else, in the dev shell.
28-sync-dist:
29- scripts/dotslash-to-buck
30-
31-# The app.
32 run *args:24 run *args:
33 scripts/run.bb {{args}}25 scripts/run.bb {{args}}
34 26
modified nix/android.nix +24 -18
@@ -1,14 +1,16 @@
1-# The APK, as derivations rather than as a buck2 graph.
1+# The APK, as derivations.
22 #
3-# android/BUCK builds the same things, and does it better for a person at
4-# a terminal: it is incremental, and it fetches jolt-native's release by digest
5-# rather than rebuilding the world. Nothing here replaces that. What this adds
6-# is the other build — from nothing, on a
7-# machine with no Android SDK, no NDK, no hand-built Chez cross target and no
8-# ~/.cache at all:
3+# The only APK build there is: this replaced a buck2 graph and the script
4+# before it, both of which named an Android SDK, an NDK, a hand-built Chez
5+# cross target and an OpenSSL by absolute path and stopped when one was
6+# missing. Every one of those is built or fetched here instead, so this works
7+# from nothing on a machine with none of them and no ~/.cache at all:
98 #
109 # nix build .#apk
1110 #
11+# `just apk` is the same build with the store path handed to adb afterwards;
12+# see scripts/apk.bb.
13+#
1214 # On a machine with a remote builder configured, prefer
1315 #
1416 # nix build .#apk --store ssh-ng://eu.nixbuild.net --eval-store auto
@@ -20,9 +22,9 @@
2022 # whole graph stays there, only .drv files go up, and the builder fetches
2123 # Google's zip over its own link.
2224 #
23-# Every path .buckconfig.local answers for is answered here by the store
24-# instead. The steps are in the same order and do the same work; where a
25-# genrule read `read_root_config`, a derivation takes an argument.
25+# The steps are the ones the graph before it ran, in the same order; where a
26+# genrule read a path out of `read_root_config`, a derivation takes an
27+# argument.
2628 { pkgs, lib, self, chez-src, jolt-native, glimmer, joltAndroid, androidSdk, ndk }:
2729
2830 let
@@ -45,9 +47,12 @@ let
4547 ndkBin = "${ndkRoot}/toolchains/llvm/prebuilt/linux-x86_64/bin";
4648 cc = "${ndkBin}/aarch64-linux-android${apiLevel}-clang";
4749
48- # What comes out of jolt-native's releases, by the digests scripts/*.dotslash
49- # pin. Same bytes buck fetches; DotSlash's `digest` is over the archive,
50- # which is what fetchurl hashes too.
50+ # What comes out of jolt-native's releases. These two pins are the Android
51+ # half of what `just bump` moves — the desktop half stays in
52+ # scripts/*.dotslash, and the tag written here is the one written there, so
53+ # a phone and a laptop run the same release. Do not edit them by hand:
54+ # bump-jolt-native.bb fetches each archive, weighs it, and writes both the
55+ # url and the digest below.
5156 #
5257 # One archive, two libraries: libvidya (the retained-tree UI) and libjoltmoq
5358 # (the AV media plane). They are built together and only make sense together
@@ -170,10 +175,10 @@ let
170175 xpatch = "${chezAndroid}/xc-tarm64le/s/xpatch";
171176
172177 # --- the Jolt half --------------------------------------------------------
173- # frq's Scheme, cross-compiled to an arm64 boot image. android/build-jolt-boot.bb
174- # does this by hand-writing a deps.edn of :paths and then driving Chez; so
175- # does this, for the same reason — there is no dependency resolution inside a
176- # cross compile, so every source root deps.edn would have resolved is named.
178+ # frq's Scheme, cross-compiled to an arm64 boot image. The deps.edn below is
179+ # written out by hand rather than resolved: there is no dependency resolution
180+ # inside a cross compile, so every source root deps.edn would have resolved is
181+ # named as a :path instead.
177182 #
178183 # The jolt that runs it is the fork, not upstream and not the one the desktop
179184 # package builds: upstream reads the socket address out of `struct addrinfo`
@@ -374,7 +379,8 @@ let
374379
375380 # Aligned and signed with a debug key. The key is generated here rather than
376381 # read from ~/.android, which is the one place this build is deliberately
377- # not the buck one: a keystore outside the store would make the output
382+ # not what the builds before it did: a keystore outside the store would make
383+ # the output
378384 # depend on the machine, and a release key has no business in the store at
379385 # all. So this output is installable and not reproducible — keytool stamps
380386 # the certificate with the time — and anything meant for a store should be
@@ -1,14 +1,16 @@
1-# The APK, as derivations rather than as a buck2 graph.1+# The APK, as derivations.
2 #2 #
3-# android/BUCK builds the same things, and does it better for a person at3+# The only APK build there is: this replaced a buck2 graph and the script
4-# a terminal: it is incremental, and it fetches jolt-native's release by digest4+# before it, both of which named an Android SDK, an NDK, a hand-built Chez
5-# rather than rebuilding the world. Nothing here replaces that. What this adds5+# cross target and an OpenSSL by absolute path and stopped when one was
6-# is the other build — from nothing, on a6+# missing. Every one of those is built or fetched here instead, so this works
7-# machine with no Android SDK, no NDK, no hand-built Chez cross target and no7+# from nothing on a machine with none of them and no ~/.cache at all:
8-# ~/.cache at all:
9 #8 #
10 # nix build .#apk9 # nix build .#apk
11 #10 #
11+# `just apk` is the same build with the store path handed to adb afterwards;
12+# see scripts/apk.bb.
13+#
12 # On a machine with a remote builder configured, prefer14 # On a machine with a remote builder configured, prefer
13 #15 #
14 # nix build .#apk --store ssh-ng://eu.nixbuild.net --eval-store auto16 # nix build .#apk --store ssh-ng://eu.nixbuild.net --eval-store auto
@@ -20,9 +22,9 @@
20 # whole graph stays there, only .drv files go up, and the builder fetches22 # whole graph stays there, only .drv files go up, and the builder fetches
21 # Google's zip over its own link.23 # Google's zip over its own link.
22 #24 #
23-# Every path .buckconfig.local answers for is answered here by the store25+# The steps are the ones the graph before it ran, in the same order; where a
24-# instead. The steps are in the same order and do the same work; where a26+# genrule read a path out of `read_root_config`, a derivation takes an
25-# genrule read `read_root_config`, a derivation takes an argument.27+# argument.
26 { pkgs, lib, self, chez-src, jolt-native, glimmer, joltAndroid, androidSdk, ndk }:28 { pkgs, lib, self, chez-src, jolt-native, glimmer, joltAndroid, androidSdk, ndk }:
27 29
28 let30 let
@@ -45,9 +47,12 @@ let
45 ndkBin = "${ndkRoot}/toolchains/llvm/prebuilt/linux-x86_64/bin";47 ndkBin = "${ndkRoot}/toolchains/llvm/prebuilt/linux-x86_64/bin";
46 cc = "${ndkBin}/aarch64-linux-android${apiLevel}-clang";48 cc = "${ndkBin}/aarch64-linux-android${apiLevel}-clang";
47 49
48- # What comes out of jolt-native's releases, by the digests scripts/*.dotslash50+ # What comes out of jolt-native's releases. These two pins are the Android
49- # pin. Same bytes buck fetches; DotSlash's `digest` is over the archive,51+ # half of what `just bump` moves — the desktop half stays in
50- # which is what fetchurl hashes too.52+ # scripts/*.dotslash, and the tag written here is the one written there, so
53+ # a phone and a laptop run the same release. Do not edit them by hand:
54+ # bump-jolt-native.bb fetches each archive, weighs it, and writes both the
55+ # url and the digest below.
51 #56 #
52 # One archive, two libraries: libvidya (the retained-tree UI) and libjoltmoq57 # One archive, two libraries: libvidya (the retained-tree UI) and libjoltmoq
53 # (the AV media plane). They are built together and only make sense together58 # (the AV media plane). They are built together and only make sense together
@@ -170,10 +175,10 @@ let
170 xpatch = "${chezAndroid}/xc-tarm64le/s/xpatch";175 xpatch = "${chezAndroid}/xc-tarm64le/s/xpatch";
171 176
172 # --- the Jolt half --------------------------------------------------------177 # --- the Jolt half --------------------------------------------------------
173- # frq's Scheme, cross-compiled to an arm64 boot image. android/build-jolt-boot.bb178+ # frq's Scheme, cross-compiled to an arm64 boot image. The deps.edn below is
174- # does this by hand-writing a deps.edn of :paths and then driving Chez; so179+ # written out by hand rather than resolved: there is no dependency resolution
175- # does this, for the same reason — there is no dependency resolution inside a180+ # inside a cross compile, so every source root deps.edn would have resolved is
176- # cross compile, so every source root deps.edn would have resolved is named.181+ # named as a :path instead.
177 #182 #
178 # The jolt that runs it is the fork, not upstream and not the one the desktop183 # The jolt that runs it is the fork, not upstream and not the one the desktop
179 # package builds: upstream reads the socket address out of `struct addrinfo`184 # package builds: upstream reads the socket address out of `struct addrinfo`
@@ -374,7 +379,8 @@ let
374 379
375 # Aligned and signed with a debug key. The key is generated here rather than380 # Aligned and signed with a debug key. The key is generated here rather than
376 # read from ~/.android, which is the one place this build is deliberately381 # read from ~/.android, which is the one place this build is deliberately
377- # not the buck one: a keystore outside the store would make the output382+ # not what the builds before it did: a keystore outside the store would make
383+ # the output
378 # depend on the machine, and a release key has no business in the store at384 # depend on the machine, and a release key has no business in the store at
379 # all. So this output is installable and not reproducible — keytool stamps385 # all. So this output is installable and not reproducible — keytool stamps
380 # the certificate with the time — and anything meant for a store should be386 # the certificate with the time — and anything meant for a store should be
deleted platforms/BUCK +0 -33
deleted file mode 100644
@@ -1,33 +0,0 @@
1-load("@prelude//platforms:defs.bzl", "host_configuration")
2-load(":defs.bzl", "execution_platform")
3-
4-# Where every action runs: locally, against the BuildBuddy cache. The same
5-# arrangement jolt-native uses, and registered the same two ways — `[build]
6-# execution_platforms` in .buckconfig and `[parser] target_platform_detector_spec`
7-# there too, since setting only the first leaves toolchain-owned actions on the
8-# prelude's uncached default.
9-execution_platform(
10- name = "cache",
11- cpu_configuration = host_configuration.cpu,
12- os_configuration = host_configuration.os,
13- use_windows_path_separators = host_info().os.is_windows,
14- visibility = ["PUBLIC"],
15-)
16-
17-# The same platform, allowed to dispatch. Most of this graph cannot use it: the
18-# packaging steps name an Android SDK, a Chez cross build and an OpenSSL by
19-# absolute path, and a worker has none of them. The boot image compile is the
20-# one that could, which is why jolt reaches it through a manifest rather than a
21-# path — see android/BUCK.
22-execution_platform(
23- name = "remote",
24- cpu_configuration = host_configuration.cpu,
25- os_configuration = host_configuration.os,
26- remote_enabled = True,
27- remote_execution_properties = {
28- "OSFamily": "Linux",
29- "container-image": "docker://gcr.io/flame-public/rbe-ubuntu24-04:latest",
30- },
31- use_windows_path_separators = host_info().os.is_windows,
32- visibility = ["PUBLIC"],
33-)
deleted file mode 100644
@@ -1,33 +0,0 @@
1-load("@prelude//platforms:defs.bzl", "host_configuration")
2-load(":defs.bzl", "execution_platform")
3-
4-# Where every action runs: locally, against the BuildBuddy cache. The same
5-# arrangement jolt-native uses, and registered the same two ways — `[build]
6-# execution_platforms` in .buckconfig and `[parser] target_platform_detector_spec`
7-# there too, since setting only the first leaves toolchain-owned actions on the
8-# prelude's uncached default.
9-execution_platform(
10- name = "cache",
11- cpu_configuration = host_configuration.cpu,
12- os_configuration = host_configuration.os,
13- use_windows_path_separators = host_info().os.is_windows,
14- visibility = ["PUBLIC"],
15-)
16-
17-# The same platform, allowed to dispatch. Most of this graph cannot use it: the
18-# packaging steps name an Android SDK, a Chez cross build and an OpenSSL by
19-# absolute path, and a worker has none of them. The boot image compile is the
20-# one that could, which is why jolt reaches it through a manifest rather than a
21-# path — see android/BUCK.
22-execution_platform(
23- name = "remote",
24- cpu_configuration = host_configuration.cpu,
25- os_configuration = host_configuration.os,
26- remote_enabled = True,
27- remote_execution_properties = {
28- "OSFamily": "Linux",
29- "container-image": "docker://gcr.io/flame-public/rbe-ubuntu24-04:latest",
30- },
31- use_windows_path_separators = host_info().os.is_windows,
32- visibility = ["PUBLIC"],
33-)
deleted platforms/defs.bzl +0 -55
deleted file mode 100644
@@ -1,55 +0,0 @@
1-# The stock prelude//platforms:default with its cache switches flipped on.
2-#
3-# The prelude's own `execution_platform` rule is static Starlark — there is no
4-# buckconfig key that turns caching on for it — so the rule is copied here and
5-# its CommandExecutorConfig changed. Everything else mirrors the original
6-# exactly, so this platform stays configuration-identical to the default.
7-#
8-# Whether actions may run on a worker is an attribute now rather than a
9-# constant. It was false because it had to be: the toolchain named absolute
10-# paths inside this checkout, which no worker would have. Both compilers are
11-# dependencies now, so there is something to ship.
12-load("@prelude//cfg/exec_platform:marker.bzl", "get_exec_platform_marker")
13-
14-def _execution_platform_impl(ctx: AnalysisContext) -> list[Provider]:
15- constraints = dict()
16- constraints.update(ctx.attrs.cpu_configuration[ConfigurationInfo].constraints)
17- constraints.update(ctx.attrs.os_configuration[ConfigurationInfo].constraints)
18- cfg = ConfigurationInfo(constraints = constraints, values = {})
19-
20- name = ctx.label.raw_target()
21- platform = ExecutionPlatformInfo(
22- label = name,
23- configuration = cfg,
24- executor_config = CommandExecutorConfig(
25- local_enabled = ctx.attrs.local_enabled,
26- remote_enabled = ctx.attrs.remote_enabled,
27- remote_cache_enabled = True,
28- allow_cache_uploads = True,
29- remote_execution_properties = ctx.attrs.remote_execution_properties,
30- remote_execution_use_case = "buck2-default",
31- use_windows_path_separators = ctx.attrs.use_windows_path_separators,
32- ),
33- )
34-
35- return [
36- DefaultInfo(),
37- platform,
38- PlatformInfo(label = str(name), configuration = cfg),
39- ExecutionPlatformRegistrationInfo(
40- platforms = [platform],
41- exec_marker_constraint = get_exec_platform_marker(),
42- ),
43- ]
44-
45-execution_platform = rule(
46- impl = _execution_platform_impl,
47- attrs = {
48- "cpu_configuration": attrs.dep(providers = [ConfigurationInfo]),
49- "local_enabled": attrs.bool(default = True),
50- "remote_enabled": attrs.bool(default = False),
51- "remote_execution_properties": attrs.dict(attrs.string(), attrs.string(), default = {}),
52- "os_configuration": attrs.dep(providers = [ConfigurationInfo]),
53- "use_windows_path_separators": attrs.bool(),
54- },
55-)
deleted file mode 100644
@@ -1,55 +0,0 @@
1-# The stock prelude//platforms:default with its cache switches flipped on.
2-#
3-# The prelude's own `execution_platform` rule is static Starlark — there is no
4-# buckconfig key that turns caching on for it — so the rule is copied here and
5-# its CommandExecutorConfig changed. Everything else mirrors the original
6-# exactly, so this platform stays configuration-identical to the default.
7-#
8-# Whether actions may run on a worker is an attribute now rather than a
9-# constant. It was false because it had to be: the toolchain named absolute
10-# paths inside this checkout, which no worker would have. Both compilers are
11-# dependencies now, so there is something to ship.
12-load("@prelude//cfg/exec_platform:marker.bzl", "get_exec_platform_marker")
13-
14-def _execution_platform_impl(ctx: AnalysisContext) -> list[Provider]:
15- constraints = dict()
16- constraints.update(ctx.attrs.cpu_configuration[ConfigurationInfo].constraints)
17- constraints.update(ctx.attrs.os_configuration[ConfigurationInfo].constraints)
18- cfg = ConfigurationInfo(constraints = constraints, values = {})
19-
20- name = ctx.label.raw_target()
21- platform = ExecutionPlatformInfo(
22- label = name,
23- configuration = cfg,
24- executor_config = CommandExecutorConfig(
25- local_enabled = ctx.attrs.local_enabled,
26- remote_enabled = ctx.attrs.remote_enabled,
27- remote_cache_enabled = True,
28- allow_cache_uploads = True,
29- remote_execution_properties = ctx.attrs.remote_execution_properties,
30- remote_execution_use_case = "buck2-default",
31- use_windows_path_separators = ctx.attrs.use_windows_path_separators,
32- ),
33- )
34-
35- return [
36- DefaultInfo(),
37- platform,
38- PlatformInfo(label = str(name), configuration = cfg),
39- ExecutionPlatformRegistrationInfo(
40- platforms = [platform],
41- exec_marker_constraint = get_exec_platform_marker(),
42- ),
43- ]
44-
45-execution_platform = rule(
46- impl = _execution_platform_impl,
47- attrs = {
48- "cpu_configuration": attrs.dep(providers = [ConfigurationInfo]),
49- "local_enabled": attrs.bool(default = True),
50- "remote_enabled": attrs.bool(default = False),
51- "remote_execution_properties": attrs.dict(attrs.string(), attrs.string(), default = {}),
52- "os_configuration": attrs.dep(providers = [ConfigurationInfo]),
53- "use_windows_path_separators": attrs.bool(),
54- },
55-)
deleted scripts/BUCK +0 -33
deleted file mode 100644
@@ -1,33 +0,0 @@
1-# The pins, as artifacts.
2-#
3-# A manifest a build action resolves has to be an input to that action, so that
4-# bumping the version it names invalidates what was built with the old one.
5-# android/BUCK hands this one to the boot image compile along with a DotSlash
6-# to read it with.
7-export_file(
8- name = "jolt",
9- mode = "reference",
10- visibility = ["PUBLIC"],
11-)
12-
13-# The NDK lookup, and the driver that uses it. Inputs, so what links the glue
14-# is named by this repo rather than found next door: the APK's own link step
15-# needs a clang and an llvm-objcopy, and jolt-native is no longer required to
16-# be on the machine for that.
17-export_file(
18- name = "android-ndk-bin",
19- mode = "reference",
20- visibility = ["PUBLIC"],
21-)
22-
23-export_file(
24- name = "android-cc",
25- mode = "reference",
26- visibility = ["PUBLIC"],
27-)
28-
29-export_file(
30- name = "android-ndk.dotslash",
31- mode = "reference",
32- visibility = ["PUBLIC"],
33-)
deleted file mode 100644
@@ -1,33 +0,0 @@
1-# The pins, as artifacts.
2-#
3-# A manifest a build action resolves has to be an input to that action, so that
4-# bumping the version it names invalidates what was built with the old one.
5-# android/BUCK hands this one to the boot image compile along with a DotSlash
6-# to read it with.
7-export_file(
8- name = "jolt",
9- mode = "reference",
10- visibility = ["PUBLIC"],
11-)
12-
13-# The NDK lookup, and the driver that uses it. Inputs, so what links the glue
14-# is named by this repo rather than found next door: the APK's own link step
15-# needs a clang and an llvm-objcopy, and jolt-native is no longer required to
16-# be on the machine for that.
17-export_file(
18- name = "android-ndk-bin",
19- mode = "reference",
20- visibility = ["PUBLIC"],
21-)
22-
23-export_file(
24- name = "android-cc",
25- mode = "reference",
26- visibility = ["PUBLIC"],
27-)
28-
29-export_file(
30- name = "android-ndk.dotslash",
31- mode = "reference",
32- visibility = ["PUBLIC"],
33-)
deleted scripts/android-cc +0 -32
deleted file mode 100755
@@ -1,32 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; The NDK's clang, as the linker rustc runs for an Android target.
7-;;
8-;; The buck-side twin of this is toolchains/ndk.sh, which the C toolchain gets
9-;; as a dependency; both resolve the same archive, pinned in one place
10-;; android-ndk.dotslash beside this script. rustc reaches it through a shim
11-;; instead because -Clinker takes a plain string: rustc_flags cannot carry an
12-;; artifact path, so the linker has to be something with a stable name. The cfg
13-;; in toolchains/BUCK is what keeps two NDKs from sharing a cache entry.
14-;;
15-;; ANDROID_NDK_HOME wins if it is set, so a machine that already has an NDK
16-;; skips the download.
17-(require '[babashka.fs :as fs]
18- '[babashka.process :as p]
19- '[clojure.string :as str])
20-
21-(def here (fs/parent (fs/canonicalize *file*)))
22-(def api (or (not-empty (str (System/getenv "JOLT_ANDROID_API"))) "28"))
23-(def target (or (not-empty (str (System/getenv "JOLT_ANDROID_TARGET"))) "aarch64-linux-android"))
24-
25-;; android-ndk-bin is where the lookup lives, because an APK build wants the
26-;; other binaries out of the same archive.
27-(def bin (str/trim (:out (p/shell {:out :string} (str (fs/path here "android-ndk-bin"))))))
28-
29-(System/exit
30- (:exit @(apply p/process {:inherit true}
31- (str (fs/path bin "clang")) (str "--target=" target api)
32- *command-line-args*)))
deleted file mode 100755
@@ -1,32 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; The NDK's clang, as the linker rustc runs for an Android target.
7-;;
8-;; The buck-side twin of this is toolchains/ndk.sh, which the C toolchain gets
9-;; as a dependency; both resolve the same archive, pinned in one place
10-;; android-ndk.dotslash beside this script. rustc reaches it through a shim
11-;; instead because -Clinker takes a plain string: rustc_flags cannot carry an
12-;; artifact path, so the linker has to be something with a stable name. The cfg
13-;; in toolchains/BUCK is what keeps two NDKs from sharing a cache entry.
14-;;
15-;; ANDROID_NDK_HOME wins if it is set, so a machine that already has an NDK
16-;; skips the download.
17-(require '[babashka.fs :as fs]
18- '[babashka.process :as p]
19- '[clojure.string :as str])
20-
21-(def here (fs/parent (fs/canonicalize *file*)))
22-(def api (or (not-empty (str (System/getenv "JOLT_ANDROID_API"))) "28"))
23-(def target (or (not-empty (str (System/getenv "JOLT_ANDROID_TARGET"))) "aarch64-linux-android"))
24-
25-;; android-ndk-bin is where the lookup lives, because an APK build wants the
26-;; other binaries out of the same archive.
27-(def bin (str/trim (:out (p/shell {:out :string} (str (fs/path here "android-ndk-bin"))))))
28-
29-(System/exit
30- (:exit @(apply p/process {:inherit true}
31- (str (fs/path bin "clang")) (str "--target=" target api)
32- *command-line-args*)))
deleted scripts/android-glue.dotslash +0 -66
deleted file mode 100644
@@ -1,66 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The NativeActivity glue and the ABI's headers, from jolt-native's v0.1.3
4-// release.
5-//
6-// jolt_main.c is what libvidya's android_main dlopens: it boots Chez over the
7-// Jolt image this repo builds and registers every Vidya symbol by hand, since
8-// the loader will not answer for a symbol living in a different shared object.
9-// The headers beside it are what it includes. Both are jolt-native's; only the
10-// boot image is frq's.
11-//
12-// Source, not a binary, and pinned for the same reason the library is: an APK
13-// should not need a second checkout to build.
14-{
15- "name": "android-glue",
16- "platforms": {
17- "linux-x86_64": {
18- "size": 10652,
19- "hash": "sha256",
20- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
21- "format": "tar.gz",
22- "path": "jolt-native-android-glue/android/jolt_main.c",
23- "providers": [
24- {
25- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
26- }
27- ]
28- },
29- "linux-aarch64": {
30- "size": 10652,
31- "hash": "sha256",
32- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
33- "format": "tar.gz",
34- "path": "jolt-native-android-glue/android/jolt_main.c",
35- "providers": [
36- {
37- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
38- }
39- ]
40- },
41- "macos-x86_64": {
42- "size": 10652,
43- "hash": "sha256",
44- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
45- "format": "tar.gz",
46- "path": "jolt-native-android-glue/android/jolt_main.c",
47- "providers": [
48- {
49- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
50- }
51- ]
52- },
53- "macos-aarch64": {
54- "size": 10652,
55- "hash": "sha256",
56- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
57- "format": "tar.gz",
58- "path": "jolt-native-android-glue/android/jolt_main.c",
59- "providers": [
60- {
61- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
62- }
63- ]
64- }
65- }
66-}
deleted file mode 100644
@@ -1,66 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The NativeActivity glue and the ABI's headers, from jolt-native's v0.1.3
4-// release.
5-//
6-// jolt_main.c is what libvidya's android_main dlopens: it boots Chez over the
7-// Jolt image this repo builds and registers every Vidya symbol by hand, since
8-// the loader will not answer for a symbol living in a different shared object.
9-// The headers beside it are what it includes. Both are jolt-native's; only the
10-// boot image is frq's.
11-//
12-// Source, not a binary, and pinned for the same reason the library is: an APK
13-// should not need a second checkout to build.
14-{
15- "name": "android-glue",
16- "platforms": {
17- "linux-x86_64": {
18- "size": 10652,
19- "hash": "sha256",
20- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
21- "format": "tar.gz",
22- "path": "jolt-native-android-glue/android/jolt_main.c",
23- "providers": [
24- {
25- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
26- }
27- ]
28- },
29- "linux-aarch64": {
30- "size": 10652,
31- "hash": "sha256",
32- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
33- "format": "tar.gz",
34- "path": "jolt-native-android-glue/android/jolt_main.c",
35- "providers": [
36- {
37- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
38- }
39- ]
40- },
41- "macos-x86_64": {
42- "size": 10652,
43- "hash": "sha256",
44- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
45- "format": "tar.gz",
46- "path": "jolt-native-android-glue/android/jolt_main.c",
47- "providers": [
48- {
49- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
50- }
51- ]
52- },
53- "macos-aarch64": {
54- "size": 10652,
55- "hash": "sha256",
56- "digest": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
57- "format": "tar.gz",
58- "path": "jolt-native-android-glue/android/jolt_main.c",
59- "providers": [
60- {
61- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz"
62- }
63- ]
64- }
65- }
66-}
deleted scripts/android-ndk-bin +0 -32
deleted file mode 100755
@@ -1,32 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; Print the directory holding the NDK's clang and LLVM binutils.
7-;;
8-;; android-cc needs one of those binaries and an APK build needs others
9-;; llvm-objcopy, for the boot image blob so the lookup is here rather than
10-;; duplicated at each caller. ANDROID_NDK_HOME wins if it is set; otherwise the
11-;; pin in android-ndk.dotslash beside this script answers, downloading once.
12-(require '[babashka.fs :as fs]
13- '[babashka.process :as p]
14- '[clojure.string :as str])
15-
16-(def here (fs/parent (fs/canonicalize *file*)))
17-(def ndk (or (not-empty (str (System/getenv "ANDROID_NDK_HOME")))
18- (not-empty (str (System/getenv "ANDROID_NDK_ROOT")))))
19-
20-(if ndk
21- (if-let [bin (->> ["linux-x86_64" "darwin-x86_64"]
22- (map #(fs/path ndk "toolchains" "llvm" "prebuilt" % "bin"))
23- (filter fs/directory?)
24- first)]
25- (println (str bin))
26- (binding [*out* *err*]
27- (println (str "scripts/android-ndk-bin: no llvm prebuilt under " ndk))
28- (System/exit 1)))
29- (println (str (fs/parent
30- (str/trim (:out (p/shell {:out :string}
31- "dotslash" "--" "fetch"
32- (str (fs/path here "android-ndk.dotslash")))))))))
deleted file mode 100755
@@ -1,32 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; Print the directory holding the NDK's clang and LLVM binutils.
7-;;
8-;; android-cc needs one of those binaries and an APK build needs others
9-;; llvm-objcopy, for the boot image blob so the lookup is here rather than
10-;; duplicated at each caller. ANDROID_NDK_HOME wins if it is set; otherwise the
11-;; pin in android-ndk.dotslash beside this script answers, downloading once.
12-(require '[babashka.fs :as fs]
13- '[babashka.process :as p]
14- '[clojure.string :as str])
15-
16-(def here (fs/parent (fs/canonicalize *file*)))
17-(def ndk (or (not-empty (str (System/getenv "ANDROID_NDK_HOME")))
18- (not-empty (str (System/getenv "ANDROID_NDK_ROOT")))))
19-
20-(if ndk
21- (if-let [bin (->> ["linux-x86_64" "darwin-x86_64"]
22- (map #(fs/path ndk "toolchains" "llvm" "prebuilt" % "bin"))
23- (filter fs/directory?)
24- first)]
25- (println (str bin))
26- (binding [*out* *err*]
27- (println (str "scripts/android-ndk-bin: no llvm prebuilt under " ndk))
28- (System/exit 1)))
29- (println (str (fs/parent
30- (str/trim (:out (p/shell {:out :string}
31- "dotslash" "--" "fetch"
32- (str (fs/path here "android-ndk.dotslash")))))))))
deleted scripts/android-ndk.dotslash +0 -55
deleted file mode 100755
@@ -1,55 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The NDK, pinned the way every other tool here is.
4-//
5-// bin/clang is the path named, but the whole archive is what matters: the
6-// driver finds its sysroot, its resource directory and the rest of the LLVM
7-// binaries relative to itself, so the tree has to travel intact. The name is
8-// only what makes this a runnable shim as well as a manifest.
9-//
10-// Google publishes SHA-1 for these and nothing else, so the digests below were
11-// taken from the archives and checked against the SHA-1 in repository2-3.xml.
12-//
13-// There is no Linux/arm64 NDK. Both macOS entries are the x86_64 prebuilt,
14-// which is what Google ships an arm64 host runs it under Rosetta.
15-{
16- "name": "android-ndk-r29",
17- "platforms": {
18- "linux-x86_64": {
19- "size": 783549481,
20- "hash": "sha256",
21- "digest": "4abbbcdc842f3d4879206e9695d52709603e52dd68d3c1fff04b3b5e7a308ecf",
22- "format": "zip",
23- "path": "android-ndk-r29/toolchains/llvm/prebuilt/linux-x86_64/bin/clang",
24- "providers": [
25- {
26- "url": "https://dl.google.com/android/repository/android-ndk-r29-linux.zip"
27- }
28- ]
29- },
30- "macos-x86_64": {
31- "size": 1049519838,
32- "hash": "sha256",
33- "digest": "ce5e4b100ec5fe5be4eb3edcb2c02528824ff9cda3860f5304619be6c3da34d3",
34- "format": "zip",
35- "path": "android-ndk-r29/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang",
36- "providers": [
37- {
38- "url": "https://dl.google.com/android/repository/android-ndk-r29-darwin.zip"
39- }
40- ]
41- },
42- "macos-aarch64": {
43- "size": 1049519838,
44- "hash": "sha256",
45- "digest": "ce5e4b100ec5fe5be4eb3edcb2c02528824ff9cda3860f5304619be6c3da34d3",
46- "format": "zip",
47- "path": "android-ndk-r29/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang",
48- "providers": [
49- {
50- "url": "https://dl.google.com/android/repository/android-ndk-r29-darwin.zip"
51- }
52- ]
53- }
54- }
55-}
deleted file mode 100755
@@ -1,55 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The NDK, pinned the way every other tool here is.
4-//
5-// bin/clang is the path named, but the whole archive is what matters: the
6-// driver finds its sysroot, its resource directory and the rest of the LLVM
7-// binaries relative to itself, so the tree has to travel intact. The name is
8-// only what makes this a runnable shim as well as a manifest.
9-//
10-// Google publishes SHA-1 for these and nothing else, so the digests below were
11-// taken from the archives and checked against the SHA-1 in repository2-3.xml.
12-//
13-// There is no Linux/arm64 NDK. Both macOS entries are the x86_64 prebuilt,
14-// which is what Google ships an arm64 host runs it under Rosetta.
15-{
16- "name": "android-ndk-r29",
17- "platforms": {
18- "linux-x86_64": {
19- "size": 783549481,
20- "hash": "sha256",
21- "digest": "4abbbcdc842f3d4879206e9695d52709603e52dd68d3c1fff04b3b5e7a308ecf",
22- "format": "zip",
23- "path": "android-ndk-r29/toolchains/llvm/prebuilt/linux-x86_64/bin/clang",
24- "providers": [
25- {
26- "url": "https://dl.google.com/android/repository/android-ndk-r29-linux.zip"
27- }
28- ]
29- },
30- "macos-x86_64": {
31- "size": 1049519838,
32- "hash": "sha256",
33- "digest": "ce5e4b100ec5fe5be4eb3edcb2c02528824ff9cda3860f5304619be6c3da34d3",
34- "format": "zip",
35- "path": "android-ndk-r29/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang",
36- "providers": [
37- {
38- "url": "https://dl.google.com/android/repository/android-ndk-r29-darwin.zip"
39- }
40- ]
41- },
42- "macos-aarch64": {
43- "size": 1049519838,
44- "hash": "sha256",
45- "digest": "ce5e4b100ec5fe5be4eb3edcb2c02528824ff9cda3860f5304619be6c3da34d3",
46- "format": "zip",
47- "path": "android-ndk-r29/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang",
48- "providers": [
49- {
50- "url": "https://dl.google.com/android/repository/android-ndk-r29-darwin.zip"
51- }
52- ]
53- }
54- }
55-}
modified scripts/apk.bb +55 -13
@@ -3,13 +3,31 @@
33 exec "$(dirname "$0")/bb" "$0" "$@"
44 )
55
6-;; The APK, built as a graph.
6+;; The APK, out of the flake.
77 ;;
88 ;; apk.bb [build|install|run|log]
99 ;;
10-;; The build itself is android/BUCK; this only asks buck for the file and then
11-;; does what was asked with it. android/build-apk.bb is the same APK built step
12-;; by step instead, for when the graph is what is being doubted.
10+;; The build itself is nix/android.nix, reached as `.#apk`; this only asks nix
11+;; for the file and then does what was asked with it. Nothing here names an
12+;; Android SDK, an NDK, a Chez cross target or an OpenSSL: the derivation
13+;; builds or fetches every one of them, which is the difference between this
14+;; and the buck2 graph it replaces — that one was handed four hand-built paths
15+;; from the machine and stopped if any was missing.
16+;;
17+;; The APK is signed with a debug key generated inside the derivation, so the
18+;; output is installable and not reproducible; anything meant for a store gets
19+;; signed from `.#apk-unsigned` instead. See nix/android.nix.
20+;;
21+;; FRQ_NIX_STORE builds the whole graph somewhere else rather than here —
22+;;
23+;; FRQ_NIX_STORE=ssh-ng://eu.nixbuild.net scripts/apk.bb
24+;;
25+;; which is the shape android.nix asks for: with a `builders` entry instead,
26+;; nix copies every remotely-built output back, and androidenv's NDK is both
27+;; `preferLocalBuild` and absent from cache.nixos.org, so 3.1 GB of toolchain
28+;; is built here and uploaded. With the remote as the *store* only .drv files
29+;; go up. An install then needs the file here, so it is fetched back at the
30+;; end — one APK rather than the closure that made it.
1331 (require '[babashka.classpath :as cp])
1432 (cp/add-classpath (str (babashka.fs/parent *file*)))
1533 (require '[frq.paths :as paths]
@@ -23,17 +41,41 @@ exec "$(dirname "$0")/bb" "$0" "$@"
2341 "platform-tools" "adb"))))
2442 (def package "uk.nandi.frq")
2543
26-(defn apk []
27- (->> (paths/out (str (fs/path root "scripts" "buck.bb"))
28- "build" "--show-output" "//:apk")
29- str/split-lines
30- (some #(when (str/includes? % "frq.apk") (second (str/split % #"\s+"))))
31- (str root "/")))
44+;; --eval-store auto goes with a remote store and only with one: evaluation
45+;; wants this tree, which is here.
46+(def store
47+ (when-let [s (paths/env "FRQ_NIX_STORE" nil)]
48+ ["--store" s "--eval-store" "auto"]))
49+
50+;; Built without a `result` symlink: the path is what the caller wants, and a
51+;; symlink into a store that may not be this one is not a useful thing to leave
52+;; in the tree.
53+(defn build []
54+ (let [out (->> (paths/nix root (concat ["nix" "build" (str root "#apk")
55+ "--no-link" "--print-out-paths"]
56+ store))
57+ (apply paths/out)
58+ str/split-lines
59+ (filter #(str/starts-with? % "/nix/store/"))
60+ last)]
61+ (when-not out
62+ (paths/die "nix build printed no store path"))
63+ out))
64+
65+;; Off a remote store the path names a file on the builder, so adb has nothing
66+;; to open. `nix copy --no-check-sigs --from` brings just that one path here.
67+(defn local-file []
68+ (let [out (build)]
69+ (when store
70+ (apply p/shell (paths/nix root (concat ["nix" "copy" "--no-check-sigs"
71+ "--from" (paths/env "FRQ_NIX_STORE" nil)
72+ out]))))
73+ out))
3274
3375 (case action
34- "build" (println (apk))
35- "install" (p/shell adb "install" "-r" (apk))
36- "run" (let [file (apk)]
76+ "build" (println (build))
77+ "install" (p/shell adb "install" "-r" (local-file))
78+ "run" (let [file (local-file)]
3779 (p/shell adb "install" "-r" file)
3880 (p/shell adb "shell" "am" "force-stop" package)
3981 (p/shell adb "shell" "am" "start" "-n" (str package "/.FrqActivity")))
@@ -3,13 +3,31 @@
3 exec "$(dirname "$0")/bb" "$0" "$@"3 exec "$(dirname "$0")/bb" "$0" "$@"
4 )4 )
5 5
6-;; The APK, built as a graph.6+;; The APK, out of the flake.
7 ;;7 ;;
8 ;; apk.bb [build|install|run|log]8 ;; apk.bb [build|install|run|log]
9 ;;9 ;;
10-;; The build itself is android/BUCK; this only asks buck for the file and then10+;; The build itself is nix/android.nix, reached as `.#apk`; this only asks nix
11-;; does what was asked with it. android/build-apk.bb is the same APK built step11+;; for the file and then does what was asked with it. Nothing here names an
12-;; by step instead, for when the graph is what is being doubted.12+;; Android SDK, an NDK, a Chez cross target or an OpenSSL: the derivation
13+;; builds or fetches every one of them, which is the difference between this
14+;; and the buck2 graph it replaces — that one was handed four hand-built paths
15+;; from the machine and stopped if any was missing.
16+;;
17+;; The APK is signed with a debug key generated inside the derivation, so the
18+;; output is installable and not reproducible; anything meant for a store gets
19+;; signed from `.#apk-unsigned` instead. See nix/android.nix.
20+;;
21+;; FRQ_NIX_STORE builds the whole graph somewhere else rather than here —
22+;;
23+;; FRQ_NIX_STORE=ssh-ng://eu.nixbuild.net scripts/apk.bb
24+;;
25+;; which is the shape android.nix asks for: with a `builders` entry instead,
26+;; nix copies every remotely-built output back, and androidenv's NDK is both
27+;; `preferLocalBuild` and absent from cache.nixos.org, so 3.1 GB of toolchain
28+;; is built here and uploaded. With the remote as the *store* only .drv files
29+;; go up. An install then needs the file here, so it is fetched back at the
30+;; end — one APK rather than the closure that made it.
13 (require '[babashka.classpath :as cp])31 (require '[babashka.classpath :as cp])
14 (cp/add-classpath (str (babashka.fs/parent *file*)))32 (cp/add-classpath (str (babashka.fs/parent *file*)))
15 (require '[frq.paths :as paths]33 (require '[frq.paths :as paths]
@@ -23,17 +41,41 @@ exec "$(dirname "$0")/bb" "$0" "$@"
23 "platform-tools" "adb"))))41 "platform-tools" "adb"))))
24 (def package "uk.nandi.frq")42 (def package "uk.nandi.frq")
25 43
26-(defn apk []44+;; --eval-store auto goes with a remote store and only with one: evaluation
27- (->> (paths/out (str (fs/path root "scripts" "buck.bb"))45+;; wants this tree, which is here.
28- "build" "--show-output" "//:apk")46+(def store
29- str/split-lines47+ (when-let [s (paths/env "FRQ_NIX_STORE" nil)]
30- (some #(when (str/includes? % "frq.apk") (second (str/split % #"\s+"))))48+ ["--store" s "--eval-store" "auto"]))
31- (str root "/")))49+
50+;; Built without a `result` symlink: the path is what the caller wants, and a
51+;; symlink into a store that may not be this one is not a useful thing to leave
52+;; in the tree.
53+(defn build []
54+ (let [out (->> (paths/nix root (concat ["nix" "build" (str root "#apk")
55+ "--no-link" "--print-out-paths"]
56+ store))
57+ (apply paths/out)
58+ str/split-lines
59+ (filter #(str/starts-with? % "/nix/store/"))
60+ last)]
61+ (when-not out
62+ (paths/die "nix build printed no store path"))
63+ out))
64+
65+;; Off a remote store the path names a file on the builder, so adb has nothing
66+;; to open. `nix copy --no-check-sigs --from` brings just that one path here.
67+(defn local-file []
68+ (let [out (build)]
69+ (when store
70+ (apply p/shell (paths/nix root (concat ["nix" "copy" "--no-check-sigs"
71+ "--from" (paths/env "FRQ_NIX_STORE" nil)
72+ out]))))
73+ out))
32 74
33 (case action75 (case action
34- "build" (println (apk))76+ "build" (println (build))
35- "install" (p/shell adb "install" "-r" (apk))77+ "install" (p/shell adb "install" "-r" (local-file))
36- "run" (let [file (apk)]78+ "run" (let [file (local-file)]
37 (p/shell adb "install" "-r" file)79 (p/shell adb "install" "-r" file)
38 (p/shell adb "shell" "am" "force-stop" package)80 (p/shell adb "shell" "am" "force-stop" package)
39 (p/shell adb "shell" "am" "start" "-n" (str package "/.FrqActivity")))81 (p/shell adb "shell" "am" "start" "-n" (str package "/.FrqActivity")))
modified scripts/bb +49 -64
@@ -1,65 +1,50 @@
1-#!/usr/bin/env dotslash
1+#!/bin/sh
2+# babashka, which the scripts here are written in.
3+#
4+# A build script wants the things a shell is bad at — reading deps.edn, hashing
5+# a file set, holding a path in a variable without quoting it three times — and
6+# Clojure is already the language this repo is written in.
7+#
8+# This used to be a DotSlash manifest, pinning a release of babashka the way
9+# the native libraries are pinned. It is the flake's now, for the reason the
10+# flake exists: a bb from `nixpkgs` is one this tree already names a version
11+# of, so a checkout needs nix and nothing else. DotSlash still answers for the
12+# desktop libraries — those are jolt-native's releases, which no nixpkgs has —
13+# but nothing has to be installed to reach *them* any more either, because the
14+# script that fetches them starts here.
15+#
16+# Three answers, in order:
17+#
18+# bb on PATH the dev shell puts one there, and so does a machine that
19+# has its own; either is what the caller meant
20+# the flake built once and kept alive by the symlink under build/,
21+# which is a gc root as well as a cache
22+# the container nix is not on every host this runs on — see CLAUDE.md —
23+# so a host without one re-enters this script where nix is,
24+# which is where the scripts want to be anyway
25+set -e
226
3-// babashka, which the scripts here are written in.
4-//
5-// A build script wants the things a shell is bad at reading deps.edn,
6-// hashing a file set, holding a path in a variable without quoting it three
7-// times and Clojure is already the language this repo is written in. Pinned
8-// like every other tool, so the script a person runs at a terminal is the one
9-// buck runs in an action.
10-//
11-// The static Linux builds, because a build machine's glibc is not ours to
12-// assume; macOS has no static option and does not need one.
13-{
14- "name": "bb",
15- "platforms": {
16- "linux-x86_64": {
17- "size": 26177709,
18- "hash": "sha256",
19- "digest": "eb3edd128276f0b6fbdefcb18dc7d42652a95ea409a81b34f08e36b8ac3cbc3c",
20- "format": "tar.gz",
21- "path": "bb",
22- "providers": [
23- {
24- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-linux-amd64-static.tar.gz"
25- }
26- ]
27- },
28- "linux-aarch64": {
29- "size": 28271754,
30- "hash": "sha256",
31- "digest": "0efd6ef36b93ea2f0ae6ebf9d1bcd1a66167c2f41c17e990659aa067654437e8",
32- "format": "tar.gz",
33- "path": "bb",
34- "providers": [
35- {
36- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-linux-aarch64-static.tar.gz"
37- }
38- ]
39- },
40- "macos-x86_64": {
41- "size": 26050398,
42- "hash": "sha256",
43- "digest": "ebbfdf159e8d5ee8b7015b15c6558b2039fe76478de893cf317c8c50805340de",
44- "format": "tar.gz",
45- "path": "bb",
46- "providers": [
47- {
48- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-macos-amd64.tar.gz"
49- }
50- ]
51- },
52- "macos-aarch64": {
53- "size": 26548984,
54- "hash": "sha256",
55- "digest": "f7d18c3ab11bb4ad0e32a45c1ae40ae25911d5fa06ba4ded07cb90b8af158077",
56- "format": "tar.gz",
57- "path": "bb",
58- "providers": [
59- {
60- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-macos-aarch64.tar.gz"
61- }
62- ]
63- }
64- }
65-}
27+root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
28+
29+if command -v bb >/dev/null 2>&1; then
30+ exec bb "$@"
31+fi
32+
33+link="$root/build/bb"
34+
35+if command -v nix >/dev/null 2>&1; then
36+ # --out-link rather than --no-link: the path has to survive a gc, and the
37+ # symlink is what roots it. Rebuilt only when it is gone or dangling, so
38+ # the usual case is one readlink.
39+ [ -x "$link/bin/bb" ] || nix build "$root#bb" --out-link "$link" >&2
40+ exec "$link/bin/bb" "$@"
41+fi
42+
43+if [ -n "$FRQ_BB_REENTERED" ]; then
44+ echo "scripts/bb: no bb and no nix, inside the container too." >&2
45+ echo "Install babashka, or put a nix on this machine." >&2
46+ exit 1
47+fi
48+
49+exec distrobox enter arch -- bash -lc \
50+ "cd $root && FRQ_BB_REENTERED=1 exec scripts/bb \"\$@\"" -- "$@"
@@ -1,65 +1,50 @@
1-#!/usr/bin/env dotslash1+#!/bin/sh
2+# babashka, which the scripts here are written in.
3+#
4+# A build script wants the things a shell is bad at — reading deps.edn, hashing
5+# a file set, holding a path in a variable without quoting it three times — and
6+# Clojure is already the language this repo is written in.
7+#
8+# This used to be a DotSlash manifest, pinning a release of babashka the way
9+# the native libraries are pinned. It is the flake's now, for the reason the
10+# flake exists: a bb from `nixpkgs` is one this tree already names a version
11+# of, so a checkout needs nix and nothing else. DotSlash still answers for the
12+# desktop libraries — those are jolt-native's releases, which no nixpkgs has —
13+# but nothing has to be installed to reach *them* any more either, because the
14+# script that fetches them starts here.
15+#
16+# Three answers, in order:
17+#
18+# bb on PATH the dev shell puts one there, and so does a machine that
19+# has its own; either is what the caller meant
20+# the flake built once and kept alive by the symlink under build/,
21+# which is a gc root as well as a cache
22+# the container nix is not on every host this runs on — see CLAUDE.md —
23+# so a host without one re-enters this script where nix is,
24+# which is where the scripts want to be anyway
25+set -e
2 26
3-// babashka, which the scripts here are written in.27+root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
4-//28+
5-// A build script wants the things a shell is bad at reading deps.edn,29+if command -v bb >/dev/null 2>&1; then
6-// hashing a file set, holding a path in a variable without quoting it three30+ exec bb "$@"
7-// times and Clojure is already the language this repo is written in. Pinned31+fi
8-// like every other tool, so the script a person runs at a terminal is the one32+
9-// buck runs in an action.33+link="$root/build/bb"
10-//34+
11-// The static Linux builds, because a build machine's glibc is not ours to35+if command -v nix >/dev/null 2>&1; then
12-// assume; macOS has no static option and does not need one.36+ # --out-link rather than --no-link: the path has to survive a gc, and the
13-{37+ # symlink is what roots it. Rebuilt only when it is gone or dangling, so
14- "name": "bb",38+ # the usual case is one readlink.
15- "platforms": {39+ [ -x "$link/bin/bb" ] || nix build "$root#bb" --out-link "$link" >&2
16- "linux-x86_64": {40+ exec "$link/bin/bb" "$@"
17- "size": 26177709,41+fi
18- "hash": "sha256",42+
19- "digest": "eb3edd128276f0b6fbdefcb18dc7d42652a95ea409a81b34f08e36b8ac3cbc3c",43+if [ -n "$FRQ_BB_REENTERED" ]; then
20- "format": "tar.gz",44+ echo "scripts/bb: no bb and no nix, inside the container too." >&2
21- "path": "bb",45+ echo "Install babashka, or put a nix on this machine." >&2
22- "providers": [46+ exit 1
23- {47+fi
24- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-linux-amd64-static.tar.gz"48+
25- }49+exec distrobox enter arch -- bash -lc \
26- ]50+ "cd $root && FRQ_BB_REENTERED=1 exec scripts/bb \"\$@\"" -- "$@"
27- },
28- "linux-aarch64": {
29- "size": 28271754,
30- "hash": "sha256",
31- "digest": "0efd6ef36b93ea2f0ae6ebf9d1bcd1a66167c2f41c17e990659aa067654437e8",
32- "format": "tar.gz",
33- "path": "bb",
34- "providers": [
35- {
36- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-linux-aarch64-static.tar.gz"
37- }
38- ]
39- },
40- "macos-x86_64": {
41- "size": 26050398,
42- "hash": "sha256",
43- "digest": "ebbfdf159e8d5ee8b7015b15c6558b2039fe76478de893cf317c8c50805340de",
44- "format": "tar.gz",
45- "path": "bb",
46- "providers": [
47- {
48- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-macos-amd64.tar.gz"
49- }
50- ]
51- },
52- "macos-aarch64": {
53- "size": 26548984,
54- "hash": "sha256",
55- "digest": "f7d18c3ab11bb4ad0e32a45c1ae40ae25911d5fa06ba4ded07cb90b8af158077",
56- "format": "tar.gz",
57- "path": "bb",
58- "providers": [
59- {
60- "url": "https://github.com/babashka/babashka/releases/download/v1.13.220/babashka-1.13.220-macos-aarch64.tar.gz"
61- }
62- ]
63- }
64- }
65-}
deleted scripts/buck.bb +0 -43
deleted file mode 100755
@@ -1,43 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; buck2, with the machine's paths written where the BUCK files can read them.
7-;;
8-;; The same arrangement jolt-native uses, and for the same reason: a BUCK file
9-;; may not look around the machine, and these answers differ on every one.
10-;; Generated rather than committed, so no checkout carries another's paths.
11-(require '[babashka.classpath :as cp])
12-(cp/add-classpath (str (babashka.fs/parent *file*)))
13-(require '[frq.paths :as paths]
14- '[babashka.fs :as fs]
15- '[babashka.process :as p])
16-
17-(def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
18-(def android-home (paths/env "ANDROID_HOME" (str (fs/path (fs/home) ".local" "share" "android-sdk"))))
19-(def chez (paths/env "CHEZ_ANDROID" (str (fs/path (fs/home) ".cache" "vidya-chez-android"))))
20-(def openssl (paths/env "OPENSSL_ANDROID" (str (fs/path (fs/home) ".cache" "frq-openssl-android" "lib"))))
21-
22-(paths/require-paths! "path"
23- [(fs/path android-home "build-tools" "36.0.0" "aapt2")
24- (fs/path android-home "platforms" "android-36" "android.jar")
25- (fs/path chez "boot" "tarm64le" "scheme.boot")
26- (fs/path openssl "libssl.so")])
27-
28-;; The boot image is compiled from source roots outside this cell — glimmer and
29-;; glimmer-vidya, out of the jolt cache — which cannot be action inputs. Hash
30-;; them here so the digest reaches the action instead. See android/BUCK.
31-(def boot-stamp
32- (paths/out (str (fs/path root "android" "build-jolt-boot.bb")) "--stamp"))
33-
34-(spit (str (fs/path root ".buckconfig.local"))
35- (str "[frq]\n"
36- " android_home = " android-home "\n"
37- " chez_android = " chez "\n"
38- " openssl_android = " openssl "\n"
39- " boot_stamp = " boot-stamp "\n"))
40-
41-(System/exit
42- (:exit @(apply p/process {:inherit true :dir root}
43- (str (fs/path root "scripts" "buck2")) *command-line-args*)))
deleted file mode 100755
@@ -1,43 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; buck2, with the machine's paths written where the BUCK files can read them.
7-;;
8-;; The same arrangement jolt-native uses, and for the same reason: a BUCK file
9-;; may not look around the machine, and these answers differ on every one.
10-;; Generated rather than committed, so no checkout carries another's paths.
11-(require '[babashka.classpath :as cp])
12-(cp/add-classpath (str (babashka.fs/parent *file*)))
13-(require '[frq.paths :as paths]
14- '[babashka.fs :as fs]
15- '[babashka.process :as p])
16-
17-(def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
18-(def android-home (paths/env "ANDROID_HOME" (str (fs/path (fs/home) ".local" "share" "android-sdk"))))
19-(def chez (paths/env "CHEZ_ANDROID" (str (fs/path (fs/home) ".cache" "vidya-chez-android"))))
20-(def openssl (paths/env "OPENSSL_ANDROID" (str (fs/path (fs/home) ".cache" "frq-openssl-android" "lib"))))
21-
22-(paths/require-paths! "path"
23- [(fs/path android-home "build-tools" "36.0.0" "aapt2")
24- (fs/path android-home "platforms" "android-36" "android.jar")
25- (fs/path chez "boot" "tarm64le" "scheme.boot")
26- (fs/path openssl "libssl.so")])
27-
28-;; The boot image is compiled from source roots outside this cell — glimmer and
29-;; glimmer-vidya, out of the jolt cache — which cannot be action inputs. Hash
30-;; them here so the digest reaches the action instead. See android/BUCK.
31-(def boot-stamp
32- (paths/out (str (fs/path root "android" "build-jolt-boot.bb")) "--stamp"))
33-
34-(spit (str (fs/path root ".buckconfig.local"))
35- (str "[frq]\n"
36- " android_home = " android-home "\n"
37- " chez_android = " chez "\n"
38- " openssl_android = " openssl "\n"
39- " boot_stamp = " boot-stamp "\n"))
40-
41-(System/exit
42- (:exit @(apply p/process {:inherit true :dir root}
43- (str (fs/path root "scripts" "buck2")) *command-line-args*)))
deleted scripts/buck2 +0 -67
deleted file mode 100755
@@ -1,67 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-{
4- "name": "buck2",
5- "platforms": {
6- "linux-x86_64": {
7- "size": 39303524,
8- "hash": "blake3",
9- "digest": "afff180bc257de220f393ed4551693d877849cda012ac39cf9d4f7a27693848e",
10- "format": "zst",
11- "path": "buck2",
12- "providers": [
13- {
14- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-x86_64-unknown-linux-musl.zst"
15- }
16- ]
17- },
18- "linux-aarch64": {
19- "size": 37790120,
20- "hash": "blake3",
21- "digest": "52e2182d65630a0b68bb33ca9ae72b64c028668e5d02fe5fd46d8fcb3c361918",
22- "format": "zst",
23- "path": "buck2",
24- "providers": [
25- {
26- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-aarch64-unknown-linux-musl.zst"
27- }
28- ]
29- },
30- "macos-x86_64": {
31- "size": 36655230,
32- "hash": "blake3",
33- "digest": "1959b2f85dbba714f5d1f7824e813b0fca81224117a51cec7db17b8ae9fc1012",
34- "format": "zst",
35- "path": "buck2",
36- "providers": [
37- {
38- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-x86_64-apple-darwin.zst"
39- }
40- ]
41- },
42- "macos-aarch64": {
43- "size": 34435267,
44- "hash": "blake3",
45- "digest": "15ff15f1c10b8ddb3e8b3d43ca73964dec3719a514d805119c5e5963257daefe",
46- "format": "zst",
47- "path": "buck2",
48- "providers": [
49- {
50- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-aarch64-apple-darwin.zst"
51- }
52- ]
53- },
54- "windows-x86_64": {
55- "size": 31803375,
56- "hash": "blake3",
57- "digest": "ab36fa3ee1b4fe2e597b8bf0bfa27f815b64ff3f520b6456fe67cb48b24f85e6",
58- "format": "zst",
59- "path": "buck2.exe",
60- "providers": [
61- {
62- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-x86_64-pc-windows-msvc.exe.zst"
63- }
64- ]
65- }
66- }
67-}
deleted file mode 100755
@@ -1,67 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-{
4- "name": "buck2",
5- "platforms": {
6- "linux-x86_64": {
7- "size": 39303524,
8- "hash": "blake3",
9- "digest": "afff180bc257de220f393ed4551693d877849cda012ac39cf9d4f7a27693848e",
10- "format": "zst",
11- "path": "buck2",
12- "providers": [
13- {
14- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-x86_64-unknown-linux-musl.zst"
15- }
16- ]
17- },
18- "linux-aarch64": {
19- "size": 37790120,
20- "hash": "blake3",
21- "digest": "52e2182d65630a0b68bb33ca9ae72b64c028668e5d02fe5fd46d8fcb3c361918",
22- "format": "zst",
23- "path": "buck2",
24- "providers": [
25- {
26- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-aarch64-unknown-linux-musl.zst"
27- }
28- ]
29- },
30- "macos-x86_64": {
31- "size": 36655230,
32- "hash": "blake3",
33- "digest": "1959b2f85dbba714f5d1f7824e813b0fca81224117a51cec7db17b8ae9fc1012",
34- "format": "zst",
35- "path": "buck2",
36- "providers": [
37- {
38- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-x86_64-apple-darwin.zst"
39- }
40- ]
41- },
42- "macos-aarch64": {
43- "size": 34435267,
44- "hash": "blake3",
45- "digest": "15ff15f1c10b8ddb3e8b3d43ca73964dec3719a514d805119c5e5963257daefe",
46- "format": "zst",
47- "path": "buck2",
48- "providers": [
49- {
50- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-aarch64-apple-darwin.zst"
51- }
52- ]
53- },
54- "windows-x86_64": {
55- "size": 31803375,
56- "hash": "blake3",
57- "digest": "ab36fa3ee1b4fe2e597b8bf0bfa27f815b64ff3f520b6456fe67cb48b24f85e6",
58- "format": "zst",
59- "path": "buck2.exe",
60- "providers": [
61- {
62- "url": "https://github.com/facebook/buck2/releases/download/2026-08-22/buck2-x86_64-pc-windows-msvc.exe.zst"
63- }
64- ]
65- }
66- }
67-}
modified scripts/bump-jolt-native.bb +47 -9
@@ -9,16 +9,23 @@ exec "$(dirname "$0")/bb" "$0" "$@"
99 ;; scripts/bump-jolt-native.bb v0.1.3 # a named one
1010 ;;
1111 ;; A jolt-native bump is four facts in three places: the tag, the URL, the size
12-;; and the digest of each archive in scripts/*.dotslash, the release's commit in
13-;; deps.edn, and the table buck reads, which is generated from the first. Done
14-;; by hand it is a lot of copying between a browser and a sha256sum, and the
15-;; failure mode is a manifest that still says v0.1.2 while its digest is v0.1.3's
16-;; — which DotSlash catches, but only on the machine that next fetches it.
12+;; and the digest of each archive in scripts/*.dotslash, the same URL and digest
13+;; for the Android archives in nix/android.nix, and the release's commit in
14+;; deps.edn. Done by hand it is a lot of copying between a browser and a
15+;; sha256sum, and the failure mode is a pin that still says v0.1.2 while its
16+;; digest is v0.1.3's — which DotSlash catches, but only on the machine that
17+;; next fetches it, and which fetchurl catches at build time and no sooner.
18+;;
19+;; The two places exist because the two builds fetch differently and neither can
20+;; read the other's pin: `just lib` and a released-halves run resolve DotSlash
21+;; manifests, and the APK is a nix derivation, whose inputs have to be fetchurl.
22+;; The digests are the same bytes either way — DotSlash's `digest` is over the
23+;; archive, which is what fetchurl hashes too.
1724 ;;
1825 ;; So: ask GitLab what the release holds, fetch each archive once, weigh it,
19-;; write the manifests back, put the release's commit in deps.edn — which is
20-;; what jolt resolves glimmer-vidya from, and so what the boot image compiles
21-;; against — and re-run dotslash-to-buck.
26+;; write the manifests and nix/android.nix back, and put the release's commit in
27+;; deps.edn — which is what jolt resolves glimmer-vidya from, and so what the
28+;; boot image compiles against.
2229 ;;
2330 ;; Nothing here decides whether the new release is a good idea. It only makes
2431 ;; the tree say one version instead of two.
@@ -126,6 +133,37 @@ exec "$(dirname "$0")/bb" "$0" "$@"
126133 (spit (str file) (str head (json/generate-string (assoc json "platforms" updated) {:pretty pretty}) "\n"))
127134 (println (str " " (fs/file-name file)))))
128135
136+;; nix/android.nix fetches two of the same archives as `pkgs.fetchurl`, because
137+;; a derivation cannot resolve a DotSlash manifest: the fetch is the input, and
138+;; an input has to be a fixed-output derivation with the digest written down.
139+;; Rewritten as text for the same reason deps.edn is — the file is mostly the
140+;; comments explaining each step, and there is no round-tripping Nix as data
141+;; here anyway.
142+;;
143+;; Every fetchurl whose url points at the repo, whatever it is called: a third
144+;; archive appearing in android.nix should move with the other two rather than
145+;; be remembered about.
146+(defn bump-nix! [tmp tag]
147+ (let [file (fs/path root "nix" "android.nix")
148+ text (slurp (str file))
149+ ;; url and sha256 as one match, so the pair moves together. Anything
150+ ;; between them — a comment, another attribute — would not match, and
151+ ;; not matching is the safe direction: it leaves the pin alone and says
152+ ;; nothing was written.
153+ pattern (re-pattern (str "(url\\s*=\\s*\")(" (java.util.regex.Pattern/quote repo)
154+ "[^\"]*)(\";\\s*\n\\s*sha256\\s*=\\s*\")([^\"]*)(\")"))
155+ seen (atom [])
156+ updated (str/replace text pattern
157+ (fn [[_ head url mid _ tail]]
158+ (let [new-url (retag url (tag-of url) tag)
159+ {:keys [digest]} (weigh tmp new-url)]
160+ (swap! seen conj (last (str/split new-url #"/")))
161+ (str head new-url mid digest tail))))]
162+ (when (empty? @seen)
163+ (paths/die (str "no fetchurl in " file " points at " repo)))
164+ (spit (str file) updated)
165+ (doseq [name @seen] (println (str " nix/android.nix " name)))))
166+
129167 ;; deps.edn takes glimmer-vidya as a git dependency, and the boot image is
130168 ;; compiled from the source root jolt resolves that to. Replaced as text rather
131169 ;; than round-tripped as EDN: the file is mostly comments explaining why each
@@ -152,7 +190,7 @@ exec "$(dirname "$0")/bb" "$0" "$@"
152190 (try
153191 (doseq [m files] (rewrite m tmp tag))
154192 (finally (fs/delete-tree tmp)))
193+ (bump-nix! tmp tag)
155194 (bump-deps! commit)
156- (p/shell (str (fs/path here "dotslash-to-buck")))
157195 (println (str "\nNow: git diff, then `just lib` and `just apk` — the pins are "
158196 "written, nothing is built.")))
@@ -9,16 +9,23 @@ exec "$(dirname "$0")/bb" "$0" "$@"
9 ;; scripts/bump-jolt-native.bb v0.1.3 # a named one9 ;; scripts/bump-jolt-native.bb v0.1.3 # a named one
10 ;;10 ;;
11 ;; A jolt-native bump is four facts in three places: the tag, the URL, the size11 ;; A jolt-native bump is four facts in three places: the tag, the URL, the size
12-;; and the digest of each archive in scripts/*.dotslash, the release's commit in12+;; and the digest of each archive in scripts/*.dotslash, the same URL and digest
13-;; deps.edn, and the table buck reads, which is generated from the first. Done13+;; for the Android archives in nix/android.nix, and the release's commit in
14-;; by hand it is a lot of copying between a browser and a sha256sum, and the14+;; deps.edn. Done by hand it is a lot of copying between a browser and a
15-;; failure mode is a manifest that still says v0.1.2 while its digest is v0.1.3's15+;; sha256sum, and the failure mode is a pin that still says v0.1.2 while its
16-;; — which DotSlash catches, but only on the machine that next fetches it.16+;; digest is v0.1.3's — which DotSlash catches, but only on the machine that
17+;; next fetches it, and which fetchurl catches at build time and no sooner.
18+;;
19+;; The two places exist because the two builds fetch differently and neither can
20+;; read the other's pin: `just lib` and a released-halves run resolve DotSlash
21+;; manifests, and the APK is a nix derivation, whose inputs have to be fetchurl.
22+;; The digests are the same bytes either way — DotSlash's `digest` is over the
23+;; archive, which is what fetchurl hashes too.
17 ;;24 ;;
18 ;; So: ask GitLab what the release holds, fetch each archive once, weigh it,25 ;; So: ask GitLab what the release holds, fetch each archive once, weigh it,
19-;; write the manifests back, put the release's commit in deps.edn — which is26+;; write the manifests and nix/android.nix back, and put the release's commit in
20-;; what jolt resolves glimmer-vidya from, and so what the boot image compiles27+;; deps.edn — which is what jolt resolves glimmer-vidya from, and so what the
21-;; against — and re-run dotslash-to-buck.28+;; boot image compiles against.
22 ;;29 ;;
23 ;; Nothing here decides whether the new release is a good idea. It only makes30 ;; Nothing here decides whether the new release is a good idea. It only makes
24 ;; the tree say one version instead of two.31 ;; the tree say one version instead of two.
@@ -126,6 +133,37 @@ exec "$(dirname "$0")/bb" "$0" "$@"
126 (spit (str file) (str head (json/generate-string (assoc json "platforms" updated) {:pretty pretty}) "\n"))133 (spit (str file) (str head (json/generate-string (assoc json "platforms" updated) {:pretty pretty}) "\n"))
127 (println (str " " (fs/file-name file)))))134 (println (str " " (fs/file-name file)))))
128 135
136+;; nix/android.nix fetches two of the same archives as `pkgs.fetchurl`, because
137+;; a derivation cannot resolve a DotSlash manifest: the fetch is the input, and
138+;; an input has to be a fixed-output derivation with the digest written down.
139+;; Rewritten as text for the same reason deps.edn is — the file is mostly the
140+;; comments explaining each step, and there is no round-tripping Nix as data
141+;; here anyway.
142+;;
143+;; Every fetchurl whose url points at the repo, whatever it is called: a third
144+;; archive appearing in android.nix should move with the other two rather than
145+;; be remembered about.
146+(defn bump-nix! [tmp tag]
147+ (let [file (fs/path root "nix" "android.nix")
148+ text (slurp (str file))
149+ ;; url and sha256 as one match, so the pair moves together. Anything
150+ ;; between them — a comment, another attribute — would not match, and
151+ ;; not matching is the safe direction: it leaves the pin alone and says
152+ ;; nothing was written.
153+ pattern (re-pattern (str "(url\\s*=\\s*\")(" (java.util.regex.Pattern/quote repo)
154+ "[^\"]*)(\";\\s*\n\\s*sha256\\s*=\\s*\")([^\"]*)(\")"))
155+ seen (atom [])
156+ updated (str/replace text pattern
157+ (fn [[_ head url mid _ tail]]
158+ (let [new-url (retag url (tag-of url) tag)
159+ {:keys [digest]} (weigh tmp new-url)]
160+ (swap! seen conj (last (str/split new-url #"/")))
161+ (str head new-url mid digest tail))))]
162+ (when (empty? @seen)
163+ (paths/die (str "no fetchurl in " file " points at " repo)))
164+ (spit (str file) updated)
165+ (doseq [name @seen] (println (str " nix/android.nix " name)))))
166+
129 ;; deps.edn takes glimmer-vidya as a git dependency, and the boot image is167 ;; deps.edn takes glimmer-vidya as a git dependency, and the boot image is
130 ;; compiled from the source root jolt resolves that to. Replaced as text rather168 ;; compiled from the source root jolt resolves that to. Replaced as text rather
131 ;; than round-tripped as EDN: the file is mostly comments explaining why each169 ;; than round-tripped as EDN: the file is mostly comments explaining why each
@@ -152,7 +190,7 @@ exec "$(dirname "$0")/bb" "$0" "$@"
152 (try190 (try
153 (doseq [m files] (rewrite m tmp tag))191 (doseq [m files] (rewrite m tmp tag))
154 (finally (fs/delete-tree tmp)))192 (finally (fs/delete-tree tmp)))
193+ (bump-nix! tmp tag)
155 (bump-deps! commit)194 (bump-deps! commit)
156- (p/shell (str (fs/path here "dotslash-to-buck")))
157 (println (str "\nNow: git diff, then `just lib` and `just apk` — the pins are "195 (println (str "\nNow: git diff, then `just lib` and `just apk` — the pins are "
158 "written, nothing is built.")))196 "written, nothing is built.")))
deleted scripts/dotslash-to-buck +0 -92
deleted file mode 100755
@@ -1,92 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; Generate buck2 http_archive data from the DotSlash files beside this script.
7-;;
8-;; DotSlash is where a tool's version, URL and digest are written down. buck
9-;; needs the same three facts to fetch that tool itself it cannot use the
10-;; shim, which resolves on the machine at run time and so is neither an action
11-;; input nor anything a remote worker could be given. Rather than write them
12-;; twice and let them drift, this reads the manifests and emits the table buck
13-;; reads.
14-;;
15-;; just sync-dist # after editing any scripts/*.dotslash
16-;;
17-;; The DotSlash format is JSON with a `//` shebang line on top: one entry per
18-;; platform, each with a url, a size, a digest and the path of the binary
19-;; inside the archive. Only the archive itself is wanted here; the path inside
20-;; it is the shim's business, and the toolchain rules name what they need.
21-(require '[babashka.fs :as fs]
22- '[cheshire.core :as json]
23- '[clojure.string :as str])
24-
25-(def here (fs/parent (fs/canonicalize *file*)))
26-(def out-file (fs/path (fs/parent here) "toolchains" "dist" "generated.bzl"))
27-
28-;; The tools buck fetches for itself. buck2 is not among them: it is the thing
29-;; doing the fetching. jolt is not either it is fetched by DotSlash on the
30-;; machine that runs the boot image compile, which may not be this one.
31-(def tools
32- [;; DotSlash itself, so an action can fetch what it needs where it runs
33- ;; rather than being handed it from here. See android/BUCK.
34- "dotslash"
35- ;; jolt-native's release, so the APK's UI half and the Jolt side of the
36- ;; tree ABI are fetched rather than built out of a second checkout.
37- "libvidya-android"
38- ;; The media plane, out of the same tarball as libvidya see its manifest
39- ;; for why the two are pinned together rather than independently.
40- "libjoltmoq-android"
41- "glimmer-vidya"
42- "android-glue"])
43-
44-(defn load-manifest [stem]
45- (let [candidate (->> [(fs/path here (str stem ".dotslash")) (fs/path here stem)]
46- (filter fs/exists?)
47- first)]
48- (when-not candidate
49- (binding [*out* *err*] (println (str "no DotSlash manifest for " stem)))
50- (System/exit 1))
51- (let [text (slurp (str candidate))]
52- (json/parse-string (subs text (str/index-of text "{"))))))
53-
54-(defn platform-entry [entry]
55- (let [;; The path of the binary inside the archive starts with the directory
56- ;; the tarball unpacks into, which is what to strip. A flat archive
57- ;; one binary, no directory around it has nothing to strip, and
58- ;; naming the binary would strip the whole payload.
59- [head rest] (str/split (get entry "path") #"/" 2)]
60- (array-map "url" (get-in entry ["providers" 0 "url"])
61- "sha256" (get entry "digest")
62- "strip_prefix" (if rest head "")
63- "type" (get entry "format"))))
64-
65-(def dist
66- (into (array-map)
67- (for [stem (sort tools)]
68- [stem (into (array-map)
69- (for [[platform entry] (sort-by key (get (load-manifest stem) "platforms"))
70- ;; http_archive takes sha256 and nothing else.
71- :when (= "sha256" (get entry "hash"))]
72- [platform (platform-entry entry)]))])))
73-
74-;; Four-space indentation, like the Starlark around it: this file is read by
75-;; people as often as by buck.
76-(def pretty
77- (json/create-pretty-printer
78- (assoc json/default-pretty-print-options
79- :indentation " "
80- :object-field-value-separator ": ")))
81-
82-(fs/create-dirs (fs/parent out-file))
83-(spit (str out-file)
84- (str/join "\n"
85- ["# @generated by scripts/dotslash-to-buck — do not edit."
86- "#"
87- "# The same archives scripts/*.dotslash pins, as facts buck can act on."
88- "# Bump the DotSlash file and run `just sync-dist`."
89- ""
90- (str "DIST = " (json/generate-string dist {:pretty pretty}))
91- ""]))
92-(println (str "wrote " (fs/relativize (fs/parent here) out-file)))
deleted file mode 100755
@@ -1,92 +0,0 @@
1-#!/bin/sh
2-#_(
3-exec "$(dirname "$0")/bb" "$0" "$@"
4-)
5-
6-;; Generate buck2 http_archive data from the DotSlash files beside this script.
7-;;
8-;; DotSlash is where a tool's version, URL and digest are written down. buck
9-;; needs the same three facts to fetch that tool itself it cannot use the
10-;; shim, which resolves on the machine at run time and so is neither an action
11-;; input nor anything a remote worker could be given. Rather than write them
12-;; twice and let them drift, this reads the manifests and emits the table buck
13-;; reads.
14-;;
15-;; just sync-dist # after editing any scripts/*.dotslash
16-;;
17-;; The DotSlash format is JSON with a `//` shebang line on top: one entry per
18-;; platform, each with a url, a size, a digest and the path of the binary
19-;; inside the archive. Only the archive itself is wanted here; the path inside
20-;; it is the shim's business, and the toolchain rules name what they need.
21-(require '[babashka.fs :as fs]
22- '[cheshire.core :as json]
23- '[clojure.string :as str])
24-
25-(def here (fs/parent (fs/canonicalize *file*)))
26-(def out-file (fs/path (fs/parent here) "toolchains" "dist" "generated.bzl"))
27-
28-;; The tools buck fetches for itself. buck2 is not among them: it is the thing
29-;; doing the fetching. jolt is not either it is fetched by DotSlash on the
30-;; machine that runs the boot image compile, which may not be this one.
31-(def tools
32- [;; DotSlash itself, so an action can fetch what it needs where it runs
33- ;; rather than being handed it from here. See android/BUCK.
34- "dotslash"
35- ;; jolt-native's release, so the APK's UI half and the Jolt side of the
36- ;; tree ABI are fetched rather than built out of a second checkout.
37- "libvidya-android"
38- ;; The media plane, out of the same tarball as libvidya see its manifest
39- ;; for why the two are pinned together rather than independently.
40- "libjoltmoq-android"
41- "glimmer-vidya"
42- "android-glue"])
43-
44-(defn load-manifest [stem]
45- (let [candidate (->> [(fs/path here (str stem ".dotslash")) (fs/path here stem)]
46- (filter fs/exists?)
47- first)]
48- (when-not candidate
49- (binding [*out* *err*] (println (str "no DotSlash manifest for " stem)))
50- (System/exit 1))
51- (let [text (slurp (str candidate))]
52- (json/parse-string (subs text (str/index-of text "{"))))))
53-
54-(defn platform-entry [entry]
55- (let [;; The path of the binary inside the archive starts with the directory
56- ;; the tarball unpacks into, which is what to strip. A flat archive
57- ;; one binary, no directory around it has nothing to strip, and
58- ;; naming the binary would strip the whole payload.
59- [head rest] (str/split (get entry "path") #"/" 2)]
60- (array-map "url" (get-in entry ["providers" 0 "url"])
61- "sha256" (get entry "digest")
62- "strip_prefix" (if rest head "")
63- "type" (get entry "format"))))
64-
65-(def dist
66- (into (array-map)
67- (for [stem (sort tools)]
68- [stem (into (array-map)
69- (for [[platform entry] (sort-by key (get (load-manifest stem) "platforms"))
70- ;; http_archive takes sha256 and nothing else.
71- :when (= "sha256" (get entry "hash"))]
72- [platform (platform-entry entry)]))])))
73-
74-;; Four-space indentation, like the Starlark around it: this file is read by
75-;; people as often as by buck.
76-(def pretty
77- (json/create-pretty-printer
78- (assoc json/default-pretty-print-options
79- :indentation " "
80- :object-field-value-separator ": ")))
81-
82-(fs/create-dirs (fs/parent out-file))
83-(spit (str out-file)
84- (str/join "\n"
85- ["# @generated by scripts/dotslash-to-buck — do not edit."
86- "#"
87- "# The same archives scripts/*.dotslash pins, as facts buck can act on."
88- "# Bump the DotSlash file and run `just sync-dist`."
89- ""
90- (str "DIST = " (json/generate-string dist {:pretty pretty}))
91- ""]))
92-(println (str "wrote " (fs/relativize (fs/parent here) out-file)))
deleted scripts/dotslash.dotslash +0 -66
deleted file mode 100644
@@ -1,66 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// DotSlash itself, so that a remote worker can fetch a toolchain the way this
4-// machine does.
5-//
6-// The other manifests here are pins buck reads and then fetches for itself.
7-// This one is different: it is fetched so that it can do the fetching. An NDK
8-// is three gigabytes unpacked, and shipping that to a worker as an action
9-// input means uploading it to the CAS first; a worker that runs this instead
10-// downloads the same pinned archive, by the same digest, from Google.
11-//
12-// Not runnable as a shim, and nothing tries: a DotSlash file cannot bootstrap
13-// the program that reads it.
14-{
15- "name": "dotslash",
16- "platforms": {
17- "linux-x86_64": {
18- "size": 842816,
19- "hash": "sha256",
20- "digest": "4c75c6eb7890ae35993b962073f6d9bbe78b42b81a5691303ad70f63bfbf7196",
21- "format": "tar.gz",
22- "path": "dotslash",
23- "providers": [
24- {
25- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.v0.5.9.tar.gz"
26- }
27- ]
28- },
29- "linux-aarch64": {
30- "size": 754251,
31- "hash": "sha256",
32- "digest": "e58374446dacd4a228388cd275d974bbd8f946916b513cf0eb86bdff5d9d675e",
33- "format": "tar.gz",
34- "path": "dotslash",
35- "providers": [
36- {
37- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.arm64.v0.5.9.tar.gz"
38- }
39- ]
40- },
41- "macos-x86_64": {
42- "size": 716580,
43- "hash": "sha256",
44- "digest": "51446593596ffe4cd22bc43a0fe6d82dd367758eb53cb4ade36d6a684ed08469",
45- "format": "tar.gz",
46- "path": "dotslash",
47- "providers": [
48- {
49- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-amd64.v0.5.9.tar.gz"
50- }
51- ]
52- },
53- "macos-aarch64": {
54- "size": 600404,
55- "hash": "sha256",
56- "digest": "eef15be1b554de7b1409cb0c69c24f2cd04f19c0f101ad69fcdf9d66d4d51639",
57- "format": "tar.gz",
58- "path": "dotslash",
59- "providers": [
60- {
61- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-arm64.v0.5.9.tar.gz"
62- }
63- ]
64- }
65- }
66-}
deleted file mode 100644
@@ -1,66 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// DotSlash itself, so that a remote worker can fetch a toolchain the way this
4-// machine does.
5-//
6-// The other manifests here are pins buck reads and then fetches for itself.
7-// This one is different: it is fetched so that it can do the fetching. An NDK
8-// is three gigabytes unpacked, and shipping that to a worker as an action
9-// input means uploading it to the CAS first; a worker that runs this instead
10-// downloads the same pinned archive, by the same digest, from Google.
11-//
12-// Not runnable as a shim, and nothing tries: a DotSlash file cannot bootstrap
13-// the program that reads it.
14-{
15- "name": "dotslash",
16- "platforms": {
17- "linux-x86_64": {
18- "size": 842816,
19- "hash": "sha256",
20- "digest": "4c75c6eb7890ae35993b962073f6d9bbe78b42b81a5691303ad70f63bfbf7196",
21- "format": "tar.gz",
22- "path": "dotslash",
23- "providers": [
24- {
25- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.v0.5.9.tar.gz"
26- }
27- ]
28- },
29- "linux-aarch64": {
30- "size": 754251,
31- "hash": "sha256",
32- "digest": "e58374446dacd4a228388cd275d974bbd8f946916b513cf0eb86bdff5d9d675e",
33- "format": "tar.gz",
34- "path": "dotslash",
35- "providers": [
36- {
37- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.arm64.v0.5.9.tar.gz"
38- }
39- ]
40- },
41- "macos-x86_64": {
42- "size": 716580,
43- "hash": "sha256",
44- "digest": "51446593596ffe4cd22bc43a0fe6d82dd367758eb53cb4ade36d6a684ed08469",
45- "format": "tar.gz",
46- "path": "dotslash",
47- "providers": [
48- {
49- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-amd64.v0.5.9.tar.gz"
50- }
51- ]
52- },
53- "macos-aarch64": {
54- "size": 600404,
55- "hash": "sha256",
56- "digest": "eef15be1b554de7b1409cb0c69c24f2cd04f19c0f101ad69fcdf9d66d4d51639",
57- "format": "tar.gz",
58- "path": "dotslash",
59- "providers": [
60- {
61- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-arm64.v0.5.9.tar.gz"
62- }
63- ]
64- }
65- }
66-}
modified scripts/frq/paths.clj +21 -4
@@ -1,9 +1,7 @@
11 ;; Where the other halves of this build are, and how to ask a program a
22 ;; question without writing the same three lines of shell each time.
33 ;;
4-;; Every script here loads this; nothing else does. The answers match the
5-;; justfile's, deliberately — a person who runs `just apk` and a person who
6-;; runs android/build-apk.bb should be building the same thing.
4+;; Every script here loads this; nothing else does.
75 (ns frq.paths
86 (:require [babashka.fs :as fs]
97 [babashka.process :as p]
@@ -26,8 +24,12 @@
2624 ;; every script here asks the same question of the same pin and a second
2725 ;; jolt-native checkout is never part of the answer.
2826 ;;
27+;; Only the desktop libraries are pinned this way now — `just lib`, and the
28+;; release half of a run. The Android side is nix/android.nix, which fetches
29+;; the same archives by the same digests as `fetchurl`.
30+;;
2931 ;; DOTSLASH names the fetcher for a caller that has one but has not got it on
30-;; PATH — buck sets it, because the fetcher is an input to those actions.
32+;; PATH.
3133 (defn dist [root name]
3234 (let [manifest (fs/path root "scripts" (str name ".dotslash"))]
3335 (when-not (fs/exists? manifest)
@@ -47,3 +49,18 @@
4749 (doseq [p paths]
4850 (when-not (fs/exists? (str p))
4951 (apply die (str "missing " label ": " p) hint))))
52+
53+;; A nix command, as an argv to run where nix is.
54+;;
55+;; nix is not on every host this runs on: on the machine these scripts were
56+;; written for it lives in an Arch distrobox, at the same path — which is why
57+;; the container is entered rather than the tree copied into it. See CLAUDE.md.
58+;; Trailing arguments are passed through `"$@"` rather than pasted into the
59+;; command line, so a value with a space in it survives the shell in between.
60+(defn nix [root args & [trailing]]
61+ (if (fs/which "nix")
62+ (concat args trailing)
63+ (concat ["distrobox" "enter" "arch" "--" "bash" "-lc"
64+ (str "cd " root " && exec " (str/join " " args) " \"$@\"")
65+ "--"]
66+ trailing)))
@@ -1,9 +1,7 @@
1 ;; Where the other halves of this build are, and how to ask a program a1 ;; Where the other halves of this build are, and how to ask a program a
2 ;; question without writing the same three lines of shell each time.2 ;; question without writing the same three lines of shell each time.
3 ;;3 ;;
4-;; Every script here loads this; nothing else does. The answers match the4+;; Every script here loads this; nothing else does.
5-;; justfile's, deliberately — a person who runs `just apk` and a person who
6-;; runs android/build-apk.bb should be building the same thing.
7 (ns frq.paths5 (ns frq.paths
8 (:require [babashka.fs :as fs]6 (:require [babashka.fs :as fs]
9 [babashka.process :as p]7 [babashka.process :as p]
@@ -26,8 +24,12 @@
26 ;; every script here asks the same question of the same pin and a second24 ;; every script here asks the same question of the same pin and a second
27 ;; jolt-native checkout is never part of the answer.25 ;; jolt-native checkout is never part of the answer.
28 ;;26 ;;
27+;; Only the desktop libraries are pinned this way now — `just lib`, and the
28+;; release half of a run. The Android side is nix/android.nix, which fetches
29+;; the same archives by the same digests as `fetchurl`.
30+;;
29 ;; DOTSLASH names the fetcher for a caller that has one but has not got it on31 ;; DOTSLASH names the fetcher for a caller that has one but has not got it on
30-;; PATH — buck sets it, because the fetcher is an input to those actions.32+;; PATH.
31 (defn dist [root name]33 (defn dist [root name]
32 (let [manifest (fs/path root "scripts" (str name ".dotslash"))]34 (let [manifest (fs/path root "scripts" (str name ".dotslash"))]
33 (when-not (fs/exists? manifest)35 (when-not (fs/exists? manifest)
@@ -47,3 +49,18 @@
47 (doseq [p paths]49 (doseq [p paths]
48 (when-not (fs/exists? (str p))50 (when-not (fs/exists? (str p))
49 (apply die (str "missing " label ": " p) hint))))51 (apply die (str "missing " label ": " p) hint))))
52+
53+;; A nix command, as an argv to run where nix is.
54+;;
55+;; nix is not on every host this runs on: on the machine these scripts were
56+;; written for it lives in an Arch distrobox, at the same path — which is why
57+;; the container is entered rather than the tree copied into it. See CLAUDE.md.
58+;; Trailing arguments are passed through `"$@"` rather than pasted into the
59+;; command line, so a value with a space in it survives the shell in between.
60+(defn nix [root args & [trailing]]
61+ (if (fs/which "nix")
62+ (concat args trailing)
63+ (concat ["distrobox" "enter" "arch" "--" "bash" "-lc"
64+ (str "cd " root " && exec " (str/join " " args) " \"$@\"")
65+ "--"]
66+ trailing)))
deleted scripts/glimmer-vidya.dotslash +0 -62
deleted file mode 100755
@@ -1,62 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The Jolt side that binds the tree ABI, from jolt-native's v0.1.3 release.
4-//
5-// deps.edn takes this as a git dependency, and jolt resolves it into its own
6-// cache. The boot image cannot: a cross compile has no dependency resolution,
7-// so every source root has to be named, and a path into somebody's ~/.jolt is
8-// not a thing a build can be handed. This is the same tree at the same commit,
9-// as an archive an action can depend on.
10-{
11- "name": "glimmer-vidya",
12- "platforms": {
13- "linux-x86_64": {
14- "size": 17988,
15- "hash": "sha256",
16- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
17- "format": "tar.gz",
18- "path": "glimmer-vidya/deps.edn",
19- "providers": [
20- {
21- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
22- }
23- ]
24- },
25- "linux-aarch64": {
26- "size": 17988,
27- "hash": "sha256",
28- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
29- "format": "tar.gz",
30- "path": "glimmer-vidya/deps.edn",
31- "providers": [
32- {
33- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
34- }
35- ]
36- },
37- "macos-x86_64": {
38- "size": 17988,
39- "hash": "sha256",
40- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
41- "format": "tar.gz",
42- "path": "glimmer-vidya/deps.edn",
43- "providers": [
44- {
45- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
46- }
47- ]
48- },
49- "macos-aarch64": {
50- "size": 17988,
51- "hash": "sha256",
52- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
53- "format": "tar.gz",
54- "path": "glimmer-vidya/deps.edn",
55- "providers": [
56- {
57- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
58- }
59- ]
60- }
61- }
62-}
deleted file mode 100755
@@ -1,62 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The Jolt side that binds the tree ABI, from jolt-native's v0.1.3 release.
4-//
5-// deps.edn takes this as a git dependency, and jolt resolves it into its own
6-// cache. The boot image cannot: a cross compile has no dependency resolution,
7-// so every source root has to be named, and a path into somebody's ~/.jolt is
8-// not a thing a build can be handed. This is the same tree at the same commit,
9-// as an archive an action can depend on.
10-{
11- "name": "glimmer-vidya",
12- "platforms": {
13- "linux-x86_64": {
14- "size": 17988,
15- "hash": "sha256",
16- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
17- "format": "tar.gz",
18- "path": "glimmer-vidya/deps.edn",
19- "providers": [
20- {
21- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
22- }
23- ]
24- },
25- "linux-aarch64": {
26- "size": 17988,
27- "hash": "sha256",
28- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
29- "format": "tar.gz",
30- "path": "glimmer-vidya/deps.edn",
31- "providers": [
32- {
33- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
34- }
35- ]
36- },
37- "macos-x86_64": {
38- "size": 17988,
39- "hash": "sha256",
40- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
41- "format": "tar.gz",
42- "path": "glimmer-vidya/deps.edn",
43- "providers": [
44- {
45- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
46- }
47- ]
48- },
49- "macos-aarch64": {
50- "size": 17988,
51- "hash": "sha256",
52- "digest": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
53- "format": "tar.gz",
54- "path": "glimmer-vidya/deps.edn",
55- "providers": [
56- {
57- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz"
58- }
59- ]
60- }
61- }
62-}
deleted scripts/jolt +0 -28
deleted file mode 100755
@@ -1,28 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// jolt with the Bionic `struct addrinfo` fix, from the fork at
4-// gitlab.com/nandithebull/jolt (commit 2b80d68d). Upstream's own release reads
5-// `ai_addr` at glibc's offset, which on Android is `ai_canonname` a null
6-// pointer so every TLS connect fails there and reports a refusal the network
7-// never made. Nothing else differs from v0.7.28.
8-//
9-// Linux x86_64 only: it is what the APK is built on. Other platforms fall back
10-// to whatever `jolt` is on PATH, which is upstream's, which is fine for
11-// everything but an Android build.
12-{
13- "name": "jolt",
14- "platforms": {
15- "linux-x86_64": {
16- "size": 15782379,
17- "hash": "sha256",
18- "digest": "aabb71f809aebd9d607b7a5036229f933c733ae90785cb29df899f116be9589f",
19- "format": "tar.gz",
20- "path": "jolt-v0.7.28-1-g2b80d68d-x86_64-linux/jolt",
21- "providers": [
22- {
23- "url": "https://gitlab.com/nandithebull/jolt/-/releases/v0.7.28-android/downloads/jolt-v0.7.28-1-g2b80d68d-x86_64-linux.tar.gz"
24- }
25- ]
26- }
27- }
28-}
deleted file mode 100755
@@ -1,28 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// jolt with the Bionic `struct addrinfo` fix, from the fork at
4-// gitlab.com/nandithebull/jolt (commit 2b80d68d). Upstream's own release reads
5-// `ai_addr` at glibc's offset, which on Android is `ai_canonname` a null
6-// pointer so every TLS connect fails there and reports a refusal the network
7-// never made. Nothing else differs from v0.7.28.
8-//
9-// Linux x86_64 only: it is what the APK is built on. Other platforms fall back
10-// to whatever `jolt` is on PATH, which is upstream's, which is fine for
11-// everything but an Android build.
12-{
13- "name": "jolt",
14- "platforms": {
15- "linux-x86_64": {
16- "size": 15782379,
17- "hash": "sha256",
18- "digest": "aabb71f809aebd9d607b7a5036229f933c733ae90785cb29df899f116be9589f",
19- "format": "tar.gz",
20- "path": "jolt-v0.7.28-1-g2b80d68d-x86_64-linux/jolt",
21- "providers": [
22- {
23- "url": "https://gitlab.com/nandithebull/jolt/-/releases/v0.7.28-android/downloads/jolt-v0.7.28-1-g2b80d68d-x86_64-linux.tar.gz"
24- }
25- ]
26- }
27- }
28-}
modified scripts/lib.bb +5 -2
@@ -7,8 +7,11 @@ exec "$(dirname "$0")/bb" "$0" "$@"
77 ;;
88 ;; libvidya is the tree ABI glimmer-vidya binds; libjoltmoq is the AV media
99 ;; plane. They come out of one archive because they are built together, and
10-;; they land in build/lib because a loader wants one directory, which is where
11-;; run.bb points LD_LIBRARY_PATH.
10+;; they land in build/lib because a loader wants one directory. `just run` does
11+;; not come through here — running a change to jolt-native means building it,
12+;; which is what the dev shell is for — so this is the released half: the same
13+;; bytes the APK takes through nix/android.nix, and what a run of the last
14+;; release takes.
1215 ;;
1316 ;; Nothing is compiled here. The pinned bytes are the bytes: this repo used to
1417 ;; clone jolt-native and cargo-build it, which meant a Rust toolchain, a build
@@ -7,8 +7,11 @@ exec "$(dirname "$0")/bb" "$0" "$@"
7 ;;7 ;;
8 ;; libvidya is the tree ABI glimmer-vidya binds; libjoltmoq is the AV media8 ;; libvidya is the tree ABI glimmer-vidya binds; libjoltmoq is the AV media
9 ;; plane. They come out of one archive because they are built together, and9 ;; plane. They come out of one archive because they are built together, and
10-;; they land in build/lib because a loader wants one directory, which is where10+;; they land in build/lib because a loader wants one directory. `just run` does
11-;; run.bb points LD_LIBRARY_PATH.11+;; not come through here — running a change to jolt-native means building it,
12+;; which is what the dev shell is for — so this is the released half: the same
13+;; bytes the APK takes through nix/android.nix, and what a run of the last
14+;; release takes.
12 ;;15 ;;
13 ;; Nothing is compiled here. The pinned bytes are the bytes: this repo used to16 ;; Nothing is compiled here. The pinned bytes are the bytes: this repo used to
14 ;; clone jolt-native and cargo-build it, which meant a Rust toolchain, a build17 ;; clone jolt-native and cargo-build it, which meant a Rust toolchain, a build
deleted scripts/libjoltmoq-android.dotslash +0 -67
deleted file mode 100755
@@ -1,67 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The AV media plane for the phone, from jolt-native's v0.1.3 release.
4-//
5-// The same tarball libvidya-android names, and deliberately so: the two objects
6-// are built together and only make sense together libjoltapp links both, and
7-// a libjoltmoq from one release beside a libvidya from another is a pairing
8-// nothing has tested. Same digest, different file out of it.
9-//
10-// Before v0.1.3 there was no such object at all: the media plane was V4L2 and
11-// PipeWire, which a phone has neither of. The camera is Camera2 over JNI now
12-// and the microphone is cpal's AAudio host.
13-//
14-// The only answer for it, the same as libvidya.
15-{
16- "name": "libjoltmoq-android",
17- "platforms": {
18- "linux-x86_64": {
19- "size": 14150473,
20- "hash": "sha256",
21- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
22- "format": "tar.gz",
23- "path": "libjoltmoq.so",
24- "providers": [
25- {
26- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
27- }
28- ]
29- },
30- "linux-aarch64": {
31- "size": 14150473,
32- "hash": "sha256",
33- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
34- "format": "tar.gz",
35- "path": "libjoltmoq.so",
36- "providers": [
37- {
38- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
39- }
40- ]
41- },
42- "macos-x86_64": {
43- "size": 14150473,
44- "hash": "sha256",
45- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
46- "format": "tar.gz",
47- "path": "libjoltmoq.so",
48- "providers": [
49- {
50- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
51- }
52- ]
53- },
54- "macos-aarch64": {
55- "size": 14150473,
56- "hash": "sha256",
57- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
58- "format": "tar.gz",
59- "path": "libjoltmoq.so",
60- "providers": [
61- {
62- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
63- }
64- ]
65- }
66- }
67-}
deleted file mode 100755
@@ -1,67 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// The AV media plane for the phone, from jolt-native's v0.1.3 release.
4-//
5-// The same tarball libvidya-android names, and deliberately so: the two objects
6-// are built together and only make sense together libjoltapp links both, and
7-// a libjoltmoq from one release beside a libvidya from another is a pairing
8-// nothing has tested. Same digest, different file out of it.
9-//
10-// Before v0.1.3 there was no such object at all: the media plane was V4L2 and
11-// PipeWire, which a phone has neither of. The camera is Camera2 over JNI now
12-// and the microphone is cpal's AAudio host.
13-//
14-// The only answer for it, the same as libvidya.
15-{
16- "name": "libjoltmoq-android",
17- "platforms": {
18- "linux-x86_64": {
19- "size": 14150473,
20- "hash": "sha256",
21- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
22- "format": "tar.gz",
23- "path": "libjoltmoq.so",
24- "providers": [
25- {
26- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
27- }
28- ]
29- },
30- "linux-aarch64": {
31- "size": 14150473,
32- "hash": "sha256",
33- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
34- "format": "tar.gz",
35- "path": "libjoltmoq.so",
36- "providers": [
37- {
38- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
39- }
40- ]
41- },
42- "macos-x86_64": {
43- "size": 14150473,
44- "hash": "sha256",
45- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
46- "format": "tar.gz",
47- "path": "libjoltmoq.so",
48- "providers": [
49- {
50- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
51- }
52- ]
53- },
54- "macos-aarch64": {
55- "size": 14150473,
56- "hash": "sha256",
57- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
58- "format": "tar.gz",
59- "path": "libjoltmoq.so",
60- "providers": [
61- {
62- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
63- }
64- ]
65- }
66- }
67-}
deleted scripts/libvidya-android.dotslash +0 -65
deleted file mode 100755
@@ -1,65 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// libvidya for the phone, from jolt-native's v0.1.3 release.
4-//
5-// arm64, API 28, built by NDK r29 through jolt-native's buck2 toolchain. The
6-// same object `just ffi-android` produces there, pinned so that building the
7-// APK needs neither that checkout nor an NDK.
8-//
9-// This is the only answer, and deliberately: a checkout used to win over it,
10-// which meant the APK on a phone depended on which directories happened to sit
11-// beside this one. To build against a jolt-native you are editing, cut a
12-// release of it and point these manifests at it `just bump <tag>`.
13-{
14- "name": "libvidya-android",
15- "platforms": {
16- "linux-x86_64": {
17- "size": 14150473,
18- "hash": "sha256",
19- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
20- "format": "tar.gz",
21- "path": "libvidya.so",
22- "providers": [
23- {
24- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
25- }
26- ]
27- },
28- "linux-aarch64": {
29- "size": 14150473,
30- "hash": "sha256",
31- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
32- "format": "tar.gz",
33- "path": "libvidya.so",
34- "providers": [
35- {
36- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
37- }
38- ]
39- },
40- "macos-x86_64": {
41- "size": 14150473,
42- "hash": "sha256",
43- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
44- "format": "tar.gz",
45- "path": "libvidya.so",
46- "providers": [
47- {
48- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
49- }
50- ]
51- },
52- "macos-aarch64": {
53- "size": 14150473,
54- "hash": "sha256",
55- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
56- "format": "tar.gz",
57- "path": "libvidya.so",
58- "providers": [
59- {
60- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
61- }
62- ]
63- }
64- }
65-}
deleted file mode 100755
@@ -1,65 +0,0 @@
1-#!/usr/bin/env dotslash
2-
3-// libvidya for the phone, from jolt-native's v0.1.3 release.
4-//
5-// arm64, API 28, built by NDK r29 through jolt-native's buck2 toolchain. The
6-// same object `just ffi-android` produces there, pinned so that building the
7-// APK needs neither that checkout nor an NDK.
8-//
9-// This is the only answer, and deliberately: a checkout used to win over it,
10-// which meant the APK on a phone depended on which directories happened to sit
11-// beside this one. To build against a jolt-native you are editing, cut a
12-// release of it and point these manifests at it `just bump <tag>`.
13-{
14- "name": "libvidya-android",
15- "platforms": {
16- "linux-x86_64": {
17- "size": 14150473,
18- "hash": "sha256",
19- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
20- "format": "tar.gz",
21- "path": "libvidya.so",
22- "providers": [
23- {
24- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
25- }
26- ]
27- },
28- "linux-aarch64": {
29- "size": 14150473,
30- "hash": "sha256",
31- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
32- "format": "tar.gz",
33- "path": "libvidya.so",
34- "providers": [
35- {
36- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
37- }
38- ]
39- },
40- "macos-x86_64": {
41- "size": 14150473,
42- "hash": "sha256",
43- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
44- "format": "tar.gz",
45- "path": "libvidya.so",
46- "providers": [
47- {
48- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
49- }
50- ]
51- },
52- "macos-aarch64": {
53- "size": 14150473,
54- "hash": "sha256",
55- "digest": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
56- "format": "tar.gz",
57- "path": "libvidya.so",
58- "providers": [
59- {
60- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz"
61- }
62- ]
63- }
64- }
65-}
modified scripts/run.bb +58 -18
@@ -7,37 +7,77 @@ exec "$(dirname "$0")/bb" "$0" "$@"
77 ;;
88 ;; run.bb [args...]
99 ;;
10-;; Everything but the source is pinned: jolt comes from scripts/jolt.dotslash
11-;; and the two native libraries from scripts/lib*.dotslash, fetched by digest
12-;; and linked into build/lib, which is the one directory the loader is pointed
13-;; at. `just lib` is done here rather than asked for — the pins say what those
14-;; bytes are, so there is nothing for a person to decide before running.
10+;; Two halves, and the split is the point. The frq source is the files on disk,
11+;; uncommitted edits and all. Everything under it — jolt, glimmer,
12+;; glimmer-vidya, both native objects — is the flake's, built rather than
13+;; fetched: this re-execs itself inside `nix develop`, and that shell is the
14+;; jolt-native input compiled and the Jolt halves that bind it, at the revs
15+;; flake.lock names.
1516 ;;
1617 ;; Deliberately not `nix run .#frq`. That builds the flake's own copy of the
1718 ;; source, which is the tree as git has it — so an edit that has not been
1819 ;; committed, or has been committed on a branch the command was not pointed at,
1920 ;; runs as whatever was there before, silently. A run that is meant to answer
2021 ;; "does my change work" has to be the files on disk.
21-(require '[babashka.fs :as fs]
22- '[babashka.process :as p])
22+;;
23+;; And deliberately not the scripts/*.dotslash pins either, which is what this
24+;; used to do. Those name a release; a change to jolt-native is by definition
25+;; not in one yet. `just lib` still fetches them, and the APK takes the same
26+;; released bytes through nix/android.nix — but a run does not.
27+(require '[babashka.classpath :as cp])
28+(cp/add-classpath (str (babashka.fs/parent *file*)))
29+(require '[frq.paths :as paths]
30+ '[babashka.fs :as fs]
31+ '[babashka.process :as p]
32+ '[clojure.string :as str])
2333
2434 (def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
25-(def lib (str (fs/path root "build" "lib")))
35+(def self (str (fs/path root "scripts" "run.bb")))
36+
37+;; Outside the shell, get inside it and come back to this same script. The
38+;; shell is what sets JOLT_NATIVE_LIB, so its absence is the test — no flag to
39+;; forget, and `nix develop --command scripts/run.bb` by hand is not a second
40+;; code path.
41+;;
42+;; --max-jobs 0 is what sends the work to the `builders` entry rather than
43+;; compiling it here. Left to the default, nix prefers the local machine, and a
44+;; cold jolt-native is egui, openh264 and quinn on a laptop — for a derivation
45+;; a remote builder has likely built already. FRQ_MAX_JOBS is the way out on a
46+;; machine with no builder configured: FRQ_MAX_JOBS=auto.
47+(when-not (System/getenv "JOLT_NATIVE_LIB")
48+ ;; Getting to a nix on a host that may not have one is paths/nix's problem,
49+ ;; and scripts/apk.bb has the same one.
50+ (let [cmd (paths/nix root
51+ ["nix" "develop" root
52+ "--max-jobs" (paths/env "FRQ_MAX_JOBS" "0")
53+ "--command" self]
54+ *command-line-args*)]
55+ (System/exit (:exit @(apply p/process {:inherit true :dir root} cmd)))))
2656
27-;; The pinned jolt — scripts/jolt is a DotSlash script, so running it is
28-;; fetching it. Off linux-x86_64 the pin has no asset and the fallback is
29-;; whatever `jolt` is on PATH, which is what that manifest says to do.
30-(def jolt
31- (let [pin (fs/path root "scripts" "jolt")]
32- (if (and (fs/exists? pin) (fs/which "dotslash")) (str pin) "jolt")))
57+;; The Jolt halves that have to match those objects. glimmer-vidya lives inside
58+;; jolt-native and binds libvidya's ABI, so it comes out of the same input that
59+;; was built rather than deps.edn's git sha — the pin drifting from the library
60+;; is exactly what the flake input's comment describes. glimmer is the flake's
61+;; for the same reason.
62+(def overrides
63+ (str "{:deps {jolt-lang/glimmer {:local/root \"" (System/getenv "GLIMMER_SRC") "\"}"
64+ " nandi/glimmer-vidya {:local/root \"" (System/getenv "GLIMMER_VIDYA_SRC") "\"}}}"))
3365
34-(p/shell (str (fs/path root "scripts" "lib.bb")))
66+;; On NixOS the store's Mesa is the system's and the window opens. Anywhere
67+;; else — a bare host, or the distrobox above — the real driver is the host's,
68+;; so defer to nixGL, which prepends it. Same rule the flake's launcher uses.
69+(def runner
70+ (when-not (fs/exists? "/run/current-system")
71+ (some-> (System/getenv "NIXGL") not-empty vector)))
3572
3673 (System/exit
3774 (:exit @(apply p/process
3875 {:inherit true
3976 :dir root
4077 :extra-env {"LD_LIBRARY_PATH"
41- (str lib (when-let [p (System/getenv "LD_LIBRARY_PATH")]
42- (str ":" p)))}}
43- jolt "-M:frq" *command-line-args*)))
78+ (->> [(System/getenv "JOLT_NATIVE_LIB")
79+ (System/getenv "FRQ_LIB_PATH")
80+ (System/getenv "LD_LIBRARY_PATH")]
81+ (remove str/blank?)
82+ (str/join ":"))}}
83+ (concat runner ["jolt" "-Sdeps" overrides "-M:frq"] *command-line-args*))))
@@ -7,37 +7,77 @@ exec "$(dirname "$0")/bb" "$0" "$@"
7 ;;7 ;;
8 ;; run.bb [args...]8 ;; run.bb [args...]
9 ;;9 ;;
10-;; Everything but the source is pinned: jolt comes from scripts/jolt.dotslash10+;; Two halves, and the split is the point. The frq source is the files on disk,
11-;; and the two native libraries from scripts/lib*.dotslash, fetched by digest11+;; uncommitted edits and all. Everything under it — jolt, glimmer,
12-;; and linked into build/lib, which is the one directory the loader is pointed12+;; glimmer-vidya, both native objects — is the flake's, built rather than
13-;; at. `just lib` is done here rather than asked for — the pins say what those13+;; fetched: this re-execs itself inside `nix develop`, and that shell is the
14-;; bytes are, so there is nothing for a person to decide before running.14+;; jolt-native input compiled and the Jolt halves that bind it, at the revs
15+;; flake.lock names.
15 ;;16 ;;
16 ;; Deliberately not `nix run .#frq`. That builds the flake's own copy of the17 ;; Deliberately not `nix run .#frq`. That builds the flake's own copy of the
17 ;; source, which is the tree as git has it — so an edit that has not been18 ;; source, which is the tree as git has it — so an edit that has not been
18 ;; committed, or has been committed on a branch the command was not pointed at,19 ;; committed, or has been committed on a branch the command was not pointed at,
19 ;; runs as whatever was there before, silently. A run that is meant to answer20 ;; runs as whatever was there before, silently. A run that is meant to answer
20 ;; "does my change work" has to be the files on disk.21 ;; "does my change work" has to be the files on disk.
21-(require '[babashka.fs :as fs]22+;;
22- '[babashka.process :as p])23+;; And deliberately not the scripts/*.dotslash pins either, which is what this
24+;; used to do. Those name a release; a change to jolt-native is by definition
25+;; not in one yet. `just lib` still fetches them, and the APK takes the same
26+;; released bytes through nix/android.nix — but a run does not.
27+(require '[babashka.classpath :as cp])
28+(cp/add-classpath (str (babashka.fs/parent *file*)))
29+(require '[frq.paths :as paths]
30+ '[babashka.fs :as fs]
31+ '[babashka.process :as p]
32+ '[clojure.string :as str])
23 33
24 (def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))34 (def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
25-(def lib (str (fs/path root "build" "lib")))35+(def self (str (fs/path root "scripts" "run.bb")))
36+
37+;; Outside the shell, get inside it and come back to this same script. The
38+;; shell is what sets JOLT_NATIVE_LIB, so its absence is the test — no flag to
39+;; forget, and `nix develop --command scripts/run.bb` by hand is not a second
40+;; code path.
41+;;
42+;; --max-jobs 0 is what sends the work to the `builders` entry rather than
43+;; compiling it here. Left to the default, nix prefers the local machine, and a
44+;; cold jolt-native is egui, openh264 and quinn on a laptop — for a derivation
45+;; a remote builder has likely built already. FRQ_MAX_JOBS is the way out on a
46+;; machine with no builder configured: FRQ_MAX_JOBS=auto.
47+(when-not (System/getenv "JOLT_NATIVE_LIB")
48+ ;; Getting to a nix on a host that may not have one is paths/nix's problem,
49+ ;; and scripts/apk.bb has the same one.
50+ (let [cmd (paths/nix root
51+ ["nix" "develop" root
52+ "--max-jobs" (paths/env "FRQ_MAX_JOBS" "0")
53+ "--command" self]
54+ *command-line-args*)]
55+ (System/exit (:exit @(apply p/process {:inherit true :dir root} cmd)))))
26 56
27-;; The pinned jolt — scripts/jolt is a DotSlash script, so running it is57+;; The Jolt halves that have to match those objects. glimmer-vidya lives inside
28-;; fetching it. Off linux-x86_64 the pin has no asset and the fallback is58+;; jolt-native and binds libvidya's ABI, so it comes out of the same input that
29-;; whatever `jolt` is on PATH, which is what that manifest says to do.59+;; was built rather than deps.edn's git sha — the pin drifting from the library
30-(def jolt60+;; is exactly what the flake input's comment describes. glimmer is the flake's
31- (let [pin (fs/path root "scripts" "jolt")]61+;; for the same reason.
32- (if (and (fs/exists? pin) (fs/which "dotslash")) (str pin) "jolt")))62+(def overrides
63+ (str "{:deps {jolt-lang/glimmer {:local/root \"" (System/getenv "GLIMMER_SRC") "\"}"
64+ " nandi/glimmer-vidya {:local/root \"" (System/getenv "GLIMMER_VIDYA_SRC") "\"}}}"))
33 65
34-(p/shell (str (fs/path root "scripts" "lib.bb")))66+;; On NixOS the store's Mesa is the system's and the window opens. Anywhere
67+;; else — a bare host, or the distrobox above — the real driver is the host's,
68+;; so defer to nixGL, which prepends it. Same rule the flake's launcher uses.
69+(def runner
70+ (when-not (fs/exists? "/run/current-system")
71+ (some-> (System/getenv "NIXGL") not-empty vector)))
35 72
36 (System/exit73 (System/exit
37 (:exit @(apply p/process74 (:exit @(apply p/process
38 {:inherit true75 {:inherit true
39 :dir root76 :dir root
40 :extra-env {"LD_LIBRARY_PATH"77 :extra-env {"LD_LIBRARY_PATH"
41- (str lib (when-let [p (System/getenv "LD_LIBRARY_PATH")]78+ (->> [(System/getenv "JOLT_NATIVE_LIB")
42- (str ":" p)))}}79+ (System/getenv "FRQ_LIB_PATH")
43- jolt "-M:frq" *command-line-args*)))80+ (System/getenv "LD_LIBRARY_PATH")]
81+ (remove str/blank?)
82+ (str/join ":"))}}
83+ (concat runner ["jolt" "-Sdeps" overrides "-M:frq"] *command-line-args*))))
modified scripts/tui.bb +40 -77
@@ -5,91 +5,54 @@ exec "$(dirname "$0")/bb" "$0" "$@"
55
66 ;; frq's screens in a terminal, from this working tree.
77 ;;
8-;; tui.bb [--headless] [--cols=N] [--rows=N]
8+;; tui.bb [--headless] [--demo] [--cols=N] [--rows=N] [--wait=MS] [--dump]
99 ;;
10-;; run.bb with the other backend under it. Two things differ, and both are
11-;; because the terminal backend is not in a jolt-native release yet:
10+;; run.bb with the other backend under it, and the same two halves: the frq
11+;; source is the files on disk, and everything below it is the flake's. The
12+;; dev shell builds jolt-native and names both Jolt sides of it — glimmer-vidya
13+;; for the window, glimmer-tui for the terminal — so this needs no checkout
14+;; beside the tree and no library fetched by digest.
1215 ;;
13-;; * `libjolttui.so` comes out of a jolt-native checkout's target directory
14-;; rather than out of a pinned archive, and is linked into build/lib beside
15-;; the two that are pinned. Point JOLT_NATIVE at that checkout, or leave it
16-;; beside this one.
17-;; * `glimmer-tui` — the jolt half of that backend, and the namespace
18-;; `frq.tui` requires — is resolved from the same checkout with -Sdeps,
19-;; which is what lets this work from a worktree, where the relative path in
20-;; deps.edn's `:tui` alias does not point where it does from a clone. The
21-;; alias is not used here for that reason: its coordinate for the same
22-;; library wins over the one -Sdeps merges in, so this passes `-m` itself
23-;; and leaves `jolt -M:tui` to the checkouts the alias is right for.
16+;; It still loads libvidya as well as libjolttui. `frq.app` requires
17+;; glimmer-vidya, and `frq.tui` requires glimmer-tui after it so the backend
18+;; installed last is the terminal; the window's library is resolved and then
19+;; asked for nothing.
2420 ;;
25-;; When the backend ships in a release, both of those become pins like every
26-;; other, and this script becomes run.bb with a different alias.
27-(require '[babashka.fs :as fs]
28- '[babashka.process :as p])
21+;; No nixGL here, unlike run.bb: a terminal wants nothing from the host's GL
22+;; driver, which is the reason this output exists on machines that have none.
23+(require '[babashka.classpath :as cp])
24+(cp/add-classpath (str (babashka.fs/parent *file*)))
25+(require '[frq.paths :as paths]
26+ '[babashka.fs :as fs]
27+ '[babashka.process :as p]
28+ '[clojure.string :as str])
2929
3030 (def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
31-(def lib (fs/path root "build" "lib"))
32-
33-(def jolt
34- (let [pin (fs/path root "scripts" "jolt")]
35- (if (and (fs/exists? pin) (fs/which "dotslash")) (str pin) "jolt")))
36-
37-(defn die [& msg]
38- (binding [*out* *err*] (println (apply str msg)))
39- (System/exit 1))
40-
41-;; The checkout the terminal backend lives in. A worktree of it counts — what
42-;; is wanted is a directory holding `jolt/glimmer-tui` and a built libjolttui.
43-(def jolt-native
44- (let [given (System/getenv "JOLT_NATIVE")
45- guess (fs/path root ".." "jolt-native")
46- dir (cond
47- given (fs/path given)
48- (fs/exists? guess) guess
49- :else nil)]
50- (when-not dir
51- (die "no jolt-native checkout: set JOLT_NATIVE, or put one beside this tree"))
52- (str (fs/canonicalize dir))))
53-
54-(def glimmer-tui (fs/path jolt-native "jolt" "glimmer-tui"))
55-
56-(when-not (fs/exists? glimmer-tui)
57- (die glimmer-tui " is not there — this wants the branch that carries the "
58- "terminal backend (crates/jolt-tui and jolt/glimmer-tui)"))
59-
60-;; cargo's release build first, then its debug one, then what buck2 left: any
61-;; of the three is the library, and which one a person has is their business.
62-(def jolttui
63- (or (first (for [c ["target/release/libjolttui.so"
64- "target/debug/libjolttui.so"]
65- :let [p (fs/path jolt-native c)]
66- :when (fs/exists? p)]
67- p))
68- (first (sort-by (comp - fs/file-time->millis fs/last-modified-time)
69- (fs/glob (fs/path jolt-native "buck-out")
70- "**/libjolttui.so")))
71- (die "no libjolttui.so under " jolt-native
72- " — build it: cargo build --release -p jolt-tui")))
73-
74-;; The two pinned libraries, into build/lib.
75-(p/shell (str (fs/path root "scripts" "lib.bb")))
76-
77-;; And the unpinned third, linked rather than copied for the same reason the
78-;; others are: a rebuild reaches a running tree without anything here going
79-;; stale.
80-(let [dest (fs/path lib "libjolttui.so")]
81- (fs/create-dirs lib)
82- (fs/delete-if-exists dest)
83- (fs/create-sym-link dest (str (fs/canonicalize jolttui))))
31+(def self (str (fs/path root "scripts" "tui.bb")))
32+
33+;; Outside the shell, get inside it and come back to this same script — the
34+;; test, the flag and the reasoning are run.bb's.
35+(when-not (System/getenv "JOLT_NATIVE_LIB")
36+ (let [cmd (paths/nix root
37+ ["nix" "develop" root
38+ "--max-jobs" (paths/env "FRQ_MAX_JOBS" "0")
39+ "--command" self]
40+ *command-line-args*)]
41+ (System/exit (:exit @(apply p/process {:inherit true :dir root} cmd)))))
42+
43+(def overrides
44+ (str "{:deps {jolt-lang/glimmer {:local/root \"" (System/getenv "GLIMMER_SRC") "\"}"
45+ " nandi/glimmer-vidya {:local/root \"" (System/getenv "GLIMMER_VIDYA_SRC") "\"}"
46+ " nandi/glimmer-tui {:local/root \"" (System/getenv "GLIMMER_TUI_SRC") "\"}}}"))
8447
8548 (System/exit
8649 (:exit @(apply p/process
8750 {:inherit true
8851 :dir root
8952 :extra-env {"LD_LIBRARY_PATH"
90- (str lib (when-let [p (System/getenv "LD_LIBRARY_PATH")]
91- (str ":" p)))}}
92- jolt
93- "-Sdeps" (str "{:deps {nandi/glimmer-tui {:local/root \""
94- glimmer-tui "\"}}}")
95- "-m" "frq.tui" *command-line-args*)))
53+ (->> [(System/getenv "JOLT_NATIVE_LIB")
54+ (System/getenv "LD_LIBRARY_PATH")]
55+ (remove str/blank?)
56+ (str/join ":"))}}
57+ (concat ["jolt" "-Sdeps" overrides "-m" "frq.tui"]
58+ *command-line-args*))))
@@ -5,91 +5,54 @@ exec "$(dirname "$0")/bb" "$0" "$@"
5 5
6 ;; frq's screens in a terminal, from this working tree.6 ;; frq's screens in a terminal, from this working tree.
7 ;;7 ;;
8-;; tui.bb [--headless] [--cols=N] [--rows=N]8+;; tui.bb [--headless] [--demo] [--cols=N] [--rows=N] [--wait=MS] [--dump]
9 ;;9 ;;
10-;; run.bb with the other backend under it. Two things differ, and both are10+;; run.bb with the other backend under it, and the same two halves: the frq
11-;; because the terminal backend is not in a jolt-native release yet:11+;; source is the files on disk, and everything below it is the flake's. The
12+;; dev shell builds jolt-native and names both Jolt sides of it — glimmer-vidya
13+;; for the window, glimmer-tui for the terminal — so this needs no checkout
14+;; beside the tree and no library fetched by digest.
12 ;;15 ;;
13-;; * `libjolttui.so` comes out of a jolt-native checkout's target directory16+;; It still loads libvidya as well as libjolttui. `frq.app` requires
14-;; rather than out of a pinned archive, and is linked into build/lib beside17+;; glimmer-vidya, and `frq.tui` requires glimmer-tui after it so the backend
15-;; the two that are pinned. Point JOLT_NATIVE at that checkout, or leave it18+;; installed last is the terminal; the window's library is resolved and then
16-;; beside this one.19+;; asked for nothing.
17-;; * `glimmer-tui` — the jolt half of that backend, and the namespace
18-;; `frq.tui` requires — is resolved from the same checkout with -Sdeps,
19-;; which is what lets this work from a worktree, where the relative path in
20-;; deps.edn's `:tui` alias does not point where it does from a clone. The
21-;; alias is not used here for that reason: its coordinate for the same
22-;; library wins over the one -Sdeps merges in, so this passes `-m` itself
23-;; and leaves `jolt -M:tui` to the checkouts the alias is right for.
24 ;;20 ;;
25-;; When the backend ships in a release, both of those become pins like every21+;; No nixGL here, unlike run.bb: a terminal wants nothing from the host's GL
26-;; other, and this script becomes run.bb with a different alias.22+;; driver, which is the reason this output exists on machines that have none.
27-(require '[babashka.fs :as fs]23+(require '[babashka.classpath :as cp])
28- '[babashka.process :as p])24+(cp/add-classpath (str (babashka.fs/parent *file*)))
25+(require '[frq.paths :as paths]
26+ '[babashka.fs :as fs]
27+ '[babashka.process :as p]
28+ '[clojure.string :as str])
29 29
30 (def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))30 (def root (str (fs/canonicalize (fs/path (fs/parent *file*) ".."))))
31-(def lib (fs/path root "build" "lib"))31+(def self (str (fs/path root "scripts" "tui.bb")))
32-32+
33-(def jolt33+;; Outside the shell, get inside it and come back to this same script — the
34- (let [pin (fs/path root "scripts" "jolt")]34+;; test, the flag and the reasoning are run.bb's.
35- (if (and (fs/exists? pin) (fs/which "dotslash")) (str pin) "jolt")))35+(when-not (System/getenv "JOLT_NATIVE_LIB")
36-36+ (let [cmd (paths/nix root
37-(defn die [& msg]37+ ["nix" "develop" root
38- (binding [*out* *err*] (println (apply str msg)))38+ "--max-jobs" (paths/env "FRQ_MAX_JOBS" "0")
39- (System/exit 1))39+ "--command" self]
40-40+ *command-line-args*)]
41-;; The checkout the terminal backend lives in. A worktree of it counts — what41+ (System/exit (:exit @(apply p/process {:inherit true :dir root} cmd)))))
42-;; is wanted is a directory holding `jolt/glimmer-tui` and a built libjolttui.42+
43-(def jolt-native43+(def overrides
44- (let [given (System/getenv "JOLT_NATIVE")44+ (str "{:deps {jolt-lang/glimmer {:local/root \"" (System/getenv "GLIMMER_SRC") "\"}"
45- guess (fs/path root ".." "jolt-native")45+ " nandi/glimmer-vidya {:local/root \"" (System/getenv "GLIMMER_VIDYA_SRC") "\"}"
46- dir (cond46+ " nandi/glimmer-tui {:local/root \"" (System/getenv "GLIMMER_TUI_SRC") "\"}}}"))
47- given (fs/path given)
48- (fs/exists? guess) guess
49- :else nil)]
50- (when-not dir
51- (die "no jolt-native checkout: set JOLT_NATIVE, or put one beside this tree"))
52- (str (fs/canonicalize dir))))
53-
54-(def glimmer-tui (fs/path jolt-native "jolt" "glimmer-tui"))
55-
56-(when-not (fs/exists? glimmer-tui)
57- (die glimmer-tui " is not there — this wants the branch that carries the "
58- "terminal backend (crates/jolt-tui and jolt/glimmer-tui)"))
59-
60-;; cargo's release build first, then its debug one, then what buck2 left: any
61-;; of the three is the library, and which one a person has is their business.
62-(def jolttui
63- (or (first (for [c ["target/release/libjolttui.so"
64- "target/debug/libjolttui.so"]
65- :let [p (fs/path jolt-native c)]
66- :when (fs/exists? p)]
67- p))
68- (first (sort-by (comp - fs/file-time->millis fs/last-modified-time)
69- (fs/glob (fs/path jolt-native "buck-out")
70- "**/libjolttui.so")))
71- (die "no libjolttui.so under " jolt-native
72- " — build it: cargo build --release -p jolt-tui")))
73-
74-;; The two pinned libraries, into build/lib.
75-(p/shell (str (fs/path root "scripts" "lib.bb")))
76-
77-;; And the unpinned third, linked rather than copied for the same reason the
78-;; others are: a rebuild reaches a running tree without anything here going
79-;; stale.
80-(let [dest (fs/path lib "libjolttui.so")]
81- (fs/create-dirs lib)
82- (fs/delete-if-exists dest)
83- (fs/create-sym-link dest (str (fs/canonicalize jolttui))))
84 47
85 (System/exit48 (System/exit
86 (:exit @(apply p/process49 (:exit @(apply p/process
87 {:inherit true50 {:inherit true
88 :dir root51 :dir root
89 :extra-env {"LD_LIBRARY_PATH"52 :extra-env {"LD_LIBRARY_PATH"
90- (str lib (when-let [p (System/getenv "LD_LIBRARY_PATH")]53+ (->> [(System/getenv "JOLT_NATIVE_LIB")
91- (str ":" p)))}}54+ (System/getenv "LD_LIBRARY_PATH")]
92- jolt55+ (remove str/blank?)
93- "-Sdeps" (str "{:deps {nandi/glimmer-tui {:local/root \""56+ (str/join ":"))}}
94- glimmer-tui "\"}}}")57+ (concat ["jolt" "-Sdeps" overrides "-m" "frq.tui"]
95- "-m" "frq.tui" *command-line-args*)))58+ *command-line-args*))))
modified src/frq/app.jolt +49 -5
@@ -11,6 +11,7 @@
1111 [frq.av :as av]
1212 [frq.avatars :as avatars]
1313 [frq.clock :as clock]
14+ [frq.glyphs :as glyphs]
1415 [frq.media :as media]
1516 [frq.platform :as platform]
1617 [frq.profile :as profile]
@@ -290,14 +291,57 @@
290291 (let [tail (subs text pos)]
291292 (cond-> acc (seq tail) (conj [:text tail])))))))
292293
294+(def ^:private text-emoji-size
295+ "An emoji in a message, at the size of the words around it. Bigger and the
296+ line it sits in grows to make room for it; smaller and it reads as a
297+ footnote on the sentence rather than a word of it."
298+ 14)
299+
300+(defn- word-node
301+ "Body text, or dim text for the lines the client writes itself."
302+ [k value system?]
303+ (if system?
304+ [:dim-label {:key k :label value}]
305+ [:label {:key k :label value}]))
306+
293307 (defn- run-node
294308 "One run as a widget. A link is accent-coloured and opens on click; the rest
295- is body text, or dim text for the lines the client writes itself."
309+ is body text.
310+
311+ Except for the emoji in it. A label is set in the text font, and that font —
312+ Ubuntu with a DejaVu subset behind it — has no emoji in it at all, so every
313+ one anybody typed was drawn as tofu. The Twemoji pack has the picture, so
314+ the emoji come out of the text and are drawn from the pack, and the words
315+ either side stay text.
316+
317+ `:emoji` and not `:reaction`, though both draw the same picture. A reaction
318+ is a tally: it wears a pill, it answers the pointer, and it names the people
319+ in it on hover. An emoji in a sentence is a character — so it is drawn bare,
320+ and a message that ends in one no longer reads as a message someone has
321+ reacted to.
322+
323+ The pieces go in a wrapping row rather than the column the runs themselves
324+ are stacked in: a row is what puts an emoji *in* a sentence instead of
325+ breaking the sentence around it, and `:hbox` wraps its children by default,
326+ so a long line still folds at the column's edge. A run with no emoji in it
327+ is still one plain label — the row is only paid for where it is needed."
296328 [j [kind value] system?]
297- (cond
298- (= :link kind) [:link {:key j :label value :on-click #(platform/open-url! value)}]
299- system? [:dim-label {:key j :label (str/trim value)}]
300- :else [:label {:key j :label (str/trim value)}]))
329+ (if (= :link kind)
330+ [:link {:key j :label value :on-click #(platform/open-url! value)}]
331+ (let [pieces (glyphs/runs (str/trim value))]
332+ (if (glyphs/emoji? pieces)
333+ ;; Runs alternate text and picture, so this gap only ever falls either
334+ ;; side of an emoji — never between two words, whose spacing is the
335+ ;; spaces the message was typed with. A bare glyph carries no margin of
336+ ;; its own the way the pill did, and a picture set flush against a word
337+ ;; reads as part of it.
338+ [:hbox {:key j :spacing 2}
339+ (map-indexed (fn [k [pkind pvalue]]
340+ (if (= :emoji pkind)
341+ [:emoji {:key k :emoji pvalue :size text-emoji-size}]
342+ (word-node k pvalue system?)))
343+ pieces)]
344+ (word-node j (str/trim value) system?)))))
301345
302346 (defn- summarise
303347 "A message in one line's worth of words."
@@ -11,6 +11,7 @@
11 [frq.av :as av]11 [frq.av :as av]
12 [frq.avatars :as avatars]12 [frq.avatars :as avatars]
13 [frq.clock :as clock]13 [frq.clock :as clock]
14+ [frq.glyphs :as glyphs]
14 [frq.media :as media]15 [frq.media :as media]
15 [frq.platform :as platform]16 [frq.platform :as platform]
16 [frq.profile :as profile]17 [frq.profile :as profile]
@@ -290,14 +291,57 @@
290 (let [tail (subs text pos)]291 (let [tail (subs text pos)]
291 (cond-> acc (seq tail) (conj [:text tail])))))))292 (cond-> acc (seq tail) (conj [:text tail])))))))
292 293
294+(def ^:private text-emoji-size
295+ "An emoji in a message, at the size of the words around it. Bigger and the
296+ line it sits in grows to make room for it; smaller and it reads as a
297+ footnote on the sentence rather than a word of it."
298+ 14)
299+
300+(defn- word-node
301+ "Body text, or dim text for the lines the client writes itself."
302+ [k value system?]
303+ (if system?
304+ [:dim-label {:key k :label value}]
305+ [:label {:key k :label value}]))
306+
293 (defn- run-node307 (defn- run-node
294 "One run as a widget. A link is accent-coloured and opens on click; the rest308 "One run as a widget. A link is accent-coloured and opens on click; the rest
295- is body text, or dim text for the lines the client writes itself."309+ is body text.
310+
311+ Except for the emoji in it. A label is set in the text font, and that font —
312+ Ubuntu with a DejaVu subset behind it — has no emoji in it at all, so every
313+ one anybody typed was drawn as tofu. The Twemoji pack has the picture, so
314+ the emoji come out of the text and are drawn from the pack, and the words
315+ either side stay text.
316+
317+ `:emoji` and not `:reaction`, though both draw the same picture. A reaction
318+ is a tally: it wears a pill, it answers the pointer, and it names the people
319+ in it on hover. An emoji in a sentence is a character — so it is drawn bare,
320+ and a message that ends in one no longer reads as a message someone has
321+ reacted to.
322+
323+ The pieces go in a wrapping row rather than the column the runs themselves
324+ are stacked in: a row is what puts an emoji *in* a sentence instead of
325+ breaking the sentence around it, and `:hbox` wraps its children by default,
326+ so a long line still folds at the column's edge. A run with no emoji in it
327+ is still one plain label — the row is only paid for where it is needed."
296 [j [kind value] system?]328 [j [kind value] system?]
297- (cond329+ (if (= :link kind)
298- (= :link kind) [:link {:key j :label value :on-click #(platform/open-url! value)}]330+ [:link {:key j :label value :on-click #(platform/open-url! value)}]
299- system? [:dim-label {:key j :label (str/trim value)}]331+ (let [pieces (glyphs/runs (str/trim value))]
300- :else [:label {:key j :label (str/trim value)}]))332+ (if (glyphs/emoji? pieces)
333+ ;; Runs alternate text and picture, so this gap only ever falls either
334+ ;; side of an emoji — never between two words, whose spacing is the
335+ ;; spaces the message was typed with. A bare glyph carries no margin of
336+ ;; its own the way the pill did, and a picture set flush against a word
337+ ;; reads as part of it.
338+ [:hbox {:key j :spacing 2}
339+ (map-indexed (fn [k [pkind pvalue]]
340+ (if (= :emoji pkind)
341+ [:emoji {:key k :emoji pvalue :size text-emoji-size}]
342+ (word-node k pvalue system?)))
343+ pieces)]
344+ (word-node j (str/trim value) system?)))))
301 345
302 (defn- summarise346 (defn- summarise
303 "A message in one line's worth of words."347 "A message in one line's worth of words."
added src/frq/glyphs.jolt +84 -0
new file mode 100644
@@ -0,0 +1,84 @@
1+(ns frq.glyphs
2+ "Where a line of chat stops being text and becomes a picture.
3+
4+ Vidya paints a `:label` with Ubuntu Light and a DejaVu subset behind it
5+ UI punctuation, maths-in-prose, box drawing and no emoji at all. So an
6+ emoji anybody typed into a message was drawn as tofu: the hollow box a font
7+ puts up for a codepoint it has no glyph for. The same emoji in a reaction
8+ pill drew properly all along, because a pill looks its glyph up in the
9+ Twemoji pack instead of setting it as text which is what `:emoji` does
10+ too, without the pill.
11+
12+ The split therefore has to happen before the text reaches a label, and this
13+ is where: the message cut into the parts a font can draw and the parts only
14+ the pack can."
15+ (:require [frq.emoji :as emoji]))
16+
17+(def ^:private tones
18+ "The five skin-tone modifiers.
19+
20+ `emoji/catalog` leaves toned variants out on purpose they multiply it by
21+ five and say nothing a reaction needs to say but the pack has a picture
22+ for every one, and vidya falls back to the untoned picture where it has
23+ none. So a tone is stripped for the lookup and kept for the drawing."
24+ #{0x1F3FB 0x1F3FC 0x1F3FD 0x1F3FE 0x1F3FF})
25+
26+(defn- untoned [s]
27+ (apply str (remove #(contains? tones (int %)) (seq s))))
28+
29+(def ^:private pack
30+ "Every emoji there is a picture for. `emoji/catalog` is already filtered to
31+ exactly that, which is why the lookup is against it and not against a range
32+ of codepoints: a codepoint the pack has missed would be swapped out of the
33+ text for a picture that does not exist, and drawn as the same tofu by a
34+ longer road."
35+ (set (map first emoji/catalog)))
36+
37+(def ^:private starts
38+ "The first codepoint of each of them. A message with no emoji in it — which
39+ is nearly all of them costs one set lookup a character this way, and no
40+ substrings at all."
41+ (set (map #(first (seq (first %))) emoji/catalog)))
42+
43+(def ^:private scan-limit
44+ "The most codepoints one emoji can run to. A family is a single glyph made
45+ of four people, three joiners and a tone each, so the scan cannot assume a
46+ cluster is short it is the longest thing in the catalog, plus room for the
47+ tones the catalog itself leaves out."
48+ (+ 5 (reduce max 1 (map #(count (first %)) emoji/catalog))))
49+
50+(defn- emoji-at
51+ "The longest emoji the pack knows that starts at `i`, or nil.
52+
53+ Longest first, because the short one is a prefix of the long one: 👨 is the
54+ head of 👨👩👧, and taking the man would leave his family as three more
55+ glyphs and two tofu joiners."
56+ [cps i]
57+ (loop [len (min scan-limit (- (count cps) i))]
58+ (when (pos? len)
59+ (let [s (apply str (subvec cps i (+ i len)))]
60+ (if (or (contains? pack s) (contains? pack (untoned s)))
61+ s
62+ (recur (dec len)))))))
63+
64+(defn runs
65+ "`text` as alternating `[:text s]` and `[:emoji s]` runs, in order.
66+
67+ An `:emoji` run is one glyph: a node draws one picture, so two emoji side by
68+ side are two runs and not one."
69+ [text]
70+ (let [cps (vec (seq (or text "")))
71+ n (count cps)
72+ flush (fn [acc buf] (cond-> acc (seq buf) (conj [:text (apply str buf)])))]
73+ (loop [i 0 buf [] acc []]
74+ (if (>= i n)
75+ (flush acc buf)
76+ (if-let [hit (and (contains? starts (nth cps i)) (emoji-at cps i))]
77+ (recur (+ i (count hit)) [] (conj (flush acc buf) [:emoji hit]))
78+ (recur (inc i) (conj buf (nth cps i)) acc))))))
79+
80+(defn emoji?
81+ "Whether any of `runs` is a picture — which is what decides between a plain
82+ label and a row that has to mix the two."
83+ [runs]
84+ (boolean (some #(= :emoji (first %)) runs)))
new file mode 100644
@@ -0,0 +1,84 @@
1+(ns frq.glyphs
2+ "Where a line of chat stops being text and becomes a picture.
3+
4+ Vidya paints a `:label` with Ubuntu Light and a DejaVu subset behind it
5+ UI punctuation, maths-in-prose, box drawing and no emoji at all. So an
6+ emoji anybody typed into a message was drawn as tofu: the hollow box a font
7+ puts up for a codepoint it has no glyph for. The same emoji in a reaction
8+ pill drew properly all along, because a pill looks its glyph up in the
9+ Twemoji pack instead of setting it as text which is what `:emoji` does
10+ too, without the pill.
11+
12+ The split therefore has to happen before the text reaches a label, and this
13+ is where: the message cut into the parts a font can draw and the parts only
14+ the pack can."
15+ (:require [frq.emoji :as emoji]))
16+
17+(def ^:private tones
18+ "The five skin-tone modifiers.
19+
20+ `emoji/catalog` leaves toned variants out on purpose they multiply it by
21+ five and say nothing a reaction needs to say but the pack has a picture
22+ for every one, and vidya falls back to the untoned picture where it has
23+ none. So a tone is stripped for the lookup and kept for the drawing."
24+ #{0x1F3FB 0x1F3FC 0x1F3FD 0x1F3FE 0x1F3FF})
25+
26+(defn- untoned [s]
27+ (apply str (remove #(contains? tones (int %)) (seq s))))
28+
29+(def ^:private pack
30+ "Every emoji there is a picture for. `emoji/catalog` is already filtered to
31+ exactly that, which is why the lookup is against it and not against a range
32+ of codepoints: a codepoint the pack has missed would be swapped out of the
33+ text for a picture that does not exist, and drawn as the same tofu by a
34+ longer road."
35+ (set (map first emoji/catalog)))
36+
37+(def ^:private starts
38+ "The first codepoint of each of them. A message with no emoji in it — which
39+ is nearly all of them costs one set lookup a character this way, and no
40+ substrings at all."
41+ (set (map #(first (seq (first %))) emoji/catalog)))
42+
43+(def ^:private scan-limit
44+ "The most codepoints one emoji can run to. A family is a single glyph made
45+ of four people, three joiners and a tone each, so the scan cannot assume a
46+ cluster is short it is the longest thing in the catalog, plus room for the
47+ tones the catalog itself leaves out."
48+ (+ 5 (reduce max 1 (map #(count (first %)) emoji/catalog))))
49+
50+(defn- emoji-at
51+ "The longest emoji the pack knows that starts at `i`, or nil.
52+
53+ Longest first, because the short one is a prefix of the long one: 👨 is the
54+ head of 👨👩👧, and taking the man would leave his family as three more
55+ glyphs and two tofu joiners."
56+ [cps i]
57+ (loop [len (min scan-limit (- (count cps) i))]
58+ (when (pos? len)
59+ (let [s (apply str (subvec cps i (+ i len)))]
60+ (if (or (contains? pack s) (contains? pack (untoned s)))
61+ s
62+ (recur (dec len)))))))
63+
64+(defn runs
65+ "`text` as alternating `[:text s]` and `[:emoji s]` runs, in order.
66+
67+ An `:emoji` run is one glyph: a node draws one picture, so two emoji side by
68+ side are two runs and not one."
69+ [text]
70+ (let [cps (vec (seq (or text "")))
71+ n (count cps)
72+ flush (fn [acc buf] (cond-> acc (seq buf) (conj [:text (apply str buf)])))]
73+ (loop [i 0 buf [] acc []]
74+ (if (>= i n)
75+ (flush acc buf)
76+ (if-let [hit (and (contains? starts (nth cps i)) (emoji-at cps i))]
77+ (recur (+ i (count hit)) [] (conj (flush acc buf) [:emoji hit]))
78+ (recur (inc i) (conj buf (nth cps i)) acc))))))
79+
80+(defn emoji?
81+ "Whether any of `runs` is a picture — which is what decides between a plain
82+ label and a row that has to mix the two."
83+ [runs]
84+ (boolean (some #(= :emoji (first %)) runs)))
deleted toolchains/BUCK +0 -19
deleted file mode 100644
@@ -1,19 +0,0 @@
1-# There is no compiler toolchain here, and that is the whole design.
2-#
3-# The APK's two native pieces are built by jolt-native: libvidya by its buck2
4-# graph, and the glue by the NDK its scripts/ pins. Everything this repo adds
5-# on top — the boot image, the dex, the packaging — is a tool invocation, so
6-# genrule is the only toolchain the graph needs. Nothing here is resolved
7-# against the machine except the Android SDK, which .buckconfig.local names.
8-load("@prelude//toolchains:genrule.bzl", "system_genrule_toolchain")
9-load("@prelude//toolchains:python.bzl", "system_python_bootstrap_toolchain")
10-
11-system_genrule_toolchain(
12- name = "genrule",
13- visibility = ["PUBLIC"],
14-)
15-
16-system_python_bootstrap_toolchain(
17- name = "python_bootstrap",
18- visibility = ["PUBLIC"],
19-)
deleted file mode 100644
@@ -1,19 +0,0 @@
1-# There is no compiler toolchain here, and that is the whole design.
2-#
3-# The APK's two native pieces are built by jolt-native: libvidya by its buck2
4-# graph, and the glue by the NDK its scripts/ pins. Everything this repo adds
5-# on top — the boot image, the dex, the packaging — is a tool invocation, so
6-# genrule is the only toolchain the graph needs. Nothing here is resolved
7-# against the machine except the Android SDK, which .buckconfig.local names.
8-load("@prelude//toolchains:genrule.bzl", "system_genrule_toolchain")
9-load("@prelude//toolchains:python.bzl", "system_python_bootstrap_toolchain")
10-
11-system_genrule_toolchain(
12- name = "genrule",
13- visibility = ["PUBLIC"],
14-)
15-
16-system_python_bootstrap_toolchain(
17- name = "python_bootstrap",
18- visibility = ["PUBLIC"],
19-)
deleted toolchains/dist.bzl +0 -32
deleted file mode 100644
@@ -1,32 +0,0 @@
1-# DotSlash, as a build artifact rather than something found on the machine.
2-#
3-# scripts/dotslash.dotslash is where the version and digest are written down,
4-# and it stays that way: dist/generated.bzl is derived from it by
5-# scripts/dotslash-to-buck, so there is one place to bump a version and no
6-# second copy of a digest to drift.
7-#
8-# Only DotSlash is fetched this way. jolt is not, and that is the point: what
9-# travels to a worker is the fetcher and the manifest, both small, and the
10-# worker resolves the manifest itself. See android/BUCK.
11-load("//dist:generated.bzl", "DIST")
12-
13-def dist_archive(name, tool, platform):
14- """One pinned archive, fetched by buck rather than by a shim.
15-
16- Unlike DotSlash, which resolves on the machine that runs a tool, this
17- makes the archive's contents an input: their bytes are in the digest of
18- every action that reads them, so a new release rebuilds what depends on
19- it and an unchanged one rebuilds nothing.
20- """
21- entry = DIST[tool][platform]
22- native.http_archive(
23- name = name,
24- urls = [entry["url"]],
25- sha256 = entry["sha256"],
26- strip_prefix = entry["strip_prefix"] or None,
27- type = entry["type"],
28- visibility = ["PUBLIC"],
29- )
30-
31-def dotslash_dist(name, platform):
32- dist_archive(name, "dotslash", platform)
deleted file mode 100644
@@ -1,32 +0,0 @@
1-# DotSlash, as a build artifact rather than something found on the machine.
2-#
3-# scripts/dotslash.dotslash is where the version and digest are written down,
4-# and it stays that way: dist/generated.bzl is derived from it by
5-# scripts/dotslash-to-buck, so there is one place to bump a version and no
6-# second copy of a digest to drift.
7-#
8-# Only DotSlash is fetched this way. jolt is not, and that is the point: what
9-# travels to a worker is the fetcher and the manifest, both small, and the
10-# worker resolves the manifest itself. See android/BUCK.
11-load("//dist:generated.bzl", "DIST")
12-
13-def dist_archive(name, tool, platform):
14- """One pinned archive, fetched by buck rather than by a shim.
15-
16- Unlike DotSlash, which resolves on the machine that runs a tool, this
17- makes the archive's contents an input: their bytes are in the digest of
18- every action that reads them, so a new release rebuilds what depends on
19- it and an unchanged one rebuilds nothing.
20- """
21- entry = DIST[tool][platform]
22- native.http_archive(
23- name = name,
24- urls = [entry["url"]],
25- sha256 = entry["sha256"],
26- strip_prefix = entry["strip_prefix"] or None,
27- type = entry["type"],
28- visibility = ["PUBLIC"],
29- )
30-
31-def dotslash_dist(name, platform):
32- dist_archive(name, "dotslash", platform)
deleted toolchains/dist/BUCK +0 -15
deleted file mode 100644
@@ -1,15 +0,0 @@
1-# The pinned fetcher. See ../dist.bzl; the version and digest come from
2-# scripts/dotslash.dotslash.
3-load("//:dist.bzl", "dist_archive", "dotslash_dist")
4-
5-dotslash_dist(name = "dotslash", platform = "linux-x86_64")
6-
7-# jolt-native's release: what a build gets when there is no sibling checkout to
8-# prefer — see the `buck` recipe in the justfile.
9-dist_archive(name = "libvidya-android", tool = "libvidya-android", platform = "linux-x86_64")
10-
11-dist_archive(name = "libjoltmoq-android", tool = "libjoltmoq-android", platform = "linux-x86_64")
12-
13-dist_archive(name = "glimmer-vidya", tool = "glimmer-vidya", platform = "linux-x86_64")
14-
15-dist_archive(name = "android-glue", tool = "android-glue", platform = "linux-x86_64")
deleted file mode 100644
@@ -1,15 +0,0 @@
1-# The pinned fetcher. See ../dist.bzl; the version and digest come from
2-# scripts/dotslash.dotslash.
3-load("//:dist.bzl", "dist_archive", "dotslash_dist")
4-
5-dotslash_dist(name = "dotslash", platform = "linux-x86_64")
6-
7-# jolt-native's release: what a build gets when there is no sibling checkout to
8-# prefer — see the `buck` recipe in the justfile.
9-dist_archive(name = "libvidya-android", tool = "libvidya-android", platform = "linux-x86_64")
10-
11-dist_archive(name = "libjoltmoq-android", tool = "libjoltmoq-android", platform = "linux-x86_64")
12-
13-dist_archive(name = "glimmer-vidya", tool = "glimmer-vidya", platform = "linux-x86_64")
14-
15-dist_archive(name = "android-glue", tool = "android-glue", platform = "linux-x86_64")
deleted toolchains/dist/generated.bzl +0 -137
deleted file mode 100644
@@ -1,137 +0,0 @@
1-# @generated by scripts/dotslash-to-buck — do not edit.
2-#
3-# The same archives scripts/*.dotslash pins, as facts buck can act on.
4-# Bump the DotSlash file and run `just sync-dist`.
5-
6-DIST = {
7- "android-glue": {
8- "linux-aarch64": {
9- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
10- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
11- "strip_prefix": "jolt-native-android-glue",
12- "type": "tar.gz"
13- },
14- "linux-x86_64": {
15- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
16- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
17- "strip_prefix": "jolt-native-android-glue",
18- "type": "tar.gz"
19- },
20- "macos-aarch64": {
21- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
22- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
23- "strip_prefix": "jolt-native-android-glue",
24- "type": "tar.gz"
25- },
26- "macos-x86_64": {
27- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
28- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
29- "strip_prefix": "jolt-native-android-glue",
30- "type": "tar.gz"
31- }
32- },
33- "dotslash": {
34- "linux-aarch64": {
35- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.arm64.v0.5.9.tar.gz",
36- "sha256": "e58374446dacd4a228388cd275d974bbd8f946916b513cf0eb86bdff5d9d675e",
37- "strip_prefix": "",
38- "type": "tar.gz"
39- },
40- "linux-x86_64": {
41- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.v0.5.9.tar.gz",
42- "sha256": "4c75c6eb7890ae35993b962073f6d9bbe78b42b81a5691303ad70f63bfbf7196",
43- "strip_prefix": "",
44- "type": "tar.gz"
45- },
46- "macos-aarch64": {
47- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-arm64.v0.5.9.tar.gz",
48- "sha256": "eef15be1b554de7b1409cb0c69c24f2cd04f19c0f101ad69fcdf9d66d4d51639",
49- "strip_prefix": "",
50- "type": "tar.gz"
51- },
52- "macos-x86_64": {
53- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-amd64.v0.5.9.tar.gz",
54- "sha256": "51446593596ffe4cd22bc43a0fe6d82dd367758eb53cb4ade36d6a684ed08469",
55- "strip_prefix": "",
56- "type": "tar.gz"
57- }
58- },
59- "glimmer-vidya": {
60- "linux-aarch64": {
61- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
62- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
63- "strip_prefix": "glimmer-vidya",
64- "type": "tar.gz"
65- },
66- "linux-x86_64": {
67- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
68- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
69- "strip_prefix": "glimmer-vidya",
70- "type": "tar.gz"
71- },
72- "macos-aarch64": {
73- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
74- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
75- "strip_prefix": "glimmer-vidya",
76- "type": "tar.gz"
77- },
78- "macos-x86_64": {
79- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
80- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
81- "strip_prefix": "glimmer-vidya",
82- "type": "tar.gz"
83- }
84- },
85- "libjoltmoq-android": {
86- "linux-aarch64": {
87- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
88- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
89- "strip_prefix": "",
90- "type": "tar.gz"
91- },
92- "linux-x86_64": {
93- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
94- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
95- "strip_prefix": "",
96- "type": "tar.gz"
97- },
98- "macos-aarch64": {
99- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
100- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
101- "strip_prefix": "",
102- "type": "tar.gz"
103- },
104- "macos-x86_64": {
105- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
106- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
107- "strip_prefix": "",
108- "type": "tar.gz"
109- }
110- },
111- "libvidya-android": {
112- "linux-aarch64": {
113- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
114- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
115- "strip_prefix": "",
116- "type": "tar.gz"
117- },
118- "linux-x86_64": {
119- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
120- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
121- "strip_prefix": "",
122- "type": "tar.gz"
123- },
124- "macos-aarch64": {
125- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
126- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
127- "strip_prefix": "",
128- "type": "tar.gz"
129- },
130- "macos-x86_64": {
131- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
132- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
133- "strip_prefix": "",
134- "type": "tar.gz"
135- }
136- }
137-}
deleted file mode 100644
@@ -1,137 +0,0 @@
1-# @generated by scripts/dotslash-to-buck — do not edit.
2-#
3-# The same archives scripts/*.dotslash pins, as facts buck can act on.
4-# Bump the DotSlash file and run `just sync-dist`.
5-
6-DIST = {
7- "android-glue": {
8- "linux-aarch64": {
9- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
10- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
11- "strip_prefix": "jolt-native-android-glue",
12- "type": "tar.gz"
13- },
14- "linux-x86_64": {
15- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
16- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
17- "strip_prefix": "jolt-native-android-glue",
18- "type": "tar.gz"
19- },
20- "macos-aarch64": {
21- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
22- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
23- "strip_prefix": "jolt-native-android-glue",
24- "type": "tar.gz"
25- },
26- "macos-x86_64": {
27- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-glue-v0.1.3.tar.gz",
28- "sha256": "83313eda124f2a0cfff6827cf4473600c1f71db2f208d654b97068a85af38da5",
29- "strip_prefix": "jolt-native-android-glue",
30- "type": "tar.gz"
31- }
32- },
33- "dotslash": {
34- "linux-aarch64": {
35- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.arm64.v0.5.9.tar.gz",
36- "sha256": "e58374446dacd4a228388cd275d974bbd8f946916b513cf0eb86bdff5d9d675e",
37- "strip_prefix": "",
38- "type": "tar.gz"
39- },
40- "linux-x86_64": {
41- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-linux-musl.x86_64.v0.5.9.tar.gz",
42- "sha256": "4c75c6eb7890ae35993b962073f6d9bbe78b42b81a5691303ad70f63bfbf7196",
43- "strip_prefix": "",
44- "type": "tar.gz"
45- },
46- "macos-aarch64": {
47- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-arm64.v0.5.9.tar.gz",
48- "sha256": "eef15be1b554de7b1409cb0c69c24f2cd04f19c0f101ad69fcdf9d66d4d51639",
49- "strip_prefix": "",
50- "type": "tar.gz"
51- },
52- "macos-x86_64": {
53- "url": "https://github.com/facebook/dotslash/releases/download/v0.5.9/dotslash-macos-amd64.v0.5.9.tar.gz",
54- "sha256": "51446593596ffe4cd22bc43a0fe6d82dd367758eb53cb4ade36d6a684ed08469",
55- "strip_prefix": "",
56- "type": "tar.gz"
57- }
58- },
59- "glimmer-vidya": {
60- "linux-aarch64": {
61- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
62- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
63- "strip_prefix": "glimmer-vidya",
64- "type": "tar.gz"
65- },
66- "linux-x86_64": {
67- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
68- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
69- "strip_prefix": "glimmer-vidya",
70- "type": "tar.gz"
71- },
72- "macos-aarch64": {
73- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
74- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
75- "strip_prefix": "glimmer-vidya",
76- "type": "tar.gz"
77- },
78- "macos-x86_64": {
79- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-glimmer-vidya-v0.1.3.tar.gz",
80- "sha256": "5ea0f7d2c3d3ff56daa3983c7222bd724a6dd4d6977c6b3bb2311d7d708ea9fe",
81- "strip_prefix": "glimmer-vidya",
82- "type": "tar.gz"
83- }
84- },
85- "libjoltmoq-android": {
86- "linux-aarch64": {
87- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
88- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
89- "strip_prefix": "",
90- "type": "tar.gz"
91- },
92- "linux-x86_64": {
93- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
94- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
95- "strip_prefix": "",
96- "type": "tar.gz"
97- },
98- "macos-aarch64": {
99- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
100- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
101- "strip_prefix": "",
102- "type": "tar.gz"
103- },
104- "macos-x86_64": {
105- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
106- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
107- "strip_prefix": "",
108- "type": "tar.gz"
109- }
110- },
111- "libvidya-android": {
112- "linux-aarch64": {
113- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
114- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
115- "strip_prefix": "",
116- "type": "tar.gz"
117- },
118- "linux-x86_64": {
119- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
120- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
121- "strip_prefix": "",
122- "type": "tar.gz"
123- },
124- "macos-aarch64": {
125- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
126- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
127- "strip_prefix": "",
128- "type": "tar.gz"
129- },
130- "macos-x86_64": {
131- "url": "https://gitlab.com/nandithebull/jolt-native/-/releases/v0.1.3/downloads/jolt-native-android-arm64-v0.1.3.tar.gz",
132- "sha256": "4519745bae6db9a791a71b38a26478879e246166802b0a48dbf7d45e4d45a108",
133- "strip_prefix": "",
134- "type": "tar.gz"
135- }
136- }
137-}