nandi/frqpublic Fork 0
main
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.

container.toml · 140 lines · 6.6 KBTOML Blame HistoryRaw
Six verbs, and the last of the nix 2e24e64 nandi 15h ago1[container]
2name = "frq-dev"
3description = "the Flutter desktop build, incremental, from a pinned toolchain"
4# `debian:13-slim` and not `arch-nix`: there is no nix in this container any
5# more, and no flake left in the tree for it to enter. The build is
6# `just build desktop`, which gets Flutter, a JDK, the Clojure CLI and Nim out
7# of `tools/toolchain.sh` by pinned sha256 -- so what the image owes it is the
8# C and GTK half Flutter's Linux target links against, and nothing else.
9registry = "debian:13-slim"
10# A Sandbox, not a Function: runs on a real VM, and the command is
11# the sandbox's own process so it dies when the command does.
12runtime = "sandbox"
13
14[build]
15# The container lives inside the repo it builds, so the copy is rooted two
16# levels up and `.` is the whole tree.
17context = "../.."
18include = ["."]
19# The whole image build, and it is one apt line. What used to be here -- a nix
20# store to populate and a devShell to print into /etc/devshell.sh, so that a
21# shell attached to this container *was* the devShell -- is gone with the nix
22# it was for. The toolchain script now plays that part, and it lives on the
23# volume rather than in a layer.
24#
25# The first half is what the toolchain itself needs: git, because Flutter
26# shells out to it against its own SDK checkout and refuses to run without
27# one; unzip and xz-utils for the tarballs; ca-certificates so curl can verify
28# what it fetches; rsync for the sync below.
29#
30# The second half is Flutter's Linux target: CMake, Ninja and pkg-config drive
31# the build, GTK 3 is what the runner links, and a C toolchain compiles both
32# that and whatever `nim c` is asked for. libssl is Nim's: nim.cfg is
33# `-d:ssl`, and std/net resolves -lssl and -lcrypto through dynlib at run time.
34setup = [
35 "apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git rsync tar unzip xz-utils && rm -rf /var/lib/apt/lists/*",
36 "apt-get update && apt-get install -y --no-install-recommends build-essential clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libssl-dev && rm -rf /var/lib/apt/lists/*",
37]
38# The build state a local checkout carries: 395MB of a 441MB repo, uploaded on
39# every start and wanted by nothing out there. Flutter builds into a volume of
The last of the Clojure 284b59c nandi 8h ago40# its own, and the Nim cache is this machine's.
Six verbs, and the last of the nix 2e24e64 nandi 15h ago41ignore = [
42 "flutter/build", "flutter/.home", "flutter/.dart_tool",
43 # The ClojureDart compiler's output. Uploading a laptop's copy would make
44 # the rsync below overwrite the one the last container compiled, and every
45 # file whose content differed would look new to the compiler and to
46 # Flutter -- the incremental build undone by the thing meant to feed it.
47 # The toolchain, which is a gigabyte of Flutter SDK and lives on the
48 # volume out here.
49 ".toolchain",
50 ".cpcache", "result", "build", ".git",
51 # An editor's linter rewrites this while the upload is reading it, and
52 # Modal fails the whole run with "was modified during build process".
53 ".clj-kondo",
54]
55
56# One volume now, where there were two: the nix binary cache went with nix.
57# `devshell` is the working state of an incremental loop, shared by every
58# container that has one -- each gets its own directory under it, named for
The last of the Clojure 284b59c nandi 8h ago59# what it belongs to, so two containers never write the
Six verbs, and the last of the nix 2e24e64 nandi 15h ago60# same tree. Modal Volumes have no locking, so those directory names are the
61# only thing keeping them apart, and two runs of the *same* container must not
62# overlap.
63[volumes]
64devshell = "/devshell"
65
66[resources]
67cpu = 8
68memory = 16384
69timeout = 3600
70
71[run]
72workdir = "/app"
73# Source in, toolchain out of the volume, build in place. None of it
74# evaluates anything: the old command spent its first minutes entering a
75# devShell, printing an environment, caching that environment against
76# flake.lock and copying a nix closure back afterwards, all to arrive at a
77# PATH. A PATH is what `tools/toolchain.sh env` prints, out of a directory
78# already on the volume.
79#
80# An incremental build is the point, and `nix build` could not give one: a
81# derivation is all-or-nothing, so any edit is a fresh sandbox and a fresh
82# compile of everything. Here the toolchain supplies the compiler and
83# `flutter build` decides what is stale -- which is the whole reason
84# `just build desktop` exists as the working-tree loop.
85command = """
86set -e
87SHELL_DIR=/devshell/frq-desktop
88
89# Beside the working tree and NOT inside it: the rsync below runs with
90# --delete, so anything under $SHELL_DIR that is not in /app is removed on
91# every run. A cache kept in there would be deleted moments before it was
92# consulted.
93export FRQ_TOOLCHAIN=/devshell/frq-desktop.toolchain
94mkdir -p "$SHELL_DIR" "$FRQ_TOOLCHAIN"
95
96echo "sync: /app -> $SHELL_DIR"
97# rsync and not cp, with --checksum and not mtimes: Modal copies the source in
98# with fresh timestamps every run, so a plain copy looks entirely new to
99# Flutter and rebuilds the lot. --checksum compares content and leaves the
100# unchanged files' timestamps alone, which is the whole basis of the
101# incremental build.
102#
103# The excludes are the state we are here to keep -- overwriting them from /app
104# would defeat the volume.
105rsync -a --checksum --delete \
106 --exclude 'flutter/.home/' \
107 --exclude 'flutter/build/' \
108 --exclude 'flutter/.dart_tool/' \
109 --exclude '.toolchain/' \
110 --exclude '.git' \
111 /app/ "$SHELL_DIR/"
112
113cd "$SHELL_DIR"
114# What survived from the last run, by presence and not by size: `du` here
115# walked the pub cache, the toolchain and every object of the last build over
116# a network volume, for numbers nobody acts on.
The last of the Clojure 284b59c nandi 8h ago117for d in "$FRQ_TOOLCHAIN" build/nim flutter/build; do
Six verbs, and the last of the nix 2e24e64 nandi 15h ago118 [ -d "$d" ] && echo " carried over: $d"
119done
120
121# Run from the volume, where the state it reuses lives. `just` is not in this
122# image and is not worth an apt line for one call: the recipe is a wrapper
123# around the toolchain, and this is that wrapper.
The last of the Clojure 284b59c nandi 8h ago124# The Nim core first: the app dlopens it at startup, and a missing .so is a
125# blank window with a StateError behind it.
Six verbs, and the last of the nix 2e24e64 nandi 15h ago126tools/toolchain.sh exec -- bash -euo pipefail -c '
The last of the Clojure 284b59c nandi 8h ago127 cd nim && nim c --app:lib --mm:orc -d:release --hints:off --path:src \
128 --out:../build/nim/libfrqcore.so src/frq_core.nim
129 cd ../flutter
130 flutter pub get
Six verbs, and the last of the nix 2e24e64 nandi 15h ago131 flutter build linux --debug'
132
133echo "built:"
134du -sh flutter/build
135"""
136# Flutter keeps its settings under XDG_CONFIG_HOME and its own caches under
137# XDG_CACHE_HOME. Both point into the volume so a second run finds what the
138# first one decided. Set here rather than in the command so a shell into this
139# container gets them too.
140env = { XDG_CACHE_HOME = "/devshell/frq-desktop.toolchain/.cache", XDG_CONFIG_HOME = "/devshell/frq-desktop.toolchain/.config", FRQ_TOOLCHAIN = "/devshell/frq-desktop.toolchain" }