nandi/frqpublic Fork 0
2e24e647a7766c822d13d253777204c3bf92fb7a
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 · 261 lines · 10.7 KBMakefile Blame HistoryRaw
Six verbs, and the last of the nix 2e24e64 nandi 15h 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 15h 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 15h 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 15h 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 15h 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 15h 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 15h 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 15h 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 15h 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 15h 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 15h 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 15h ago104 cd "{{root}}"
105 shift
106 case "{{suite}}" in
107 all) just test common && just test nim && just test dart ;;
108 common) exec python3 tools/check-common.py common ;;
109 nim) just _nim-test "$@" ;;
110 dart) just _nim-lib
111 exec "{{tc}}" exec -- bash -c \
112 'cd dart/frq_core && dart pub get && dart test -r expanded' ;;
113 live) just _nim-lib
114 exec "{{tc}}" exec -- bash -c \
115 'cd dart/frq_core && dart pub get >/dev/null && dart run tool/live_ui.dart "$@"' _ "$@" ;;
116 *) echo "usage: just test [all|common|nim|dart|live]" >&2; exit 1 ;;
117 esac
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago118
Six verbs, and the last of the nix 2e24e64 nandi 15h ago119# The containers in `.modal/`, run on Modal rather than here: this machine
120# 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 ago121#
Six verbs, and the last of the nix 2e24e64 nandi 15h ago122# `--shell` leaves a sandbox running with the container's own image, volumes
123# and environment, and prints the command to attach to it. It blocks — an
124# ephemeral app takes its sandbox down when the entrypoint returns — so attach
125# from a second terminal and Ctrl-C here when done. The sandbox bills until
126# you do.
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago127#
Six verbs, and the last of the nix 2e24e64 nandi 15h ago128# just modal dev
129# just modal web --shell
130[doc('run a .modal/ container on Modal')]
131modal container="dev" *args:
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago132 #!/usr/bin/env bash
133 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 15h ago134 cd "{{root}}"
135 shift || true
A shell that is already the devShell, and two recipes to reach it e853593 nandi 5d ago136 exec modal run ".modal/{{container}}/container.py" "$@"
137
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago138# The Modal-built web bundle, served from this machine on localhost.
139#
Six verbs, and the last of the nix 2e24e64 nandi 15h ago140# Not a local build: `modal volume get` pulls down what `just modal
141# web` already compiled, so this needs only python3.
142#
143# It exists for the auth broker rather than for convenience. freeq's broker
144# finishes an OAuth login by redirecting to `return_to`, and only to an origin
145# on its allowlist: its own https hosts, and http://localhost or
146# http://127.0.0.1 on ANY port. Served from anywhere else — the Modal URL
147# included — a Bluesky sign-in gets `400 Invalid return_to URL` and can never
148# complete. Guest and app-password sign-in work on the deployed URL; neither
149# goes near the broker.
150[doc('serve the Modal-built web bundle on localhost')]
151serve port="8080":
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago152 #!/usr/bin/env bash
153 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 15h ago154 cd "{{root}}"
155 out="{{root}}/.web-local"
A third target, and the seam that was already waiting for it f54ca45 nandi 2d ago156 mkdir -p "$out"
157 echo "fetching the Modal-built bundle…"
158 # --force: this is a mirror of the volume, and a stale file left behind
159 # would be served in preference to the one just built.
Six verbs, and the last of the nix 2e24e64 nandi 15h ago160 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 ago161 echo
162 echo " http://localhost:{{port}}"
163 echo
Six verbs, and the last of the nix 2e24e64 nandi 15h ago164 echo "Bluesky sign-in works here and not on the Modal URL. Put"
165 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 ago166 exec python3 -m http.server {{port}} --bind 127.0.0.1 --directory "$out/web"
167
Six verbs, and the last of the nix 2e24e64 nandi 15h ago168# --- the work behind the verbs ------------------------------------------
One frontend where there were three, and a core that is not Clojure 438b247 nandi 19h ago169
170# The Nim core as a shared library, into build/nim.
171#
The renderer, and a transport bug that took four tries 58e6c97 nandi 16h ago172# `--mm:orc` and not refc, and it is not a preference: refc gives each thread
173# its own GC heap, so the Socket the reader and writer threads share is a ref
174# 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 19h ago175#
176# `-d:release` and not `-d:danger`: the bounds checks are what turn a
Six verbs, and the last of the nix 2e24e64 nandi 15h ago177# malformed line off a socket into an exception rather than a read past the
178# end of a buffer, and this parses exactly that.
179[private]
180_nim-lib:
One frontend where there were three, and a core that is not Clojure 438b247 nandi 19h ago181 #!/usr/bin/env bash
182 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 15h ago183 cd "{{root}}"
184 out="{{root}}/build/nim"
One frontend where there were three, and a core that is not Clojure 438b247 nandi 19h ago185 mkdir -p "$out"
Six verbs, and the last of the nix 2e24e64 nandi 15h ago186 exec "{{tc}}" exec -- bash -euo pipefail -c '
187 cd nim
188 nim c --app:lib --mm:orc -d:release --hints:off \
189 --path:src --out:"'"$out"'/libfrqcore.so" src/frq_core.nim
190 echo "built '"$out"'/libfrqcore.so"
191 nm -D --defined-only "'"$out"'/libfrqcore.so" | grep " T frq_" || true'
192
193[private]
194_nim-test *args:
The binding is Dart, and it works f7aea3b nandi 19h ago195 #!/usr/bin/env bash
196 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 15h ago197 cd "{{root}}"
198 exec "{{tc}}" exec -- bash -euo pipefail -c '
199 cd nim
200 if [ -n "${1:-}" ]; then
201 exec nim c -r --hints:off --path:src "tests/$1.nim"
202 fi
203 for t in tests/t*.nim; do
204 echo "== $t"
205 nim c -r --hints:off --path:src "$t"
206 done' _ "$@"
207
208# The three Flutter targets, which differ only in what they compile and which
209# entry point they paint.
210#
211# apk ClojureDart, then Gradle. Impure on purpose: Gradle resolves its
212# own dependencies over the network and has sdkmanager install a
213# platform and build-tools into ANDROID_HOME as it goes, so the
214# SDK has to be writable — which is what `just tools android` gets
215# it. Everything it leaves behind is under `.toolchain/` and
216# gitignored.
217# desktop the same `clojure -M:cljd compile`, Flutter's Linux target.
218# ui no ClojureDart at all: `lib/main_nim.dart` asks the Nim core for
219# a widget tree and paints it.
220# app `frq.main-nim` is `frq.main` with one line changed —
221# `frq.net.nim/install!` where it said `frq.net.dart/install!`.
222# Every screen, cell and action is the one that was already there.
223[private]
224_flutter target action:
Nim under the existing UI, not instead of it 56551a8 nandi 18h ago225 #!/usr/bin/env bash
226 set -euo pipefail
Six verbs, and the last of the nix 2e24e64 nandi 15h ago227 cd "{{root}}"
228 case "{{target}}" in
229 apk) "{{tc}}" android ;;
230 ui|app) just _nim-lib ;;
Nim under the existing UI, not instead of it 56551a8 nandi 18h ago231 esac
Six verbs, and the last of the nix 2e24e64 nandi 15h ago232 exec "{{tc}}" exec -- bash -euo pipefail -c '
233 cd flutter
234 # Nim resolves OpenSSL through dynlib at run time; without the host
235 # library on the loader path `newContext` dies in a SIGSEGV that says
236 # nothing about SSL.
237 export LD_LIBRARY_PATH="${FRQ_OPENSSL_LIB:-}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
238 cljd() { clojure -Sdeps "{:mvn/local-repo \"$FRQ_M2\"}" -M:cljd compile "$@"; }
239
240 case "$1:$2" in
241 apk:*)
242 cljd
243 # Rewritten every run: it carries absolute paths.
244 flutter config --android-sdk "$ANDROID_HOME" >/dev/null
245 flutter build apk --debug
246 apk=build/app/outputs/flutter-apk/app-debug.apk
247 [ "$2" = run ] || exit 0
248 adb install -r "$apk"
249 exec adb shell monkey -p uk.nandi.frq \
250 -c android.intent.category.LAUNCHER 1 ;;
251 desktop:build) cljd; exec flutter build linux --debug ;;
252 desktop:run) cljd; exec flutter run -d linux ;;
253 ui:build) flutter pub get
254 exec flutter build linux --debug -t lib/main_nim.dart ;;
255 ui:run) flutter pub get
256 exec flutter run -d linux -t lib/main_nim.dart ;;
257 app:build) flutter pub get; cljd frq.main-nim
258 exec flutter build linux --debug -t lib/main_nim_app.dart ;;
259 app:run) flutter pub get; cljd frq.main-nim
260 exec flutter run -d linux -t lib/main_nim_app.dart ;;
261 esac' _ "{{target}}" "{{action}}"