nandi/frqpublic Fork 0
7b594b1cb76366f8da6100724c37818830700e8c
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.

justfile · 300 lines · 13.9 KBMakefile Blame HistoryRaw
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago1# The work is here now, in recipe bodies, where it used to be in scripts/ —
2# babashka scripts run through a scripts/bb that went looking for a babashka.
3# That indirection bought one thing worth having, a shared way to reach nix on
4# a host that keeps it in a container, and `nix` below is the whole of it.
5#
6# Every recipe that runs frq has the same shape: outside the dev shell, re-enter
7# it and come back to this same recipe; inside, hand jolt the deps overrides and
8# the library path the shell exported. The re-entry test is JOLT_NATIVE_LIB,
9# which only the shell sets — no flag to forget, and no second code path for
10# someone who runs `nix develop --command just run` by hand.
Take glimmer-vidya from gitlab, so a stranger can build this 5c40e75 nandi 19d ago11
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago12set shell := ["bash", "-euo", "pipefail", "-c"]
A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 20d ago13
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago14# Every recipe below is a `#!` script and passes its arguments on with "$@".
15# Without this that is empty in one — just interpolates into a shebang recipe
16# rather than handing it argv — and `just tui --headless` silently ran the
17# terminal instead.
18set positional-arguments
19
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago20# nix is not on every host this runs on: on the machine these recipes were
21# written for it lives in an Arch distrobox, at the same path — which is why
22# the container is entered rather than the tree copied into it. See CLAUDE.md.
23nix := `command -v nix >/dev/null 2>&1 && echo nix || echo "distrobox enter arch -- nix"`
24
25# --max-jobs 0 is what sends the work to the `builders` entry rather than
26# compiling it here. Left to the default, nix prefers the local machine, and a
27# cold jolt-native is egui, openh264 and quinn on a laptop — for a derivation a
28# remote builder has likely built already. FRQ_MAX_JOBS=auto is the way out on
29# a machine with no builder configured.
30jobs := env("FRQ_MAX_JOBS", "0")
31
A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 20d ago32default:
33 @just --list
34
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago35# The build itself is nix/android.nix, reached as `.#apk`; this only asks nix
36# for the file and then does what was asked with it. Nothing here names an
37# Android SDK, an NDK, a Chez cross target or an OpenSSL: the derivation builds
38# or fetches every one of them.
39#
40# The APK is signed with a debug key generated inside the derivation, so the
41# output is installable and not reproducible; anything meant for a store gets
42# signed from `.#apk-unsigned` instead. See nix/android.nix.
43#
44# FRQ_NIX_STORE builds the whole graph somewhere else rather than here —
45#
46# FRQ_NIX_STORE=ssh-ng://eu.nixbuild.net just apk
47#
48# which is the shape android.nix asks for: with a `builders` entry instead, nix
49# copies every remotely-built output back, and androidenv's NDK is both
50# preferLocalBuild and absent from cache.nixos.org, so 3.1 GB of toolchain is
51# built here and uploaded. With the remote as the *store* only .drv files go
52# up. An install then needs the file here, so it is fetched back at the end —
53# one APK rather than the closure that made it.
54#
Build the APK as derivations only, and retire the buck2 graph 3bc3aaa nandi 16d ago55# The APK, out of the flake. `just apk install` puts it on the device.
Build the APK with buck2, from pins rather than from a second checkout a71ef8f nandi 19d ago56apk action="build":
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago57 #!/usr/bin/env bash
58 set -euo pipefail
59 cd "{{justfile_directory()}}"
60 adb="${ADB:-$HOME/.local/share/android-sdk/platform-tools/adb}"
61 package="uk.nandi.frq"
62
63 # --eval-store auto goes with a remote store and only with one: evaluation
64 # wants this tree, which is here.
65 store=()
66 [ -n "${FRQ_NIX_STORE:-}" ] && store=(--store "$FRQ_NIX_STORE" --eval-store auto)
67
68 build() {
69 # The Android objects come from jolt-native's CI under a "latest" alias,
70 # and a flake input is locked once and then stays put — so without this
71 # an APK is built against whatever flake.lock recorded the first time,
72 # however old. Only this input: a bare `nix flake update` would move
73 # jolt, nixpkgs and glimmer too, and the point of their pins is that
74 # they move when someone decides they should.
75 {{nix}} flake update jolt-native-android --flake . >&2
76
77 # Built without a `result` symlink: the path is what the caller wants,
78 # and a symlink into a store that may not be this one is not a useful
79 # thing to leave in the tree.
80 local out
81 out=$({{nix}} build .#apk --no-link --print-out-paths "${store[@]}" \
82 | grep '^/nix/store/' | tail -1)
83 [ -n "$out" ] || { echo "nix build printed no store path" >&2; exit 1; }
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago84
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago85 # Off a remote store the path names a file on the builder, so adb has
86 # nothing to open. `nix copy --from` brings just that one path here.
87 if [ -n "${FRQ_NIX_STORE:-}" ]; then
88 {{nix}} copy --no-check-sigs --from "$FRQ_NIX_STORE" "$out" >&2
89 fi
90 echo "$out"
91 }
92
93 case "{{action}}" in
94 build) build ;;
95 install) "$adb" install -r "$(build)" ;;
96 run) file=$(build)
97 "$adb" install -r "$file"
98 "$adb" shell am force-stop "$package"
99 "$adb" shell am start -n "$package/.FrqActivity" ;;
100 log) "$adb" logcat -s VidyaJolt Vidya ;;
101 *) echo "usage: just apk [build|install|run|log]" >&2; exit 1 ;;
102 esac
103
104# Two halves, and the split is the point. The frq source is the files on disk,
105# uncommitted edits and all. Everything under it — jolt, glimmer, glimmer-vidya,
106# both native objects — is the flake's, built rather than fetched.
107#
108# Deliberately not `nix run .#frq`. That builds the flake's own copy of the
109# source, which is the tree as git has it — so an edit that has not been
110# committed, or committed on a branch the command was not pointed at, runs as
111# whatever was there before, silently. A run meant to answer "does my change
112# work" has to be the files on disk.
113#
Run this tree on a native half the builders made a32699e nandi 17d ago114# The app: this tree's source on the flake's everything-else, in the dev shell.
A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 20d ago115run *args:
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago116 #!/usr/bin/env bash
117 set -euo pipefail
118 cd "{{justfile_directory()}}"
119 if [ -z "${JOLT_NATIVE_LIB:-}" ]; then
120 exec {{nix}} develop . --max-jobs {{jobs}} --command just run "$@"
121 fi
122
123 # The Jolt halves that have to match those objects. glimmer-vidya lives
124 # inside jolt-native and binds libvidya's ABI, so it comes out of the same
125 # input that was built rather than deps.edn's git sha — the pin drifting
126 # from the library is exactly what the flake input's comment describes.
127 deps="{:deps {jolt-lang/glimmer {:local/root \"$GLIMMER_SRC\"}"
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago128 deps="$deps nandi/glimmer-jvui {:local/root \"$GLIMMER_JVUI_SRC\"}"
129 deps="$deps jvui/jvui {:local/root \"$JVUI_SRC\"}}}"
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago130
131 export LD_LIBRARY_PATH="$JOLT_NATIVE_LIB:$FRQ_LIB_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
Paint the same screens into a terminal ab83b42 nandi 17d ago132
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago133 # On NixOS the store's Mesa is the system's and the window opens. Anywhere
134 # else — a bare host, or the distrobox above — the real driver is the
135 # host's, so defer to nixGL, which prepends it.
136 runner=()
137 [ -e /run/current-system ] || runner=("$NIXGL")
138
139 exec "${runner[@]}" jolt -Sdeps "$deps" -M:frq "$@"
140
141# `run` with the other backend under it. It still loads libvidya as well as
142# libjolttui: `frq.app` requires glimmer-vidya, and `frq.tui` requires
143# glimmer-tui after it so the backend installed last is the terminal.
144#
145# No nixGL here, unlike `run`: a terminal wants nothing from the host's GL
146# driver, which is the reason this output exists on machines that have none.
147#
Paint the same screens into a terminal ab83b42 nandi 17d ago148# The same screens in a terminal. `just tui --headless` prints one screenshot.
149tui *args:
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago150 #!/usr/bin/env bash
151 set -euo pipefail
152 cd "{{justfile_directory()}}"
153 if [ -z "${JOLT_NATIVE_LIB:-}" ]; then
154 exec {{nix}} develop . --max-jobs {{jobs}} --command just tui "$@"
155 fi
156
157 deps="{:deps {jolt-lang/glimmer {:local/root \"$GLIMMER_SRC\"}"
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago158 deps="$deps nandi/glimmer-jvui {:local/root \"$GLIMMER_JVUI_SRC\"}"
159 deps="$deps jvui/jvui {:local/root \"$JVUI_SRC\"}"
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago160 deps="$deps nandi/glimmer-tui {:local/root \"$GLIMMER_TUI_SRC\"}}}"
161
162 export LD_LIBRARY_PATH="$JOLT_NATIVE_LIB${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
Build the desktop libraries rather than fetching a release of them 0b81161 nandi 15d ago163
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago164 exec jolt -Sdeps "$deps" -m frq.tui "$@"
165
Paint frq with glimmer-cosmic, and give the tabs one shape 7b594b1 nandi 8d ago166# `run` with glimmer-cosmic under it, libcosmic doing the painting. There is
167# no pin to fall back on: the flake's jolt-native builds no libjoltcosmic, so
168# this needs a jolt-native checkout with one built, named by FRQ_JOLT_NATIVE
169# or found beside this tree the way the shell always looks.
170#
171# nix develop --command cargo build --release -p jolt-cosmic in that checkout
172#
173# Inside jolt-native's shell and not with the host's cargo: jolt runs on the
174# store's glibc, and an object linked against a newer host one (Arch's, here)
175# asks for symbol versions that glibc does not have — dlopen refuses it, and
176# jolt reports that as the library not being found at all.
177#
178# nixGL for the same reason as `run`: libcosmic paints through wgpu.
179#
180# The same screens, painted by libcosmic. A spike: most tags paint as columns.
181cosmic *args:
182 #!/usr/bin/env bash
183 set -euo pipefail
184 cd "{{justfile_directory()}}"
185 if [ -z "${JOLT_NATIVE_LIB:-}" ]; then
186 exec {{nix}} develop . --max-jobs {{jobs}} --command just cosmic "$@"
187 fi
188
189 if [ -z "${FRQ_JOLT_NATIVE:-}" ] || [ ! -e "$FRQ_JOLT_NATIVE/target/release/libjoltcosmic.so" ]; then
190 echo "frq: no libjoltcosmic.so in ${FRQ_JOLT_NATIVE:-the pin} — nix develop --command cargo build --release -p jolt-cosmic in a jolt-native checkout, then FRQ_JOLT_NATIVE=<it> just cosmic" >&2
191 exit 1
192 fi
193
194 deps="{:deps {jolt-lang/glimmer {:local/root \"$GLIMMER_SRC\"}"
195 deps="$deps nandi/glimmer-jvui {:local/root \"$GLIMMER_JVUI_SRC\"}"
196 deps="$deps jvui/jvui {:local/root \"$JVUI_SRC\"}"
197 deps="$deps nandi/glimmer-cosmic {:local/root \"$FRQ_JOLT_NATIVE/glimmer-backends/glimmer-cosmic\"}}}"
198
199 export LD_LIBRARY_PATH="$JOLT_NATIVE_LIB:$FRQ_LIB_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
200
201 runner=()
202 [ -e /run/current-system ] || runner=("$NIXGL")
203
204 exec "${runner[@]}" jolt -Sdeps "$deps" -m frq.cosmic "$@"
205
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago206# The same classpath as `tui`, with an nREPL on it instead of a `-main`: a
207# session that can require `frq.tui` and then redefine a component while it is
208# on screen, which is a second and not the minute a rebuild costs.
209#
210# just nrepl then, from an editor or a client on 7888:
211# (require (quote frq.tui)) both backends, terminal installed last
212# (frq.tui/-main "--headless" "--demo")
213# (glimmer.core/reload!) re-mount after redefining a component
214#
215# `just repl nrepl-server` is the window's half of this — the same thing minus
216# glimmer-tui. Port is nrepl-server's own positional: `just nrepl 7889`.
217nrepl *args:
218 #!/usr/bin/env bash
219 set -euo pipefail
220 cd "{{justfile_directory()}}"
221 if [ -z "${JOLT_NATIVE_LIB:-}" ]; then
222 exec {{nix}} develop . --max-jobs {{jobs}} --command just nrepl "$@"
223 fi
224
225 deps="{:deps {jolt-lang/glimmer {:local/root \"$GLIMMER_SRC\"}"
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago226 deps="$deps nandi/glimmer-jvui {:local/root \"$GLIMMER_JVUI_SRC\"}"
227 deps="$deps jvui/jvui {:local/root \"$JVUI_SRC\"}"
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago228 deps="$deps nandi/glimmer-tui {:local/root \"$GLIMMER_TUI_SRC\"}}}"
229
230 export LD_LIBRARY_PATH="$JOLT_NATIVE_LIB:$FRQ_LIB_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
231
232 exec jolt -Sdeps "$deps" nrepl-server "$@"
233
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago234# `jolt` in the repo root does not work on its own: deps.edn carries
235# :jolt/native, so every invocation here loads libvidya and libjoltmoq before it
236# reads a line, and dies naming the library if the loader cannot find them. So
237# this is `run` without the app — and `run` is this with a window's worth of
238# extra care about the GL driver.
239#
Build the desktop libraries rather than fetching a release of them 0b81161 nandi 15d ago240# A jolt with the native libraries under it: a REPL, or `just repl nrepl-server`.
241repl *args:
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago242 #!/usr/bin/env bash
243 set -euo pipefail
244 cd "{{justfile_directory()}}"
245 if [ -z "${JOLT_NATIVE_LIB:-}" ]; then
246 exec {{nix}} develop . --max-jobs {{jobs}} --command just repl "$@"
247 fi
248
249 deps="{:deps {jolt-lang/glimmer {:local/root \"$GLIMMER_SRC\"}"
Paint frq with jvui, and take the last Rust out of the window 77963dc nandi 9d ago250 deps="$deps nandi/glimmer-jvui {:local/root \"$GLIMMER_JVUI_SRC\"}"
251 deps="$deps jvui/jvui {:local/root \"$JVUI_SRC\"}}}"
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago252
253 export LD_LIBRARY_PATH="$JOLT_NATIVE_LIB:$FRQ_LIB_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
254
255 exec jolt -Sdeps "$deps" "$@"
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago256
257# Regenerate src/frq/moq/raw.clj from the libmoq_ffi we actually load.
258#
259# UniFFI embeds its interface metadata in the object, so `uniffi-bindgen
260# --library` reads the truth out of the .so rather than a header shipped
Fetch libmoq_ffi again, and keep the codecs out of Rust f518938 nandi 9d ago261# beside it. Those differ at one version number: the published Linux and
262# Android objects are built without moq-ffi's `audio` and `video` features
263# (206 functions, no codecs), while the shipped C header describes the Apple
264# build (230). The object is the only source this recipe will accept.
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago265#
266# The bindgen must match the uniffi that built the object — 0.32 for moq-ffi
267# 0.3.17 — and it is built once into the scratch dir rather than pinned into
268# the flake: nothing in a normal build needs it, and a regeneration is a thing
269# done when the moq-ffi pin moves, by hand, on purpose.
270#
271# just gen-moq # the loaded library
272# just gen-moq path/to/libmoq_ffi.so
273#
274# Regenerate the libmoq_ffi bindings from the object's own embedded metadata.
275gen-moq lib="":
276 #!/usr/bin/env bash
277 set -euo pipefail
278 lib="${1:-${JOLT_NATIVE_LIB:-}/libmoq_ffi.so}"
279 [ -f "$lib" ] || { echo "no libmoq_ffi.so at $lib — pass one: just gen-moq <path>" >&2; exit 1; }
280 work="${TMPDIR:-/tmp}/frq-gen-moq"
281 mkdir -p "$work/ubg/src"
282 cat > "$work/ubg/Cargo.toml" <<'TOML'
283 [package]
284 name = "ubg"
285 version = "0.1.0"
286 edition = "2021"
287 [[bin]]
288 name = "uniffi-bindgen"
289 path = "src/main.rs"
290 [dependencies]
291 uniffi = { version = "0.32", features = ["cli"] }
292 TOML
293 echo 'fn main() { uniffi::uniffi_bindgen_main() }' > "$work/ubg/src/main.rs"
294 ( cd "$work/ubg" && cargo build --release -q )
295 ( cd "$work/ubg" && ./target/release/uniffi-bindgen generate \
296 --library "$lib" --language python --out-dir "$work/py" --no-format )
297 python3 tools/py2jolt.py "$work"/py/*.py > "$work/body.clj"
298 { sed -n '1,/^ (:require \[jolt.ffi :as ffi\]))$/p' src/frq/moq/raw.clj; echo; cat "$work/body.clj"; } > "$work/raw.clj"
299 mv "$work/raw.clj" src/frq/moq/raw.clj
300 echo "wrote src/frq/moq/raw.clj ($(grep -c '^(ffi/defcfn' src/frq/moq/raw.clj) entry points)"