Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
251 commits
Select commit Hold shift + click to select a range
f2c88e6
fix: add filesystem stub for CI closure builds
mrosseel Feb 4, 2026
0257842
fix: add pifinder.devMode option declaration
mrosseel Feb 4, 2026
a1ba877
fix: wrap services.nix config in explicit config block
mrosseel Feb 4, 2026
454726f
fix: add package hashes to python-env.nix
mrosseel Feb 4, 2026
10d0c33
feat: support self-hosted ARM64 runner for faster builds
mrosseel Feb 4, 2026
5b17091
fix: add device tree filter and fix PWM overlay syntax
mrosseel Feb 4, 2026
7292ac6
fix: add write permissions and self-hosted runner to release workflow
mrosseel Feb 5, 2026
9fcc29e
fix: use ubuntu-latest for all workflows, simplify QEMU setup
mrosseel Feb 5, 2026
7430061
fix: lint and type errors in sys_utils_nixos.py
mrosseel Feb 5, 2026
6000482
fix: swap noqa/type-ignore comment order for ruff
mrosseel Feb 5, 2026
001751d
fix: name SD image with version tag
mrosseel Feb 5, 2026
9c361a6
fix: add sys_utils_base.py to tracked files
mrosseel Feb 5, 2026
a2c0f9a
fix: NixOS netboot camera, sys_utils, and solver issues
mrosseel Feb 6, 2026
34dca88
feat: runtime camera selection via /boot/camera.txt for SD cards
mrosseel Feb 6, 2026
d12ca7a
feat(nixos): refactor sys_utils and add netboot deploy script
mrosseel Feb 7, 2026
2aa6e15
fix: misc UI, DB, and CI improvements
mrosseel Feb 7, 2026
d606d40
fix(netboot): improve NFS compatibility for Nix store
mrosseel Feb 9, 2026
63e727d
fix(deploy): add SSH keepalives and improve rsync transfer
mrosseel Feb 9, 2026
a919541
fix: move comet_file to writable data_dir
mrosseel Feb 9, 2026
dcb241a
fix(netboot): improve initrd network and add libcamera IPA path
mrosseel Feb 9, 2026
ddd3f97
fix: add missing PWM udev rule
mrosseel Feb 9, 2026
329d7c2
feat: add early boot LED indicator service
mrosseel Feb 9, 2026
04576e1
feat: add C boot splash with Knight Rider animation
mrosseel Feb 9, 2026
b3bd709
fix: make Knight Rider scanner brighter red
mrosseel Feb 9, 2026
91f926e
fix: stop boot-splash via ExecStartPre instead of conflicts
mrosseel Feb 9, 2026
9a70253
fix: minimize bootstrap closure size
mrosseel Feb 9, 2026
e78c47e
fix: strip more bloat from bootstrap
mrosseel Feb 9, 2026
371655a
fix: disable NetworkManager VPN plugins
mrosseel Feb 9, 2026
530717c
fix: swap type-ignore before noqa for mypy parsing
mrosseel Feb 9, 2026
75fdff8
fix: strip more bloat - disable xdg, fuse, perl deps
mrosseel Feb 9, 2026
0c4ef2e
fix: disable lesspipe (pulls perl 112MB)
mrosseel Feb 9, 2026
617d202
fix: replace NetworkManager with wpa_supplicant
mrosseel Feb 9, 2026
baf9d1b
fix: override NetworkManager to exclude openconnect
mrosseel Feb 9, 2026
c5eefd6
fix: remove invalid NetworkManager overlay
mrosseel Feb 9, 2026
b2c18c5
fix: use bare type: ignore for gi.repository import
mrosseel Feb 9, 2026
448e256
fix: override openconnect with dummy to remove GTK dep
mrosseel Feb 9, 2026
7c82e9a
fix: override modemmanager to remove 284MB cellular bloat
mrosseel Feb 9, 2026
4f7f816
revert: remove broken modemmanager override
mrosseel Feb 9, 2026
64669d2
feat: switch from NetworkManager to iwd + systemd-networkd
mrosseel Feb 9, 2026
c3eb187
fix: disable more documentation modules
mrosseel Feb 9, 2026
14f13f5
fix: mkForce systemPackages to exclude w3m from base profile
mrosseel Feb 9, 2026
b3ef9a6
fix: disable containers to remove perl (112MB)
mrosseel Feb 9, 2026
957b55e
fix: PWM overlay pinctrl and boot splash improvements
mrosseel Feb 9, 2026
f00b041
ci: use Pi5 native runner with ubuntu-latest fallback
mrosseel Feb 9, 2026
78c1eb9
fix(ci): use correct flake output names
mrosseel Feb 9, 2026
721e59b
fix: use /etc/static for symlinks in deploy script
mrosseel Feb 9, 2026
258a367
fix: use Type=simple for pifinder service
mrosseel Feb 9, 2026
bf4d561
fix: remove pam.d before symlink in deploy script
mrosseel Feb 9, 2026
59a146f
fix: point bootstrap flake to mrosseel/PiFinder/nixos
mrosseel Feb 9, 2026
791d99a
feat: centralize PiFinder repo URL in pifinder.repoUrl option
mrosseel Feb 9, 2026
c971bd2
ci: add bootstrap tarball build workflow
mrosseel Feb 9, 2026
f236d32
ci: trigger bootstrap build on push to nixos branch
mrosseel Feb 9, 2026
3d43eb3
fix(ci): find image file not directory
mrosseel Feb 9, 2026
86a9273
fix(ci): use sudo for tar and exclude lost+found
mrosseel Feb 9, 2026
34e412b
fix(ci): clean up leftover files from previous runs
mrosseel Feb 9, 2026
5e0ed42
feat: manifest-based software update UI with channels
mrosseel Feb 10, 2026
21c23c2
chore: add nix dev shell for local testing
mrosseel Feb 10, 2026
7334f30
feat: camera switching via NixOS specialisations
mrosseel Feb 10, 2026
7204b16
fix: use absolute path for sudo in sys_utils
mrosseel Feb 10, 2026
e8c6f2e
fix: use absolute paths for systemctl/journalctl in sys_utils
mrosseel Feb 10, 2026
6b69b89
feat: upgrade nixpkgs 24.11 → 25.11 (Python 3.13)
mrosseel Feb 10, 2026
6a81855
fix: u-boot boot chain, RPi.GPIO aarch64, I2C, sudo, /boot mount
mrosseel Feb 11, 2026
2007bda
perf: boot time optimizations and u-boot PCI/USB stripping
mrosseel Feb 11, 2026
4e67699
fix: bootstrap migration progress and nix fetch issues
mrosseel Feb 11, 2026
be3a4cc
feat: unified nix dev shell, pygame keyboard, software update UI
mrosseel Feb 11, 2026
7b78f40
fix: camera test mode, PAM auth, service PATH, AP networking
mrosseel Feb 11, 2026
1ac9d9b
feat: include catalog images in SD card image
mrosseel Feb 12, 2026
6e80659
feat: bootstrap migration tarball and pifinder-src optimization
mrosseel Feb 12, 2026
f804d57
refactor: remove bootstrapMode, use full system for migration tarball
mrosseel Feb 12, 2026
fdb9300
fix: keep welcome.png in pifinder-src (needed at runtime)
mrosseel Feb 12, 2026
57cf44c
feat: add nix-path-registration first-boot service
mrosseel Feb 12, 2026
3cd23c7
feat: store-path-based NixOS upgrade
mrosseel Feb 13, 2026
a883cd7
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
231b3ff
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
30194a0
fix: use nix build instead of nix copy --from in upgrade service
mrosseel Feb 13, 2026
c27ed16
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
5e642ce
style: apply ruff formatting to Python codebase
mrosseel Feb 13, 2026
5e75817
refactor: replace nox/pip with nix develop for CI and dev tooling
mrosseel Feb 13, 2026
676be12
fix: add watchdog fallback for CI when self-hosted runner unavailable
mrosseel Feb 13, 2026
204be3f
fix: add SSH port 22 to firewall allowedTCPPorts
mrosseel Feb 13, 2026
e817105
fix: open firewall for Samba, remove redundant SSH port
mrosseel Feb 13, 2026
c1d8e8c
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
bf0054a
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
c76fdcd
fix: clean stale avahi PID file before restart
mrosseel Feb 13, 2026
da85b86
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
8b60e3c
fix: disable Determinate Nix to avoid FlakeHub registration
mrosseel Feb 13, 2026
98cdafe
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
0359235
fix: harden avahi hostname handling and use display constants
mrosseel Feb 13, 2026
bb2b72e
fix: run switch-to-configuration in detached scope during upgrade
mrosseel Feb 13, 2026
1cffae1
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
ecf0c3d
fix: use restartIfChanged/stopIfChanged for upgrade service
mrosseel Feb 13, 2026
0fde64e
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
021667d
ci: add config key removal warning for PRs
mrosseel Feb 13, 2026
c183328
refactor: replace version.txt with pifinder-build.json
mrosseel Feb 13, 2026
c55bf84
refactor: remove unused update_needed function and tests
mrosseel Feb 13, 2026
3189497
ci: add concurrency group to prevent queued run pileup
mrosseel Feb 13, 2026
cba851a
feat: persist unstable channel unlock across restarts
mrosseel Feb 13, 2026
3bace42
chore: stamp build [skip ci]
github-actions[bot] Feb 13, 2026
6a64841
feat: add upgrade progress UI with download tracking
mrosseel Feb 18, 2026
40d8bc8
chore: stamp build [skip ci]
github-actions[bot] Feb 18, 2026
922c1b6
fix: use loose rpfilter for multi-interface WiFi+ethernet support
mrosseel Feb 19, 2026
2d0ccdb
chore: stamp build [skip ci]
github-actions[bot] Feb 19, 2026
9c366c4
docs: add critical Pi 4 build limitations to CLAUDE.md
mrosseel Feb 19, 2026
49a2fc8
feat: add dev mode toggle and screen off burn-in protection
mrosseel Feb 19, 2026
d79c103
feat: add test mode toggle with visual feedback
mrosseel Feb 20, 2026
c1dc370
chore: stamp build [skip ci]
github-actions[bot] Feb 20, 2026
a6a8ef4
revert: remove test mode and dev mode features (moved to screensaver …
mrosseel Feb 20, 2026
2952da1
chore: stamp build [skip ci]
github-actions[bot] Feb 20, 2026
4133bee
feat: auto-generate pifinder-build.json from git rev at nix build time
mrosseel Feb 21, 2026
fcbe630
chore: stamp build [skip ci]
github-actions[bot] Feb 21, 2026
1959bae
feat: replace bootstrap tarball with DD-able migration image
mrosseel Feb 23, 2026
123e4f6
chore: stamp build [skip ci]
github-actions[bot] Feb 23, 2026
463b21a
fix: revert to tarball approach for migration (SD image too large for…
mrosseel Feb 23, 2026
3e78e8e
chore: stamp build [skip ci]
github-actions[bot] Feb 23, 2026
3701785
fix: clean up stale mounts before migration tarball build
mrosseel Feb 24, 2026
99ba14c
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
e68c241
fix: clean up stale tarballs from previous workflow runs
mrosseel Feb 24, 2026
5d48cff
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
0a7e7b5
feat: auto-update migration branch SHA256 after tarball build
mrosseel Feb 24, 2026
24a57a1
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
370762f
feat: add minimal migration profile with first-boot deferred download
mrosseel Feb 24, 2026
b85f7f1
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
ed8faa7
feat: merge migration tarball build into main CI workflow
mrosseel Feb 24, 2026
7d2dbca
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
09d9465
fix: shrink migration closure by ~200MB
mrosseel Feb 24, 2026
c1444ca
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
e175730
fix: remove nixpkgs source, python, perl from migration closure
mrosseel Feb 24, 2026
d7a0cdf
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
df6143e
fix: log uncompressed size in migration tarball build
mrosseel Feb 24, 2026
7dbdc53
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
68ec945
feat: build migration tarball directly from nix store closure
mrosseel Feb 24, 2026
e4b639f
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
da65780
fix: use sudo for tarball staging cleanup
mrosseel Feb 24, 2026
8b187a7
chore: stamp build [skip ci]
github-actions[bot] Feb 24, 2026
5087f01
feat: merge upstream/main into nixos
mrosseel Mar 9, 2026
a229215
Merge branch 'nixos' of github.com:mrosseel/PiFinder into nixos
mrosseel Mar 9, 2026
3080e36
chore: stamp build [skip ci]
github-actions[bot] Mar 9, 2026
1ca781d
fix: remove auto-update SHA256 step from CI
mrosseel Mar 10, 2026
f5c7388
chore: stamp build [skip ci]
github-actions[bot] Mar 10, 2026
c778025
fix: first-boot service waits for internet and retries on failure
mrosseel Mar 10, 2026
e66b4f8
chore: stamp build [skip ci]
github-actions[bot] Mar 10, 2026
b2178e6
feat: show OLED scanner animation during first-boot download
mrosseel Mar 10, 2026
90a7687
chore: stamp build [skip ci]
github-actions[bot] Mar 10, 2026
4788e9e
fix: guard against None solution in screen_update crash loop
mrosseel Mar 11, 2026
1093a10
chore: stamp build [skip ci]
github-actions[bot] Mar 11, 2026
4792293
feat: merge upstream/main into nixos
mrosseel May 3, 2026
70bae40
Merge upstream/main into nixos
mrosseel May 25, 2026
869975d
chore: stamp build [skip ci]
github-actions[bot] May 25, 2026
d705057
feat(nixos): prep for 3.0 — release docs, dev-env parity, MIN bump
mrosseel May 26, 2026
0e1366a
fix(nixos): codex review — UART node, gpsd parity, JSON upgrade progress
mrosseel May 27, 2026
47bca8c
chore: stamp build [skip ci]
github-actions[bot] May 27, 2026
1035ab2
ci(nixos): bump migration tarball default version to 3.0.0
mrosseel May 27, 2026
9a5ddfa
chore: stamp build [skip ci]
github-actions[bot] May 27, 2026
ea0b58d
ci(nixos): swap Magic Nix Cache for cachix-action in lint.yml (stop-gap)
mrosseel May 27, 2026
376637f
chore: stamp build [skip ci]
github-actions[bot] May 27, 2026
e2c57cd
revert: restore Magic Nix Cache in lint.yml (cachix-action swap was w…
mrosseel May 27, 2026
33a6c80
chore: stamp build [skip ci]
github-actions[bot] May 27, 2026
d316393
chore: stamp build [skip ci]
github-actions[bot] May 27, 2026
769c908
refactor(nixos): make pifinder-build.json the single source of truth
mrosseel May 27, 2026
400fb91
chore: stamp build [skip ci]
github-actions[bot] May 28, 2026
d021534
docs(adr): 0004 — self-hosted Attic for NixOS binary distribution
mrosseel May 28, 2026
82f26b0
feat(nixos): wire cache.pifinder.eu — Attic standalone, cachix removed
mrosseel May 28, 2026
43c3d2a
chore: stamp build [skip ci]
github-actions[bot] May 28, 2026
9c32f22
ci(nixos): gate stamp-build on push events (lets brickbots PR runs su…
mrosseel May 28, 2026
ba8283e
Merge upstream/main into nixos
mrosseel Jun 17, 2026
8678421
fix(comets): make vectorized propagation work on skyfield >= 1.46
mrosseel Jun 17, 2026
c069005
fix(catalogs): restore upstream's catalog module (T9 search + disk ca…
mrosseel Jun 17, 2026
f8c82eb
test(software): update version literals for MIN_NIXOS_VERSION 3.0.0
mrosseel Jun 17, 2026
5084410
fix(logging): persist active log-config selection in PiFinder_data
mrosseel Jun 18, 2026
298275e
fix(solver): load tetra3 DB by name instead of an explicit path
mrosseel Jun 18, 2026
7eef66a
ci(nixos): publish releases to retained Attic cache, drop Cachix
mrosseel Jun 18, 2026
dea4e56
merge: bring nixos up to date with upstream/main
mrosseel Jun 18, 2026
3a08c27
chore(nixos): stop tracking .direnv build cache
mrosseel Jun 18, 2026
606664b
feat(nixos): manage Python deps with uv2nix instead of hand-written d…
mrosseel Jun 18, 2026
d18bf30
ci(nixos): cache lint/test/type-check via Attic, drop dead magic-nix-…
mrosseel Jun 18, 2026
3ae56cd
fix(nixos): reliable WiFi AP fallback, clearer offline UX, surface sy…
mrosseel Jun 18, 2026
8ca2139
ci(nixos): run build fallback on native ubuntu-24.04-arm instead of QEMU
mrosseel Jun 19, 2026
b2fc711
fix(nixos): provision uv2nix build backends for dbus-python, pygobjec…
mrosseel Jun 19, 2026
ab0ead7
fix(nixos): make the uv2nix env build on aarch64 (build backends, hea…
mrosseel Jun 19, 2026
0985ec0
fix(nixos): provide setuptools backend for timezonefinder (sdist on a…
mrosseel Jun 19, 2026
cf1eef7
ci(nixos): tokenless Attic pull for fork PRs + always() on stamp-build
mrosseel Jun 19, 2026
f22d398
chore: stamp build [skip ci]
github-actions[bot] Jun 19, 2026
9ed7d3a
fix(network): make D-Bus wifi add/delete/list robust
mrosseel Jun 19, 2026
30acc36
fix(nixos): repair non-root /nix/store ownership before NetworkManager
mrosseel Jun 19, 2026
3750286
chore: stamp build [skip ci]
github-actions[bot] Jun 19, 2026
ba2496a
fix(nixos): patch RPi.GPIO board detection for mainline-DT Pi 4
mrosseel Jun 19, 2026
fade0f5
chore: stamp build [skip ci]
github-actions[bot] Jun 19, 2026
f87bba1
fix(nixos): bind-remount the store in the ownership repair (don't tak…
mrosseel Jun 19, 2026
dbbd598
chore: stamp build [skip ci]
github-actions[bot] Jun 19, 2026
1668edc
fix(network): report the live wifi mode instead of the init-time cache
mrosseel Jun 19, 2026
b57aa23
fix(nixos): surface nix errors from pifinder-upgrade instead of swall…
mrosseel Jun 19, 2026
115c19a
chore: stamp build [skip ci]
github-actions[bot] Jun 19, 2026
b6d3582
fix(nixos): drop the invalid pifinder-release pubkey placeholder
mrosseel Jun 19, 2026
be112f7
feat(nixos): set root password declaratively via hashedPassword
mrosseel Jun 19, 2026
ea86c0c
fix(nixos): build the migration tarball with root-owned paths
mrosseel Jun 19, 2026
7158f42
fix(nixos): make picamera2 previews optional for headless camera
mrosseel Jun 19, 2026
7b51f38
chore: stamp build [skip ci]
github-actions[bot] Jun 19, 2026
0d2e4e4
docs(nixos): note pifinder user must stay initialPassword (not hashed)
mrosseel Jun 20, 2026
a383881
chore: stamp build [skip ci]
github-actions[bot] Jun 20, 2026
58daae3
fix(nixos): wait for clock sync before first-boot download; real OLED…
mrosseel Jun 20, 2026
67ab181
chore: stamp build [skip ci]
github-actions[bot] Jun 21, 2026
df21998
merge: bring nixos up to date with upstream/main
mrosseel Jun 23, 2026
3e18c91
chore: stamp build [skip ci]
github-actions[bot] Jun 23, 2026
9bfe25b
test(software): _fetch_github_releases propagates network errors
mrosseel Jun 23, 2026
1a759d1
chore: stamp build [skip ci]
github-actions[bot] Jun 23, 2026
4708a39
fix(nixos): pin explicit NTP servers so a dead DHCP NTP server can't …
mrosseel Jun 23, 2026
0d299f4
chore: stamp build [skip ci]
github-actions[bot] Jun 23, 2026
5a7640a
test(nixos): port web integration tests to Nix
mrosseel Jun 23, 2026
0bfd6ae
chore: stamp build [skip ci]
github-actions[bot] Jun 23, 2026
851c6f1
docs(nixos): add NixOS deploy/update context (channels, rollback, bui…
mrosseel Jun 24, 2026
f263b74
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
fc18bde
fix(ci): make Lint & Test workflow green again
mrosseel Jun 24, 2026
d048d34
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
599d08d
feat(nixos): size-based download progress + availability check + prom…
mrosseel Jun 24, 2026
d26db31
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
b7cb42e
fix(ci): add user nix profile to PATH so attic resolves on the migrat…
mrosseel Jun 24, 2026
2a4f376
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
bb824aa
fix(network): AP no longer self-starts and beats client WiFi at boot;…
mrosseel Jun 24, 2026
4899492
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
ba83bc2
feat(status): show the active uplink (Ethernet when wired) and live W…
mrosseel Jun 24, 2026
4aa5978
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
fb45b22
fix(nixos): upgrade/first-boot size query is advisory, never aborts
mrosseel Jun 24, 2026
0999ea7
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
32d5531
docs: convert contributors guide to the Nix workflow (deps, channels,…
mrosseel Jun 24, 2026
0b7d399
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
26b1bb6
fix(nixos): fast delta-only download-size query for the progress bar
mrosseel Jun 24, 2026
46e4c25
fix(nixos): make software updates fail closed
mrosseel Jun 24, 2026
3728d85
fix(ui): keep unstable trunk and testable PRs visible
mrosseel Jun 24, 2026
9d6a5d2
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
4a37f0a
fix(ui): read testable PRs from upstream
mrosseel Jun 24, 2026
07db713
chore: stamp build [skip ci]
github-actions[bot] Jun 24, 2026
210f2c0
feat(nixos): drive update channels from manifest
mrosseel Jun 24, 2026
d1657e6
ci(nixos): keep manifest branch single-file and concurrency-safe
mrosseel Jun 24, 2026
9b7c725
ci(nixos): simplify publish_manifest.sh — drop one-time source-tree c…
mrosseel Jun 25, 2026
5aa3b27
feat(nixos): rotate Attic cache keys after S3 chunk-store cutover
mrosseel Jun 25, 2026
9fcfeb5
docs(nixos): add handover notes for manifest-driven update channels
mrosseel Jun 24, 2026
a4f8db2
ci(nixos): stop building on mrosseel pushes — PRs/dispatch only
mrosseel Jun 25, 2026
0082044
fix(ci,software): manifest from brickbots; build-native verify-only o…
mrosseel Jun 25, 2026
dfcd5b6
ci: build+publish on brickbots pushes only (scoped push trigger)
mrosseel Jun 25, 2026
b1cf8bc
ci(nixos): align CI workflows with brickbots PR #493 (no diff)
mrosseel Jun 25, 2026
cd6b7d7
ci(nixos): rotate Attic dev cache key in nixos-pr-build.yml (sync wit…
mrosseel Jun 25, 2026
10eb481
revert(nixos): restore 8UU dev cache key — undo the accidental S3-cut…
mrosseel Jun 25, 2026
e289db6
refactor(nixos): rename migration.nix → device.nix
mrosseel Jun 25, 2026
7e0bbb0
feat(nixos): live within-path download progress + key-proof + avahi/h…
mrosseel Jun 25, 2026
73d0cc6
fix(catalog): rebuild stale object cache so the details screen stops …
mrosseel Jun 25, 2026
f10edd8
fix(nixos): boot the selected camera — repoint extlinux DEFAULT + reboot
mrosseel Jun 26, 2026
f886940
docs(adr): correct Attic chunking claim in ADR 0001
mrosseel Jun 26, 2026
ef6b735
perf(nixos): split tetra3 + fonts out of pifinder-src
mrosseel Jun 26, 2026
652ef13
feat(nixos): rollback to previous generation via Software screen
mrosseel Jun 26, 2026
afc59b1
perf: defer timezonefinder and pandas imports to cut startup time
mrosseel Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
66 changes: 66 additions & 0 deletions .github/scripts/publish_manifest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
# Update update-manifest.json on the metadata-only `nixos-manifest` branch.
#
# The branch holds only that one JSON file; it carries no source tree. The job
# here is just: read the current manifest, let the updater rewrite its entry,
# and push. Concurrency-safe: a git ref update is compare-and-swap, so if a
# concurrent writer lands first our push is rejected, and we re-fetch the new
# tip, re-apply this run's entry onto it, and retry.
#
# Usage:
# publish_manifest.sh "<commit message>" <updater argv...>
# The updater argv contains the literal token @MANIFEST@, replaced with the
# manifest path on each attempt. It must be idempotent (replaces its own entry).
set -euo pipefail

BRANCH="nixos-manifest"
COMMIT_MSG="$1"
shift

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

WORKTREE="$(mktemp -d)"
trap 'git worktree remove --force "$WORKTREE" >/dev/null 2>&1 || true' EXIT
git worktree add --detach "$WORKTREE" >/dev/null
MANIFEST="$WORKTREE/update-manifest.json"

for attempt in 1 2 3 4 5; do
git fetch origin "$BRANCH" >/dev/null 2>&1 || true

if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then
# reset --hard so a retry after a rejected push starts from the true tip,
# not the stale entry from the previous attempt (which would otherwise
# silently drop the concurrent writer's change).
git -C "$WORKTREE" checkout -q -B "$BRANCH" "refs/remotes/origin/$BRANCH"
git -C "$WORKTREE" reset -q --hard "refs/remotes/origin/$BRANCH"
else
# Branch does not exist yet: start it empty.
git -C "$WORKTREE" checkout -q --orphan "$BRANCH"
git -C "$WORKTREE" rm -rfq --cached . >/dev/null 2>&1 || true
fi

cmd=()
for arg in "$@"; do
cmd+=( "${arg/@MANIFEST@/$MANIFEST}" )
done
"${cmd[@]}"

git -C "$WORKTREE" add update-manifest.json
if git -C "$WORKTREE" diff --staged --quiet; then
echo "Manifest unchanged"
exit 0
fi

git -C "$WORKTREE" commit -q -m "$COMMIT_MSG"
if git -C "$WORKTREE" push origin "HEAD:$BRANCH" 2>/dev/null; then
echo "Manifest published (attempt $attempt)"
exit 0
fi

echo "Push rejected by a concurrent update; retrying ($attempt/5)"
sleep $((attempt * 2))
done

echo "Failed to publish manifest after 5 attempts" >&2
exit 1
193 changes: 193 additions & 0 deletions .github/scripts/update_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
#!/usr/bin/env python3
"""Update the generated PiFinder software update manifest."""

import argparse
import json
import re
from datetime import datetime, timezone
from pathlib import Path


STORE_PATH_RE = re.compile(r"^/nix/store/[a-z0-9]+-[A-Za-z0-9._+=?,-]+$")
EMPTY_MANIFEST = {
"schema": 1,
"generated_at": None,
"channels": {
"stable": [],
"beta": [],
"unstable": [],
},
}


def now_iso() -> str:
return datetime.now(timezone.utc).replace(microsecond=0).isoformat()


def load_manifest(path: Path) -> dict:
if not path.exists():
return json.loads(json.dumps(EMPTY_MANIFEST))
with path.open() as f:
data = json.load(f)
if data.get("schema") != 1:
raise SystemExit(f"unsupported manifest schema in {path}")
channels = data.setdefault("channels", {})
for name in ("stable", "beta", "unstable"):
channels.setdefault(name, [])
return data


def save_manifest(path: Path, manifest: dict) -> None:
manifest["generated_at"] = now_iso()
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w") as f:
json.dump(manifest, f, indent=2, sort_keys=True)
f.write("\n")


def valid_store_path(value: str | None) -> bool:
return isinstance(value, str) and STORE_PATH_RE.fullmatch(value) is not None


def set_available(entry: dict) -> dict:
if valid_store_path(entry.get("store_path")):
entry["available"] = True
entry.pop("reason", None)
else:
entry["store_path"] = None
entry["available"] = False
entry.setdefault("reason", "no build")
return entry


def replace_entry(entries: list[dict], predicate, entry: dict) -> list[dict]:
return [item for item in entries if not predicate(item)] + [entry]


def sort_unstable(entries: list[dict]) -> list[dict]:
def key(item: dict) -> tuple[int, int, str]:
if item.get("kind") == "trunk":
return (0, 0, item.get("source_ref", ""))
if item.get("kind") == "pr":
return (1, -int(item.get("number") or 0), item.get("label", ""))
return (2, 0, item.get("label", ""))

return sorted(entries, key=key)


def update_build(args: argparse.Namespace) -> None:
manifest = load_manifest(args.manifest)
channels = manifest["channels"]
store_path = args.store_path or None
short_sha = (args.head_sha or args.sha)[:7]

if args.pr_number:
number = int(args.pr_number)
entry = {
"kind": "pr",
"number": number,
"label": f"PR#{number}-{short_sha}",
"title": args.pr_title or f"PR #{number}",
"notes": args.pr_body or None,
"source_repo": args.head_repo,
"source_ref": args.head_ref,
"source_sha": args.head_sha,
"version": args.version or f"PR#{number}-{short_sha}",
"store_path": store_path,
}
set_available(entry)
channels["unstable"] = replace_entry(
channels["unstable"],
lambda item: item.get("kind") == "pr"
and int(item.get("number") or 0) == number,
entry,
)
else:
entry = {
"kind": "trunk",
"label": args.version or f"{args.ref_name}-{short_sha}",
"title": f"{args.ref_name} branch",
"notes": None,
"source_repo": args.repository,
"source_ref": args.ref_name,
"source_sha": args.sha,
"version": args.version or f"{args.ref_name}-{short_sha}",
"store_path": store_path,
}
set_available(entry)
channels["unstable"] = replace_entry(
channels["unstable"],
lambda item: item.get("kind") == "trunk"
and item.get("source_repo") == args.repository
and item.get("source_ref") == args.ref_name,
entry,
)

channels["unstable"] = sort_unstable(channels["unstable"])
save_manifest(args.manifest, manifest)


def update_release(args: argparse.Namespace) -> None:
manifest = load_manifest(args.manifest)
channel = "beta" if args.release_type == "beta" else "stable"
entry = {
"kind": "release",
"label": args.tag,
"title": args.title or f"PiFinder {args.tag}",
"notes": args.notes or None,
"source_repo": args.repository,
"source_ref": args.tag,
"source_sha": args.sha,
"version": args.version,
"store_path": args.store_path or None,
}
set_available(entry)
manifest["channels"][channel] = replace_entry(
manifest["channels"][channel],
lambda item: item.get("kind") == "release" and item.get("label") == args.tag,
entry,
)
save_manifest(args.manifest, manifest)


def parser() -> argparse.ArgumentParser:
root = argparse.ArgumentParser()
sub = root.add_subparsers(dest="command", required=True)

build = sub.add_parser("build")
build.add_argument("--manifest", type=Path, required=True)
build.add_argument("--repository", required=True)
build.add_argument("--ref-name", required=True)
build.add_argument("--sha", required=True)
build.add_argument("--store-path", required=True)
build.add_argument("--version", required=True)
build.add_argument("--pr-number")
build.add_argument("--pr-title")
build.add_argument("--pr-body")
build.add_argument("--head-repo")
build.add_argument("--head-ref")
build.add_argument("--head-sha")
build.set_defaults(func=update_build)

release = sub.add_parser("release")
release.add_argument("--manifest", type=Path, required=True)
release.add_argument("--repository", required=True)
release.add_argument("--sha", required=True)
release.add_argument("--tag", required=True)
release.add_argument("--version", required=True)
release.add_argument("--release-type", choices=("stable", "beta"), required=True)
release.add_argument("--store-path", required=True)
release.add_argument("--title")
release.add_argument("--notes")
release.set_defaults(func=update_release)

return root


def main() -> None:
args = parser().parse_args()
args.func(args)


if __name__ == "__main__":
main()
Loading
Loading