| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 1 | # Six verbs over one tree. |
| Inline the babashka scripts into the justfile 76dcc6c nandi 12d ago | 2 | # |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 3 | # 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 |
| The last of the Clojure 284b59c nandi yesterday | 16 | # just modal CONTAINER dev |
| CI builds the image, Modal serves it 5693bd5 nandi 9h ago | 17 | # just deploy web the CI-built image, to a Modal URL |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 18 | # just serve [PORT] the Modal-built web bundle, on localhost |
| 19 | # just tools ... the toolchain itself |
| Take glimmer-vidya from gitlab, so a stranger can build this 5c40e75 nandi 20d ago | 20 | |
| Write the build in babashka, and pin the babashka 34832a8 nandi 19d ago | 21 | set shell := ["bash", "-euo", "pipefail", "-c"] |
| A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 21d ago | 22 | |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 23 | # Every recipe is a `#!` script. Without this, "$@" is empty in one of them — |
| 24 | # 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 11d ago | 25 | set positional-arguments |
| 26 | |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 27 | root := justfile_directory() |
| 28 | tc := justfile_directory() / "tools/toolchain.sh" |
| Inline the babashka scripts into the justfile 76dcc6c nandi 12d ago | 29 | |
| A freeq client in jolt, as glimmer components on Vidya 4719d6f nandi 21d ago | 30 | default: |
| 31 | @just --list |
| 32 | |
| The last of the Clojure 284b59c nandi yesterday | 33 | # The toolchain, directly: `just tools versions`, |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 34 | # `just tools exec -- flutter doctor`. |
| The last of the Clojure 284b59c nandi yesterday | 35 | [doc('the toolchain itself: versions, exec -- CMD')] |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 36 | tools *args: |
| 37 | #!/usr/bin/env bash |
| 38 | cd "{{root}}" |
| 39 | exec "{{tc}}" "$@" |
| 40 | |
| 41 | # Build a target. |
| 42 | # |
| The last of the Clojure 284b59c nandi yesterday | 43 | # desktop the app: Nim owns the state and the screens, Flutter paints |
| A web version, from the same core 23846db nandi 10h ago | 44 | # web the same, in a browser: the core compiled by `nim js`, the |
| 45 | # socket a WebSocket to freeq's own bridge, Flutter painting |
| The last of the Clojure 284b59c nandi yesterday | 46 | # lib the Nim core alone, as build/nim/libfrqcore.so |
| A web version, from the same core 23846db nandi 10h ago | 47 | # core-js the core alone, as build/web/frq_core.js |
| The last of the Clojure 284b59c nandi yesterday | 48 | # |
| 49 | # There were four more. `apk` and `web` compiled ClojureDart and went with it: |
| 50 | # the web target cannot come back without a wasm build of the core, since a |
| 51 | # browser has no dart:ffi, and the APK wants libfrqcore.so cross-compiled for |
| 52 | # Android's ABIs. `ui` and `app` were the two halves of the migration, and |
| 53 | # there is one app now. |
| A web version, from the same core 23846db nandi 10h ago | 54 | [doc('build a target: desktop web lib core-js')] |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 55 | build target="desktop": |
| Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 8d ago | 56 | #!/usr/bin/env bash |
| 57 | set -euo pipefail |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 58 | cd "{{root}}" |
| 59 | case "{{target}}" in |
| 60 | desktop) just _flutter desktop build ;; |
| A web version, from the same core 23846db nandi 10h ago | 61 | web) just _web-bundle ;; |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 62 | lib) just _nim-lib ;; |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 63 | core-js) just _nim-js ;; |
| A web version, from the same core 23846db nandi 10h ago | 64 | *) echo "usage: just build [desktop|web|lib|core-js]" >&2; exit 1 ;; |
| Build the APK, out of ClojureDart and Flutter e2b0e6b nandi 8d ago | 65 | esac |
| 66 | |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 67 | # Build a target and start it. |
| Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 8d ago | 68 | # |
| The last of the Clojure 284b59c nandi yesterday | 69 | # FRQ_TRACE=1 every line in and out, both languages in one log |
| 70 | # FRQ_AUTOCONNECT=1 press Connect at startup, for a window a script cannot |
| 71 | # click; FRQ_NICK overrides the nickname |
| A web version, from the same core 23846db nandi 10h ago | 72 | [doc('build the app and start it: desktop web')] |
| The last of the Clojure 284b59c nandi yesterday | 73 | run target="desktop": |
| Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 8d ago | 74 | #!/usr/bin/env bash |
| 75 | set -euo pipefail |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 76 | cd "{{root}}" |
| 77 | case "{{target}}" in |
| 78 | desktop) just _flutter desktop run ;; |
| A web version, from the same core 23846db nandi 10h ago | 79 | web) just _web-bundle |
| 80 | echo "serving build/web on http://localhost:8000" |
| 81 | exec python3 -m http.server 8000 --directory build/web ;; |
| 82 | *) echo "usage: just run [desktop|web]" >&2; exit 1 ;; |
| Paint the desktop with Flutter too, beside libcosmic fc5f63c nandi 8d ago | 83 | esac |
| A shell that is already the devShell, and two recipes to reach it e853593 nandi 6d ago | 84 | |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 85 | # Test a suite. |
| 86 | # |
| 87 | # nim the Nim core. No Flutter, no Dart, no SDK — a rule about the IRC |
| 88 | # wire format is checkable in a second. |
| 89 | # dart the Dart side of the FFI boundary, on the plain Dart VM. Passing |
| 90 | # `nim` and failing this one is a marshalling bug, which is why the |
| 91 | # two are separate suites. |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 92 | # web the JavaScript build of the same core, driven as a browser |
| 93 | # drives it. Needs node and nothing else. |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 94 | # live the whole stack against a real freeq. Not in `all`: it wants a |
| 95 | # network and a running server. |
| 96 | # |
| 97 | # just test all of them |
| 98 | # just test nim tircparse one Nim file |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 99 | [doc('run a suite: all nim dart layout web live')] |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 100 | test suite="all" *args: |
| A third target, and the seam that was already waiting for it f54ca45 nandi 3d ago | 101 | #!/usr/bin/env bash |
| 102 | set -euo pipefail |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 103 | cd "{{root}}" |
| 104 | shift |
| 105 | case "{{suite}}" in |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 106 | all) just test nim && just test dart && just test layout \ |
| 107 | && just test web ;; |
| Lay every screen out in a test, and fix what that found 36bdfc5 nandi yesterday | 108 | layout) just _nim-lib |
| 109 | just _flutter layout test ;; |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 110 | nim) just _nim-test "$@" ;; |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 111 | web) just _nim-js |
| 112 | exec node nim/web/test/smoke.js build/web/frq_core.js ;; |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 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 "$@"' _ "$@" ;; |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 119 | *) echo "usage: just test [all|nim|dart|layout|web|live]" >&2; exit 1 ;; |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 120 | esac |
| A third target, and the seam that was already waiting for it f54ca45 nandi 3d ago | 121 | |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 122 | # 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 6d ago | 124 | # |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 125 | # `--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 6d ago | 130 | # |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 131 | # just modal dev |
| The last of the Clojure 284b59c nandi yesterday | 132 | # just modal dev --shell |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 133 | [doc('run a .modal/ container on Modal')] |
| 134 | modal container="dev" *args: |
| A shell that is already the devShell, and two recipes to reach it e853593 nandi 6d ago | 135 | #!/usr/bin/env bash |
| 136 | set -euo pipefail |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 137 | cd "{{root}}" |
| 138 | shift || true |
| A shell that is already the devShell, and two recipes to reach it e853593 nandi 6d ago | 139 | exec modal run ".modal/{{container}}/container.py" "$@" |
| 140 | |
| CI builds the image, Modal serves it 5693bd5 nandi 9h ago | 141 | # Deploy, rather than run: a URL that stays up between pushes. |
| 142 | # |
| The registry it pushes to is the one it has 627b785 nandi 9h ago | 143 | # Nothing is built here. `.modal/web/` points at an image rickub already made |
| 144 | # and pushed, and FRQ_WEB_IMAGE is which tag of it — so this is the same |
| 145 | # command the `web` workflow's deploy job runs, with the tag named by hand |
| 146 | # instead of by the commit. Normally you want the job; this is for deploying an older tag, or a |
| CI builds the image, Modal serves it 5693bd5 nandi 9h ago | 147 | # first deploy before CI has one. |
| 148 | # |
| The registry it pushes to is the one it has 627b785 nandi 9h ago | 149 | # FRQ_WEB_IMAGE=registry.rickub.com/nandi/frq-web:<sha> just deploy web |
| CI builds the image, Modal serves it 5693bd5 nandi 9h ago | 150 | [doc('deploy a .modal/ container as a URL (needs FRQ_WEB_IMAGE)')] |
| 151 | deploy container="web": |
| 152 | #!/usr/bin/env bash |
| 153 | set -euo pipefail |
| 154 | cd "{{root}}" |
| 155 | if [ -z "${FRQ_WEB_IMAGE:-}" ]; then |
| 156 | echo "deploy: set FRQ_WEB_IMAGE to the image tag CI pushed" >&2 |
| 157 | echo " e.g. registry.gitlab.com/<ns>/frq/web:\$(git rev-parse HEAD)" >&2 |
| 158 | exit 1 |
| 159 | fi |
| 160 | exec modal deploy ".modal/{{container}}/container.py" |
| 161 | |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 162 | # The same core, compiled to JavaScript. |
| 163 | # |
| 164 | # `--path:src --path:web`, in that order, because the later path wins: every |
| 165 | # module under `nim/web/frq` shadows the one beside it in `nim/src/frq`, so |
| 166 | # `frq/conn` is a queue the host fills rather than two socket threads, and the |
| 167 | # shared code above them never learns which host it is on. |
| A web version, from the same core 23846db nandi 10h ago | 168 | # The web bundle: the core as JavaScript, and Flutter around it. |
| 169 | # |
| 170 | # The core goes into `flutter/web/` rather than being copied afterwards, |
| 171 | # because `flutter build web` copies that directory into the bundle — so the |
| 172 | # page's `<script src="frq_core.js">` resolves the same in a dev server as it |
| 173 | # does in the built output. |
| 174 | [private] |
| 175 | _web-bundle: |
| 176 | #!/usr/bin/env bash |
| 177 | set -euo pipefail |
| 178 | cd "{{root}}" |
| 179 | just _nim-js |
| 180 | cp build/web/frq_core.js flutter/web/frq_core.js |
| 181 | exec "{{tc}}" exec -- bash -euo pipefail -c ' |
| 182 | cd flutter |
| 183 | flutter pub get |
| 184 | flutter build web |
| 185 | rm -rf ../build/web |
| 186 | cp -r build/web ../build/web |
| 187 | echo "built build/web"' |
| 188 | |
| The core, compiled to JavaScript 5ac0521 nandi 10h ago | 189 | [private] |
| 190 | _nim-js: |
| 191 | #!/usr/bin/env bash |
| 192 | set -euo pipefail |
| 193 | cd "{{root}}" |
| 194 | out="{{root}}/build/web" |
| 195 | mkdir -p "$out" |
| 196 | exec "{{tc}}" exec -- bash -euo pipefail -c ' |
| 197 | cd nim |
| 198 | nim js -d:release --hints:off \ |
| 199 | --path:src --path:web --out:"'"$out"'/frq_core.js" web/frq_web.nim |
| 200 | printf "built %s (%s)\n" "'"$out"'/frq_core.js" \ |
| 201 | "$(gzip -9c "'"$out"'/frq_core.js" | wc -c | awk "{printf \"%d KB gzipped\", \$1/1024}")"' |
| 202 | |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 203 | [private] |
| 204 | _nim-lib: |
| One frontend where there were three, and a core that is not Clojure 438b247 nandi yesterday | 205 | #!/usr/bin/env bash |
| 206 | set -euo pipefail |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 207 | cd "{{root}}" |
| 208 | out="{{root}}/build/nim" |
| One frontend where there were three, and a core that is not Clojure 438b247 nandi yesterday | 209 | mkdir -p "$out" |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 210 | exec "{{tc}}" exec -- bash -euo pipefail -c ' |
| 211 | cd nim |
| 212 | nim c --app:lib --mm:orc -d:release --hints:off \ |
| 213 | --path:src --out:"'"$out"'/libfrqcore.so" src/frq_core.nim |
| 214 | echo "built '"$out"'/libfrqcore.so" |
| 215 | nm -D --defined-only "'"$out"'/libfrqcore.so" | grep " T frq_" || true' |
| 216 | |
| 217 | [private] |
| 218 | _nim-test *args: |
| The binding is Dart, and it works f7aea3b nandi yesterday | 219 | #!/usr/bin/env bash |
| 220 | set -euo pipefail |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 221 | cd "{{root}}" |
| 222 | exec "{{tc}}" exec -- bash -euo pipefail -c ' |
| 223 | cd nim |
| 224 | if [ -n "${1:-}" ]; then |
| 225 | exec nim c -r --hints:off --path:src "tests/$1.nim" |
| 226 | fi |
| 227 | for t in tests/t*.nim; do |
| 228 | echo "== $t" |
| 229 | nim c -r --hints:off --path:src "$t" |
| 230 | done' _ "$@" |
| 231 | |
| 232 | [private] |
| 233 | _flutter target action: |
| Nim under the existing UI, not instead of it 56551a8 nandi yesterday | 234 | #!/usr/bin/env bash |
| 235 | set -euo pipefail |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 236 | cd "{{root}}" |
| The last of the Clojure 284b59c nandi yesterday | 237 | just _nim-lib |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 238 | exec "{{tc}}" exec -- bash -euo pipefail -c ' |
| 239 | cd flutter |
| 240 | # Nim resolves OpenSSL through dynlib at run time; without the host |
| 241 | # library on the loader path `newContext` dies in a SIGSEGV that says |
| 242 | # nothing about SSL. |
| 243 | export LD_LIBRARY_PATH="${FRQ_OPENSSL_LIB:-}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" |
| The last of the Clojure 284b59c nandi yesterday | 244 | flutter pub get |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 245 | case "$1:$2" in |
| The last of the Clojure 284b59c nandi yesterday | 246 | desktop:build) exec flutter build linux --debug ;; |
| 247 | desktop:run) exec flutter run -d linux ;; |
| Lay every screen out in a test, and fix what that found 36bdfc5 nandi yesterday | 248 | # Widget tests, which lay every screen out for real. Headless: no |
| The last of the Clojure 284b59c nandi yesterday | 249 | # GL and no window, which is what makes them the check a Wayland |
| Lay every screen out in a test, and fix what that found 36bdfc5 nandi yesterday | 250 | # window cannot be. |
| The last of the Clojure 284b59c nandi yesterday | 251 | layout:test) exec flutter test test/nim_layout_test.dart ;; |
| 252 | *) echo "unknown target/action: $1 $2" >&2; exit 1 ;; |
| Six verbs, and the last of the nix 2e24e64 nandi yesterday | 253 | esac' _ "{{target}}" "{{action}}" |