nandi/frqpublic Fork 0
4dfc71908cc3f12174bb0d6dd8688ff3164879c3
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 · 269 lines · 11.1 KBMakefile Blame HistoryRaw
Six verbs, and the last of the nix 2e24e64 nandi 12h ago1# Six verbs over one tree.
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago2#
Six verbs, and the last of the nix 2e24e64 nandi 12h ago3# There is no nix here any more. `tools/toolchain.sh` fetches Flutter (which
4# carries Dart), a JDK, the Clojure CLI and Nim as sha256-pinned tarballs into
5# `.toolchain/`, and every recipe below runs inside the environment that
6# script prints. One mechanism, and the same one the containers in `.modal/`
7# use — which is what lets a plain Debian image build this.
8#
9# What the host still brings: a C compiler (Nim shells out to one), OpenSSL
10# (nim.cfg is `-d:ssl`), git, curl, unzip, python3. For `run desktop` and the
11# other Linux builds, GTK and the usual CMake/Ninja/pkg-config.
12#
13# just build TARGET apk desktop web lib ui app
14# just run TARGET apk desktop web ui app
15# just test SUITE all nim dart common live
16# just modal CONTAINER dev web
17# just serve [PORT] the Modal-built web bundle, on localhost
18# just tools ... the toolchain itself
Take glimmer-vidya from gitlab, so a stranger can build this 5c40e75 nandi 19d ago19
Write the build in babashka, and pin the babashka 34832a8 nandi 18d ago20set shell := ["bash", "-euo", "pipefail", "-c"]
A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 20d ago21
Six verbs, and the last of the nix 2e24e64 nandi 12h ago22# Every recipe is a `#!` script. Without this, "$@" is empty in one of them —
23# just interpolates into a shebang recipe rather than handing it argv.
Give the terminal's classpath an nREPL, and hand recipes their arguments 664397d nandi 10d ago24set positional-arguments
25
Six verbs, and the last of the nix 2e24e64 nandi 12h ago26root := justfile_directory()
27tc := justfile_directory() / "tools/toolchain.sh"
Inline the babashka scripts into the justfile 76dcc6c nandi 11d ago28
A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 20d ago29default:
30 @just --list
31
Six verbs, and the last of the nix 2e24e64 nandi 12h ago32# The toolchain, directly: `just tools versions`, `just tools android`,
33# `just tools exec -- flutter doctor`.
34[doc('the toolchain itself: versions, android, exec -- CMD')]
35tools *args:
36 #!/usr/bin/env bash
37 cd "{{root}}"
38 exec "{{tc}}" "$@"
39
40# Build a target.
41#
42# apk the Android app, via Gradle
43# desktop the ClojureDart app on Flutter's Linux target
44# web the same screens compiled to JavaScript, into build/web
45# lib the Nim core as build/nim/libfrqcore.so
46# ui Nim owning the state and the screens, painted by Flutter
47# app the ClojureDart app with the Nim core as its transport only
48[doc('build a target: apk desktop web lib ui app')]
49build target="desktop":
Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 7d ago50 #!/usr/bin/env bash
51 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago52 cd "{{root}}"
53 case "{{target}}" in
54 apk) just _flutter apk build ;;
55 desktop) just _flutter desktop build ;;
56 web) exec tools/build-web.sh build ;;
57 lib) just _nim-lib ;;
58 ui) just _flutter ui build ;;
59 app) just _flutter app build ;;
60 *) echo "usage: just build [apk|desktop|web|lib|ui|app]" >&2; exit 1 ;;
Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 7d ago61 esac
62
Six verbs, and the last of the nix 2e24e64 nandi 12h ago63# Build a target and start it.
Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 7d ago64#
Six verbs, and the last of the nix 2e24e64 nandi 12h ago65# apk install on a connected device and launch it
66# web serve build/web on ARG (default 8080)
67# the rest open the window
Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 7d ago68#
Six verbs, and the last of the nix 2e24e64 nandi 12h ago69# just run apk
70# just run web 3000
71[doc('build a target and start it')]
72run target="desktop" arg="":
Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 7d ago73 #!/usr/bin/env bash
74 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago75 cd "{{root}}"
76 case "{{target}}" in
77 apk) just _flutter apk run ;;
78 desktop) just _flutter desktop run ;;
79 web) port="${2:-}"; exec tools/build-web.sh serve "${port:-8080}" ;;
80 ui) just _flutter ui run ;;
81 app) just _flutter app run ;;
82 log) just tools exec -- adb logcat -s flutter ;;
83 *) echo "usage: just run [apk|desktop|web|ui|app|log]" >&2; exit 1 ;;
Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 7d ago84 esac
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago85
Six verbs, and the last of the nix 2e24e64 nandi 12h ago86# Test a suite.
87#
88# common what may appear in common/, read off the source. Needs no
89# toolchain at all, which is why CI runs exactly this.
90# nim the Nim core. No Flutter, no Dart, no SDK — a rule about the IRC
91# wire format is checkable in a second.
92# dart the Dart side of the FFI boundary, on the plain Dart VM. Passing
93# `nim` and failing this one is a marshalling bug, which is why the
94# two are separate suites.
95# live the whole stack against a real freeq. Not in `all`: it wants a
96# network and a running server.
97#
98# just test all of them
99# just test nim tircparse one Nim file
100[doc('run a suite: all common nim dart live')]
101test suite="all" *args:
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago102 #!/usr/bin/env bash
103 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago104 cd "{{root}}"
105 shift
106 case "{{suite}}" in
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 11h ago107 all) just test common && just test nim && just test dart \
108 && just test layout ;;
Six verbs, and the last of the nix 2e24e64 nandi 12h ago109 common) exec python3 tools/check-common.py common ;;
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 11h ago110 layout) just _nim-lib
111 just _flutter layout test ;;
Six verbs, and the last of the nix 2e24e64 nandi 12h ago112 nim) just _nim-test "$@" ;;
113 dart) just _nim-lib
114 exec "{{tc}}" exec -- bash -c \
115 'cd dart/frq_core && dart pub get && dart test -r expanded' ;;
116 live) just _nim-lib
117 exec "{{tc}}" exec -- bash -c \
118 'cd dart/frq_core && dart pub get >/dev/null && dart run tool/live_ui.dart "$@"' _ "$@" ;;
119 *) echo "usage: just test [all|common|nim|dart|live]" >&2; exit 1 ;;
120 esac
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago121
Six verbs, and the last of the nix 2e24e64 nandi 12h ago122# The containers in `.modal/`, run on Modal rather than here: this machine
123# evaluates and Modal builds. See CLAUDE.md, which says so rather more firmly.
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago124#
Six verbs, and the last of the nix 2e24e64 nandi 12h ago125# `--shell` leaves a sandbox running with the container's own image, volumes
126# and environment, and prints the command to attach to it. It blocks — an
127# ephemeral app takes its sandbox down when the entrypoint returns — so attach
128# from a second terminal and Ctrl-C here when done. The sandbox bills until
129# you do.
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago130#
Six verbs, and the last of the nix 2e24e64 nandi 12h ago131# just modal dev
132# just modal web --shell
133[doc('run a .modal/ container on Modal')]
134modal container="dev" *args:
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago135 #!/usr/bin/env bash
136 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago137 cd "{{root}}"
138 shift || true
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago139 exec modal run ".modal/{{container}}/container.py" "$@"
140
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago141# The Modal-built web bundle, served from this machine on localhost.
142#
Six verbs, and the last of the nix 2e24e64 nandi 12h ago143# Not a local build: `modal volume get` pulls down what `just modal
144# web` already compiled, so this needs only python3.
145#
146# It exists for the auth broker rather than for convenience. freeq's broker
147# finishes an OAuth login by redirecting to `return_to`, and only to an origin
148# on its allowlist: its own https hosts, and http://localhost or
149# http://127.0.0.1 on ANY port. Served from anywhere else — the Modal URL
150# included — a Bluesky sign-in gets `400 Invalid return_to URL` and can never
151# complete. Guest and app-password sign-in work on the deployed URL; neither
152# goes near the broker.
153[doc('serve the Modal-built web bundle on localhost')]
154serve port="8080":
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago155 #!/usr/bin/env bash
156 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago157 cd "{{root}}"
158 out="{{root}}/.web-local"
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago159 mkdir -p "$out"
160 echo "fetching the Modal-built bundle…"
161 # --force: this is a mirror of the volume, and a stale file left behind
162 # would be served in preference to the one just built.
Six verbs, and the last of the nix 2e24e64 nandi 12h ago163 modal volume get --force devshell frq-web/flutter/build/web "$out"
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago164 echo
165 echo " http://localhost:{{port}}"
166 echo
Six verbs, and the last of the nix 2e24e64 nandi 12h ago167 echo "Bluesky sign-in works here and not on the Modal URL. Put"
168 echo "wss://irc.freeq.at/irc in the Server field — a browser has no TCP."
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago169 exec python3 -m http.server {{port}} --bind 127.0.0.1 --directory "$out/web"
170
Six verbs, and the last of the nix 2e24e64 nandi 12h ago171# --- the work behind the verbs ------------------------------------------
One frontend where there were three, and a core that is not Clojure 438b247 nandi 16h ago172
173# The Nim core as a shared library, into build/nim.
174#
The renderer, and a transport bug that took four tries 58e6c97 nandi 13h ago175# `--mm:orc` and not refc, and it is not a preference: refc gives each thread
176# its own GC heap, so the Socket the reader and writer threads share is a ref
177# from another heap and dereferencing it segfaults. ORC's heap is shared.
One frontend where there were three, and a core that is not Clojure 438b247 nandi 16h ago178#
179# `-d:release` and not `-d:danger`: the bounds checks are what turn a
Six verbs, and the last of the nix 2e24e64 nandi 12h ago180# malformed line off a socket into an exception rather than a read past the
181# end of a buffer, and this parses exactly that.
182[private]
183_nim-lib:
One frontend where there were three, and a core that is not Clojure 438b247 nandi 16h ago184 #!/usr/bin/env bash
185 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago186 cd "{{root}}"
187 out="{{root}}/build/nim"
One frontend where there were three, and a core that is not Clojure 438b247 nandi 16h ago188 mkdir -p "$out"
Six verbs, and the last of the nix 2e24e64 nandi 12h ago189 exec "{{tc}}" exec -- bash -euo pipefail -c '
190 cd nim
191 nim c --app:lib --mm:orc -d:release --hints:off \
192 --path:src --out:"'"$out"'/libfrqcore.so" src/frq_core.nim
193 echo "built '"$out"'/libfrqcore.so"
194 nm -D --defined-only "'"$out"'/libfrqcore.so" | grep " T frq_" || true'
195
196[private]
197_nim-test *args:
The binding is Dart, and it works f7aea3b nandi 16h ago198 #!/usr/bin/env bash
199 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago200 cd "{{root}}"
201 exec "{{tc}}" exec -- bash -euo pipefail -c '
202 cd nim
203 if [ -n "${1:-}" ]; then
204 exec nim c -r --hints:off --path:src "tests/$1.nim"
205 fi
206 for t in tests/t*.nim; do
207 echo "== $t"
208 nim c -r --hints:off --path:src "$t"
209 done' _ "$@"
210
211# The three Flutter targets, which differ only in what they compile and which
212# entry point they paint.
213#
214# apk ClojureDart, then Gradle. Impure on purpose: Gradle resolves its
215# own dependencies over the network and has sdkmanager install a
216# platform and build-tools into ANDROID_HOME as it goes, so the
217# SDK has to be writable — which is what `just tools android` gets
218# it. Everything it leaves behind is under `.toolchain/` and
219# gitignored.
220# desktop the same `clojure -M:cljd compile`, Flutter's Linux target.
221# ui no ClojureDart at all: `lib/main_nim.dart` asks the Nim core for
222# a widget tree and paints it.
223# app `frq.main-nim` is `frq.main` with one line changed —
224# `frq.net.nim/install!` where it said `frq.net.dart/install!`.
225# Every screen, cell and action is the one that was already there.
226[private]
227_flutter target action:
Nim under the existing UI, not instead of it 56551a8 nandi 15h ago228 #!/usr/bin/env bash
229 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 12h ago230 cd "{{root}}"
231 case "{{target}}" in
232 apk) "{{tc}}" android ;;
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 11h ago233 ui|app|layout) just _nim-lib ;;
Nim under the existing UI, not instead of it 56551a8 nandi 15h ago234 esac
Six verbs, and the last of the nix 2e24e64 nandi 12h ago235 exec "{{tc}}" exec -- bash -euo pipefail -c '
236 cd flutter
237 # Nim resolves OpenSSL through dynlib at run time; without the host
238 # library on the loader path `newContext` dies in a SIGSEGV that says
239 # nothing about SSL.
240 export LD_LIBRARY_PATH="${FRQ_OPENSSL_LIB:-}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
241 cljd() { clojure -Sdeps "{:mvn/local-repo \"$FRQ_M2\"}" -M:cljd compile "$@"; }
242
243 case "$1:$2" in
244 apk:*)
245 cljd
246 # Rewritten every run: it carries absolute paths.
247 flutter config --android-sdk "$ANDROID_HOME" >/dev/null
248 flutter build apk --debug
249 apk=build/app/outputs/flutter-apk/app-debug.apk
250 [ "$2" = run ] || exit 0
251 adb install -r "$apk"
252 exec adb shell monkey -p uk.nandi.frq \
253 -c android.intent.category.LAUNCHER 1 ;;
254 desktop:build) cljd; exec flutter build linux --debug ;;
255 desktop:run) cljd; exec flutter run -d linux ;;
256 ui:build) flutter pub get
257 exec flutter build linux --debug -t lib/main_nim.dart ;;
258 ui:run) flutter pub get
259 exec flutter run -d linux -t lib/main_nim.dart ;;
260 app:build) flutter pub get; cljd frq.main-nim
261 exec flutter build linux --debug -t lib/main_nim_app.dart ;;
262 app:run) flutter pub get; cljd frq.main-nim
263 exec flutter run -d linux -t lib/main_nim_app.dart ;;
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 11h ago264 # Widget tests, which lay every screen out for real. Headless: no
265 # GL, no window, which is what makes them the check a Wayland
266 # window cannot be.
267 layout:test) flutter pub get
268 exec flutter test test/nim_layout_test.dart ;;
Six verbs, and the last of the nix 2e24e64 nandi 12h ago269 esac' _ "{{target}}" "{{action}}"