nandi/frqpublic Fork 0
3975b4bc9fe9fd59fc0e81ca2bb7ffdba986934a
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 · 270 lines · 11.2 KBMakefile Blame HistoryRaw
Six verbs, and the last of the nix 2e24e64 nandi 13h 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 13h 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 13h 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 13h 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 13h 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 13h 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 13h 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 13h 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 13h 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 13h 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 13h 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 13h ago104 cd "{{root}}"
105 shift
106 case "{{suite}}" in
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 13h 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 13h ago109 common) exec python3 tools/check-common.py common ;;
Four more modules into Nim: members, glyphs, emoji, store 3975b4b nandi 8h ago110 emoji) exec python3 tools/emoji2nim.py ;;
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 13h ago111 layout) just _nim-lib
112 just _flutter layout test ;;
Six verbs, and the last of the nix 2e24e64 nandi 13h ago113 nim) just _nim-test "$@" ;;
114 dart) just _nim-lib
115 exec "{{tc}}" exec -- bash -c \
116 'cd dart/frq_core && dart pub get && dart test -r expanded' ;;
117 live) just _nim-lib
118 exec "{{tc}}" exec -- bash -c \
119 'cd dart/frq_core && dart pub get >/dev/null && dart run tool/live_ui.dart "$@"' _ "$@" ;;
120 *) echo "usage: just test [all|common|nim|dart|live]" >&2; exit 1 ;;
121 esac
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago122
Six verbs, and the last of the nix 2e24e64 nandi 13h ago123# The containers in `.modal/`, run on Modal rather than here: this machine
124# 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 ago125#
Six verbs, and the last of the nix 2e24e64 nandi 13h ago126# `--shell` leaves a sandbox running with the container's own image, volumes
127# and environment, and prints the command to attach to it. It blocks — an
128# ephemeral app takes its sandbox down when the entrypoint returns — so attach
129# from a second terminal and Ctrl-C here when done. The sandbox bills until
130# you do.
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago131#
Six verbs, and the last of the nix 2e24e64 nandi 13h ago132# just modal dev
133# just modal web --shell
134[doc('run a .modal/ container on Modal')]
135modal container="dev" *args:
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago136 #!/usr/bin/env bash
137 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 13h ago138 cd "{{root}}"
139 shift || true
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago140 exec modal run ".modal/{{container}}/container.py" "$@"
141
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago142# The Modal-built web bundle, served from this machine on localhost.
143#
Six verbs, and the last of the nix 2e24e64 nandi 13h ago144# Not a local build: `modal volume get` pulls down what `just modal
145# web` already compiled, so this needs only python3.
146#
147# It exists for the auth broker rather than for convenience. freeq's broker
148# finishes an OAuth login by redirecting to `return_to`, and only to an origin
149# on its allowlist: its own https hosts, and http://localhost or
150# http://127.0.0.1 on ANY port. Served from anywhere else — the Modal URL
151# included — a Bluesky sign-in gets `400 Invalid return_to URL` and can never
152# complete. Guest and app-password sign-in work on the deployed URL; neither
153# goes near the broker.
154[doc('serve the Modal-built web bundle on localhost')]
155serve port="8080":
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago156 #!/usr/bin/env bash
157 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 13h ago158 cd "{{root}}"
159 out="{{root}}/.web-local"
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago160 mkdir -p "$out"
161 echo "fetching the Modal-built bundle…"
162 # --force: this is a mirror of the volume, and a stale file left behind
163 # would be served in preference to the one just built.
Six verbs, and the last of the nix 2e24e64 nandi 13h ago164 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 ago165 echo
166 echo " http://localhost:{{port}}"
167 echo
Six verbs, and the last of the nix 2e24e64 nandi 13h ago168 echo "Bluesky sign-in works here and not on the Modal URL. Put"
169 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 ago170 exec python3 -m http.server {{port}} --bind 127.0.0.1 --directory "$out/web"
171
Six verbs, and the last of the nix 2e24e64 nandi 13h ago172# --- the work behind the verbs ------------------------------------------
One frontend where there were three, and a core that is not Clojure 438b247 nandi 17h ago173
174# The Nim core as a shared library, into build/nim.
175#
The renderer, and a transport bug that took four tries 58e6c97 nandi 14h ago176# `--mm:orc` and not refc, and it is not a preference: refc gives each thread
177# its own GC heap, so the Socket the reader and writer threads share is a ref
178# 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 17h ago179#
180# `-d:release` and not `-d:danger`: the bounds checks are what turn a
Six verbs, and the last of the nix 2e24e64 nandi 13h ago181# malformed line off a socket into an exception rather than a read past the
182# end of a buffer, and this parses exactly that.
183[private]
184_nim-lib:
One frontend where there were three, and a core that is not Clojure 438b247 nandi 17h ago185 #!/usr/bin/env bash
186 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 13h ago187 cd "{{root}}"
188 out="{{root}}/build/nim"
One frontend where there were three, and a core that is not Clojure 438b247 nandi 17h ago189 mkdir -p "$out"
Six verbs, and the last of the nix 2e24e64 nandi 13h ago190 exec "{{tc}}" exec -- bash -euo pipefail -c '
191 cd nim
192 nim c --app:lib --mm:orc -d:release --hints:off \
193 --path:src --out:"'"$out"'/libfrqcore.so" src/frq_core.nim
194 echo "built '"$out"'/libfrqcore.so"
195 nm -D --defined-only "'"$out"'/libfrqcore.so" | grep " T frq_" || true'
196
197[private]
198_nim-test *args:
The binding is Dart, and it works f7aea3b nandi 17h ago199 #!/usr/bin/env bash
200 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 13h ago201 cd "{{root}}"
202 exec "{{tc}}" exec -- bash -euo pipefail -c '
203 cd nim
204 if [ -n "${1:-}" ]; then
205 exec nim c -r --hints:off --path:src "tests/$1.nim"
206 fi
207 for t in tests/t*.nim; do
208 echo "== $t"
209 nim c -r --hints:off --path:src "$t"
210 done' _ "$@"
211
212# The three Flutter targets, which differ only in what they compile and which
213# entry point they paint.
214#
215# apk ClojureDart, then Gradle. Impure on purpose: Gradle resolves its
216# own dependencies over the network and has sdkmanager install a
217# platform and build-tools into ANDROID_HOME as it goes, so the
218# SDK has to be writable — which is what `just tools android` gets
219# it. Everything it leaves behind is under `.toolchain/` and
220# gitignored.
221# desktop the same `clojure -M:cljd compile`, Flutter's Linux target.
222# ui no ClojureDart at all: `lib/main_nim.dart` asks the Nim core for
223# a widget tree and paints it.
224# app `frq.main-nim` is `frq.main` with one line changed —
225# `frq.net.nim/install!` where it said `frq.net.dart/install!`.
226# Every screen, cell and action is the one that was already there.
227[private]
228_flutter target action:
Nim under the existing UI, not instead of it 56551a8 nandi 16h ago229 #!/usr/bin/env bash
230 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 13h ago231 cd "{{root}}"
232 case "{{target}}" in
233 apk) "{{tc}}" android ;;
Lay every screen out in a test, and fix what that found 36bdfc5 nandi 13h ago234 ui|app|layout) just _nim-lib ;;
Nim under the existing UI, not instead of it 56551a8 nandi 16h ago235 esac
Six verbs, and the last of the nix 2e24e64 nandi 13h ago236 exec "{{tc}}" exec -- bash -euo pipefail -c '
237 cd flutter
238 # Nim resolves OpenSSL through dynlib at run time; without the host
239 # library on the loader path `newContext` dies in a SIGSEGV that says
240 # nothing about SSL.
241 export LD_LIBRARY_PATH="${FRQ_OPENSSL_LIB:-}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
242 cljd() { clojure -Sdeps "{:mvn/local-repo \"$FRQ_M2\"}" -M:cljd compile "$@"; }
243
244 case "$1:$2" in
245 apk:*)
246 cljd
247 # Rewritten every run: it carries absolute paths.
248 flutter config --android-sdk "$ANDROID_HOME" >/dev/null
249 flutter build apk --debug
250 apk=build/app/outputs/flutter-apk/app-debug.apk
251 [ "$2" = run ] || exit 0
252 adb install -r "$apk"
253 exec adb shell monkey -p uk.nandi.frq \
254 -c android.intent.category.LAUNCHER 1 ;;
255 desktop:build) cljd; exec flutter build linux --debug ;;
256 desktop:run) cljd; exec flutter run -d linux ;;
257 ui:build) flutter pub get
258 exec flutter build linux --debug -t lib/main_nim.dart ;;
259 ui:run) flutter pub get
260 exec flutter run -d linux -t lib/main_nim.dart ;;
261 app:build) flutter pub get; cljd frq.main-nim
262 exec flutter build linux --debug -t lib/main_nim_app.dart ;;
263 app:run) flutter pub get; cljd frq.main-nim
264 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 13h ago265 # Widget tests, which lay every screen out for real. Headless: no
266 # GL, no window, which is what makes them the check a Wayland
267 # window cannot be.
268 layout:test) flutter pub get
269 exec flutter test test/nim_layout_test.dart ;;
Six verbs, and the last of the nix 2e24e64 nandi 13h ago270 esac' _ "{{target}}" "{{action}}"