nandi/frqpublic Fork 0
fce25eccf64f75d87838c0ac1016b7c4d33db960
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 · 260 lines · 12.0 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
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago166# The same classpath as `tui`, with an nREPL on it instead of a `-main`: a
167# session that can require `frq.tui` and then redefine a component while it is
168# on screen, which is a second and not the minute a rebuild costs.
169#
170# just nrepl then, from an editor or a client on 7888:
171# (require (quote frq.tui)) both backends, terminal installed last
172# (frq.tui/-main "--headless" "--demo")
173# (glimmer.core/reload!) re-mount after redefining a component
174#
175# `just repl nrepl-server` is the window's half of this — the same thing minus
176# glimmer-tui. Port is nrepl-server's own positional: `just nrepl 7889`.
177nrepl *args:
178 #!/usr/bin/env bash
179 set -euo pipefail
180 cd "{{justfile_directory()}}"
181 if [ -z "${JOLT_NATIVE_LIB:-}" ]; then
182 exec {{nix}} develop . --max-jobs {{jobs}} --command just nrepl "$@"
183 fi
184
185 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 ago186 deps="$deps nandi/glimmer-jvui {:local/root \"$GLIMMER_JVUI_SRC\"}"
187 deps="$deps jvui/jvui {:local/root \"$JVUI_SRC\"}"
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago188 deps="$deps nandi/glimmer-tui {:local/root \"$GLIMMER_TUI_SRC\"}}}"
189
190 export LD_LIBRARY_PATH="$JOLT_NATIVE_LIB:$FRQ_LIB_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
191
192 exec jolt -Sdeps "$deps" nrepl-server "$@"
193
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago194# `jolt` in the repo root does not work on its own: deps.edn carries
195# :jolt/native, so every invocation here loads libvidya and libjoltmoq before it
196# reads a line, and dies naming the library if the loader cannot find them. So
197# this is `run` without the app — and `run` is this with a window's worth of
198# extra care about the GL driver.
199#
Build the desktop libraries rather than fetching a release of them 0b81161 nandi 15d ago200# A jolt with the native libraries under it: a REPL, or `just repl nrepl-server`.
201repl *args:
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago202 #!/usr/bin/env bash
203 set -euo pipefail
204 cd "{{justfile_directory()}}"
205 if [ -z "${JOLT_NATIVE_LIB:-}" ]; then
206 exec {{nix}} develop . --max-jobs {{jobs}} --command just repl "$@"
207 fi
208
209 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 ago210 deps="$deps nandi/glimmer-jvui {:local/root \"$GLIMMER_JVUI_SRC\"}"
211 deps="$deps jvui/jvui {:local/root \"$JVUI_SRC\"}}}"
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago212
213 export LD_LIBRARY_PATH="$JOLT_NATIVE_LIB:$FRQ_LIB_PATH${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
214
215 exec jolt -Sdeps "$deps" "$@"
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago216
217# Regenerate src/frq/moq/raw.clj from the libmoq_ffi we actually load.
218#
219# UniFFI embeds its interface metadata in the object, so `uniffi-bindgen
220# --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 ago221# beside it. Those differ at one version number: the published Linux and
222# Android objects are built without moq-ffi's `audio` and `video` features
223# (206 functions, no codecs), while the shipped C header describes the Apple
224# 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 ago225#
226# The bindgen must match the uniffi that built the object — 0.32 for moq-ffi
227# 0.3.17 — and it is built once into the scratch dir rather than pinned into
228# the flake: nothing in a normal build needs it, and a regeneration is a thing
229# done when the moq-ffi pin moves, by hand, on purpose.
230#
231# just gen-moq # the loaded library
232# just gen-moq path/to/libmoq_ffi.so
233#
234# Regenerate the libmoq_ffi bindings from the object's own embedded metadata.
235gen-moq lib="":
236 #!/usr/bin/env bash
237 set -euo pipefail
238 lib="${1:-${JOLT_NATIVE_LIB:-}/libmoq_ffi.so}"
239 [ -f "$lib" ] || { echo "no libmoq_ffi.so at $lib — pass one: just gen-moq <path>" >&2; exit 1; }
240 work="${TMPDIR:-/tmp}/frq-gen-moq"
241 mkdir -p "$work/ubg/src"
242 cat > "$work/ubg/Cargo.toml" <<'TOML'
243 [package]
244 name = "ubg"
245 version = "0.1.0"
246 edition = "2021"
247 [[bin]]
248 name = "uniffi-bindgen"
249 path = "src/main.rs"
250 [dependencies]
251 uniffi = { version = "0.32", features = ["cli"] }
252 TOML
253 echo 'fn main() { uniffi::uniffi_bindgen_main() }' > "$work/ubg/src/main.rs"
254 ( cd "$work/ubg" && cargo build --release -q )
255 ( cd "$work/ubg" && ./target/release/uniffi-bindgen generate \
256 --library "$lib" --language python --out-dir "$work/py" --no-format )
257 python3 tools/py2jolt.py "$work"/py/*.py > "$work/body.clj"
258 { sed -n '1,/^ (:require \[jolt.ffi :as ffi\]))$/p' src/frq/moq/raw.clj; echo; cat "$work/body.clj"; } > "$work/raw.clj"
259 mv "$work/raw.clj" src/frq/moq/raw.clj
260 echo "wrote src/frq/moq/raw.clj ($(grep -c '^(ffi/defcfn' src/frq/moq/raw.clj) entry points)"