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 · 160 lines · 7.4 KBTOML Blame HistoryRaw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
[container]
name        = "frq-flutter-dev"
description = "the Flutter desktop build, incremental, in a nix devShell"
base        = "arch-nix"
# A Sandbox, not a Function: runs on a real VM, and the command is
# the sandbox's own process so it dies when the command does.
runtime     = "sandbox"

[build]
# The container lives inside the repo it builds, so the copy is rooted two
# levels up and `.` is the whole tree.
context = "../.."
include = ["."]
# `dev` is the shell you actually want. There is no default shell in this
# flake any more -- the one that used to be there belonged to the retired
# libcosmic frontend -- so a bare `nix develop` here fails rather than
# resolving to the wrong tree.
# The devShell, baked in rather than entered. `print-dev-env` writes the whole
# environment out as shell -- PATH, the compiler, every variable mkShell sets
# -- and realises its inputs on the way, so the closure becomes an image layer
# instead of a fetch every container pays for. Sourcing it from .bashrc means a
# shell attached to this container *is* the devShell: no `nix develop`, no
# clone of the flake's git inputs, no wait.
#
# `dev` stays for the case where the baked env is stale against a flake edit.
commands = [
  "nix print-dev-env /app#flutter-desktop --accept-flake-config --extra-substituters file:///nix-cache > /etc/devshell.sh",
  "echo '. /etc/devshell.sh' >> /root/.bashrc",
  "printf '#!/bin/sh\\nexec nix develop /app#flutter-desktop \"$@\"\\n' > /usr/local/bin/dev && chmod +x /usr/local/bin/dev",
]
# The build state a local checkout carries: 395MB of a 441MB repo, uploaded on
# every start and wanted by nothing out there. Flutter builds into a volume of
# its own, and the clojure caches are this machine's.
ignore  = [
    "flutter/build", "flutter/.home", "flutter/.dart_tool",
    "flutter/.clojuredart", "flutter/.cpcache",
    ".cpcache", "result", "build", ".git",
]

# Two volumes doing two different jobs. `nix-cache` is the binary cache every
# container here reads from and writes back to. `devshell` is the working
# state of a `nix develop` loop, and it is shared by every container that has
# one -- each gets its own directory under it, named for the devShell it
# belongs to, so two projects (or two shells of one project) never write the
# same tree. Modal Volumes have no locking, so the directories are the only
# thing keeping them apart, and two runs of the *same* devshell must not
# overlap.
[volumes]
nix-cache = "/nix-cache"
devshell  = "/devshell"

[resources]
cpu     = 8
memory  = 16384
timeout = 3600

[run]
workdir = "/app"
# Nix for the dependencies, the ordinary toolchain for the build. `nix build`
# cannot do this: a derivation is all-or-nothing, so any edit is a fresh
# sandbox and a fresh compile of everything. Here the devShell supplies the
# compiler and the libraries, and `flutter build` decides what is stale --
# which is the whole reason `just flutter-desktop` exists as the working-tree
# loop rather than as another `nix build`.
#
# rsync and not cp, with --checksum and not mtimes: Modal copies the source in
# with fresh timestamps on every run, so a plain copy would look entirely new
# to Flutter and rebuild the lot. --checksum compares content, leaves the
# unchanged files' timestamps alone, and lets the incremental build work.
#
# The excludes are the state that must NOT be overwritten from /app -- it is
# what we are here to keep. `just flutter-desktop` seeds those caches only
# when they are missing, so finding them warm is all it takes.
command = """
set -e
# This container's own directory on the shared devshell volume, named for the
# devShell it keeps the state of. Anything else using this volume picks its
# own name and the two never meet.
SHELL_DIR=/devshell/frq-flutter-desktop
mkdir -p "$SHELL_DIR" "$SHELL_DIR/.cache"

# A worktree's `.git` is a *file* naming a gitdir back on the machine that
# copied it in, and nix believes it and goes looking for a path that is not
# here. It has to go before any flake reference to /app.
rm -rf /app/.git

echo "sync: /app -> $SHELL_DIR"
# `nix shell --command` and not `nix profile install`: a profile install puts
# rsync in ~/.nix-profile/bin, which is not on the PATH of the shell already
# running, so the very next line said `rsync: command not found`.
#
# rsync and not cp, with --checksum and not mtimes: Modal copies the source in
# with fresh timestamps every run, so a plain copy looks entirely new to
# Flutter and rebuilds the lot. --checksum compares content and leaves the
# unchanged files' timestamps alone, which is the whole basis of the
# incremental build.
#
# The excludes are the state we are here to keep -- overwriting them from /app
# would defeat the volume. `just flutter-desktop` seeds those caches only when
# they are missing, so finding them warm is all it takes.
nix shell nixpkgs#rsync --accept-flake-config \
    --extra-substituters file:///nix-cache --command \
  rsync -a --checksum --delete \
    --exclude 'flutter/.home/' \
    --exclude 'flutter/.clojuredart/' \
    --exclude 'flutter/build/' \
    --exclude 'flutter/.dart_tool/' \
    --exclude '.git' \
    /app/ "$SHELL_DIR/"

cd "$SHELL_DIR"
echo "state carried over:"
du -sh flutter/.home flutter/.clojuredart flutter/build 2>/dev/null \
  || echo "  (none yet -- first run)"

# Nix for the dependencies, the ordinary toolchain for the build. `nix build`
# cannot do this: a derivation is all-or-nothing, so any edit is a fresh
# sandbox and a fresh compile of everything. Here the devShell supplies the
# compiler and the libraries and `flutter build` decides what is stale.
# Evaluated from /app and built in the volume. Both halves matter: /app is the
# pristine copy, so nix stores a source tree of the repo rather than one
# carrying gigabytes of flutter/build, while the recipe still runs where the
# state it reuses lives -- `just -f` is what puts it there, since the recipe
# cds to its own justfile's directory.
nix develop /app#flutter-desktop --accept-flake-config \
    --extra-substituters file:///nix-cache \
    --max-jobs auto --command just -f "$SHELL_DIR/justfile" flutter-desktop

echo "built:"
du -sh flutter/build

# The devShell's closure is gigabytes of Flutter, Dart, clang and GTK, and the
# store it landed in belongs to the image rather than to a volume -- so
# without this every run re-fetches it from upstream. Written back, the next
# run substitutes it from file:///nix-cache instead.
if [ -f /nix-cache/nix-cache-info ]; then
    echo "cache: writing the devShell closure back"
    nix copy --no-check-sigs --all --to file:///nix-cache
fi
"""
# Nix's own cache, on the volume rather than in the container. Without it
# every Sandbox starts empty and `nix develop` re-clones the flake's git
# inputs -- nixgl and its transitives --
# because flake.lock pins which revision to fetch, not whether it is already
# on disk. Set here rather than in the command so an interactive shell into
# this container gets it too.
env     = { XDG_CACHE_HOME = "/devshell/frq-flutter-desktop/.cache" }

[nix]
# Every nix command in the container reads the mounted cache, including one
# typed by hand in a shell. Passing --extra-substituters per command only ever
# covered the scripts.
substituters = ["file:///nix-cache"]
# No devShell warming at image build time: this enters `nix develop` at run
# time, on the VM, where the cache answers for its closure. The ptyshim that
# warming would need under gVisor is deprecated and does not come back.
flake = false
shim  = false

# [experimental] overrides the sandbox default of vm_runtime = true.