Files
DarkRoom/packaging/flatpak/paris.tourolle.darkroom.yml
T
dtourolle 4f31123b0c Let the user choose which SCRFD finds their faces
faces.md §12.3 measured what the cheapest detector costs: the small
faces in every group shot, and a dog embedded a dozen times. Which
trade is right depends on the machine doing the sweep — a desktop left
overnight and a tablet on a battery want different answers — so the
detector is now a per-device setting, Fast / Balanced / Thorough on
the settings page beside the indexing button, persisted with the rest
of the settings file.

A detector is half of a model id. Every face, marker, shard and
calibration is keyed on faces.model_id precisely so that a model change
is a new id and a re-index rather than a silent change under existing
data, and a detector change is a model change: it decides which faces
exist and where the landmarks that align them land. So each choice
names its own pipeline. 500M keeps the bare "w600k_mbf" every existing
library was written under, so an upgrade disturbs nothing; the others
are qualified. Choosing one restarts coverage from zero under the new
id, the sweep re-detects, confirmed names carry across by box overlap,
and the sync shards are keyed by the same id so a peer on another
setting neither adopts nor pollutes them. The library controller
carries the id into the sync the same way it carries the cache budget,
because the sync starts from places that have no settings in reach.

All three shape-fixed exports ship — APK, Arch, Flatpak — since a
tablet has no other way to obtain the one it was not installed with;
the APK grows by twenty megabytes for the choice.
2026-09-11 22:12:53 +02:00

202 lines
9.9 KiB
YAML

# Flatpak manifest — FR-PLAT-LIN-3 (sandboxed distribution), NFR-COMPAT-2.
#
# YAML rather than JSON because this file has more to explain than to declare,
# and JSON cannot hold a comment. flatpak-builder reads both.
#
# Build it, from the repository root:
#
# flatpak-builder --user --install --force-clean \
# build/flatpak packaging/flatpak/paris.tourolle.darkroom.yml
#
# Read docs/distribution.md before changing any permission below. Every line in
# `finish-args` is a hole in the sandbox, and the one that is conspicuously
# absent — `--filesystem=` — is absent on purpose and is explained there.
id: paris.tourolle.darkroom
# 25.08 is the current freedesktop runtime, and the choice is made by what the
# binary needs rather than by what is newest. `ldd` on a release build names
# fontconfig, freetype, expat, libpng, zlib, brotli and bzip2 — all in the
# Platform — and nothing else: Vulkan, libxkbcommon and the two display-server
# protocols are reached without a link-time dependency (wgpu dlopens
# libvulkan.so.1, and x11rb and wayland-client speak the wire protocols in Rust
# rather than binding libxcb or libwayland). So the runtime has to supply a
# Vulkan loader and an ICD at *runtime*, which is the GL extension's job, and
# not much else.
runtime: org.freedesktop.Platform
runtime-version: '25.08'
sdk: org.freedesktop.Sdk
# The Rust toolchain is an SDK extension rather than something this manifest
# installs, so the build is offline-capable in the part that matters and the
# compiler is the one freedesktop tested against its own glibc.
#
# Note what this quietly overrides: `rust-toolchain.toml` pins 1.92.0, and that
# pin is honoured by *rustup*, which is not what the extension provides. The
# extension's cargo therefore ignores the file and builds with its own stable
# (1.98.0 on 25.08). That is fine here and deliberately different from
# CONTRIBUTING.md's "do not override the toolchain": the pin exists so `cargo
# fmt --check` and `clippy -D warnings` agree between a laptop and CI, and
# neither runs in this build. A *release binary* only needs a compiler at or
# above the workspace's `rust-version`.
sdk-extensions:
- org.freedesktop.Sdk.Extension.rust-stable
command: darkroom-desktop
finish-args:
# FR-PLAT-LIN-2 asks for both display servers. `fallback-x11` rather than
# `x11`: it grants the X socket only when Wayland is unavailable, so a
# Wayland session does not leave an X11 hole open beside the socket actually
# in use. `--share=ipc` goes with it — without it X11 cannot use shared
# memory and every frame is pushed through the socket instead.
- --socket=wayland
- --socket=fallback-x11
- --share=ipc
# The GPU. The develop pipeline is compute shaders through wgpu and there is
# no CPU renderer behind it, so this is not an optimisation: without
# /dev/dri the application starts and cannot develop anything.
#
# `dri` rather than `all`: it covers the render nodes and the NVIDIA device
# nodes, which is the whole of what a Vulkan ICD opens. `all` would add every
# other device on the machine for no gain.
- --device=dri
# Nextcloud (FR-NC-*). Nothing else here reaches the network — face grouping,
# segmentation and lens correction are all local and stay local (NFR-SEC-5).
- --share=network
# Credential storage (FR-NC-2). The keyring crate speaks the Secret Service
# D-Bus interface directly, which GNOME Keyring and KWallet's `ksecretd` both
# implement, so what it needs is a talk hole to that well-known name.
#
# Worth being precise, because FR-PLAT-LIN-3 says "Secret Service portal" and
# these are two different things: xdg-desktop-portal's `org.freedesktop.
# portal.Secret` hands an application a master key for a store it keeps
# itself, whereas this talks to the session's secret daemon. Only the latter
# puts the app password where `secret-tool` and Seahorse can see it, which is
# what makes a credential individually revocable by the user rather than
# opaque inside our own data directory. If no daemon answers, FR-NC-2's
# degraded mode is what the user gets — the same behaviour as outside a
# sandbox, which is the point.
- --talk-name=org.freedesktop.secrets
# No `--filesystem=` line of any kind, and this is the substance of
# FR-PLAT-LIN-3 rather than an omission.
#
# What that leaves working: /run/user/$UID/doc is mounted in every sandbox, so
# a photograph opened from a file manager — the .desktop entry declares the
# RAW MIME types and `Exec=darkroom-desktop %F` — arrives as a document-portal
# path in argv and opens. That path is genuinely portal-mediated and needs no
# code change.
#
# What that leaves broken: choosing a *library root*. The folder connector
# takes a typed absolute path (`SignIn::EndpointOnly`, placeholder
# `/home/you/Pictures`) and checks it with `std::fs`, and nothing in the tree
# calls the FileChooser portal — there is no ashpd, no rfd, no toolkit dialog.
# A path typed into that field does not exist in this sandbox, so the launch
# screen refuses it with "that folder does not exist", which is at least an
# honest error.
#
# `--filesystem=host` would make that work today and is exactly what the
# requirement forbids, so it is not here. docs/distribution.md §4 records what
# closes the gap and how to run a Flatpak build in the meantime.
modules:
- name: darkroom
buildsystem: simple
build-options:
append-path: /usr/lib/sdk/rust-stable/bin
env:
# Inside the build sandbox rather than in $HOME, so a rebuild starts
# from the state flatpak-builder is managing and not from whatever the
# host's cargo cache happens to hold.
CARGO_HOME: /run/build/darkroom/cargo
# Cargo fetches 826 crates, and Flathub's builders forbid this — a
# submission there needs `cargo-sources.json` generated by
# flatpak-builder-tools' `flatpak-cargo-generator.py` from Cargo.lock,
# listing every crate as its own source, plus a vendored-registry
# `.cargo/config.toml`. That file is ~30k lines, has to be regenerated on
# every dependency change, and buys nothing for a build from a local
# checkout, which is what this manifest is for and what packaging/PKGBUILD
# is for as well. Add it when there is a Flathub submission, not before.
build-args:
- --share=network
build-commands:
# `--locked` for the reason CI uses it: a lockfile that resolves
# differently in the packaging build than in the tree is a release whose
# dependency versions nobody chose.
- cargo build --release --locked -p darkroom-desktop
- install -Dm755 target/release/darkroom-desktop /app/bin/darkroom-desktop
- install -Dm644 packaging/paris.tourolle.darkroom.desktop
/app/share/applications/paris.tourolle.darkroom.desktop
- install -Dm644 packaging/paris.tourolle.darkroom.metainfo.xml
/app/share/metainfo/paris.tourolle.darkroom.metainfo.xml
# The icon's name is the contract, not its path — the desktop entry says
# `Icon=paris.tourolle.darkroom` and the shell resolves that through the
# hicolor theme. 256x256 because that is the source's actual size;
# installing it under a size it is not makes scaled icons look wrong.
- install -Dm644 ui/dr-ui/ui/app-icon.png
/app/share/icons/hicolor/256x256/apps/paris.tourolle.darkroom.png
# The face models, where `system_face_models_dirs()` looks: it reads
# $XDG_DATA_DIRS, which includes /app/share inside a Flatpak, so this is
# the same lookup that finds /usr/share/darkroom/models from the Arch
# package. Last in the search order, so a pair the user dropped in their
# own data directory still outranks these.
#
# These live in Git LFS. A checkout made without `git lfs pull` has
# ~130-byte pointers here, and `type: dir` below would copy the pointers
# in without complaint — producing a Flatpak whose face indexing fails
# inside the graph loader on the user's machine. Refuse instead, with the
# command that fixes it.
- |
for m in scrfd_500m_640.onnx scrfd_2.5g_640.onnx scrfd_10g_640.onnx arcface_mbf_b1.onnx; do
if [ "$(stat -c%s "models/face/$m")" -lt 100000 ]; then
echo "error: $m is an LFS pointer, not a model — run: git lfs pull" >&2
exit 1
fi
install -Dm644 "models/face/$m" "/app/share/darkroom/models/$m"
done
# The scene model, for the per-category grades. In the repository, unlike
# the face weights — AGPL, and GPLv3 §13 permits the combination
# (models/LICENCE.md) — so it installs unconditionally. Three files: the
# graph, its vocabulary, and the category descriptor; dr_ui reports the
# tab unavailable without any one of them. The pointer check is on the
# graph alone, the other two being legitimately small.
- |
if [ "$(stat -c%s models/scene/yolo26s-sem-ade20k.onnx)" -lt 100000 ]; then
echo "error: the scene model is an LFS pointer — run: git lfs pull" >&2
exit 1
fi
for m in yolo26s-sem-ade20k.onnx yolo26s-sem-ade20k.classes.json categories.txt; do
install -Dm644 "models/scene/$m" "/app/share/darkroom/models/$m"
done
- install -Dm644 README.md /app/share/doc/darkroom/README.md
sources:
# The local checkout, for the same reason packaging/PKGBUILD builds from
# one: this makes a Flatpak of what you are actually working on. Swap it
# for an `archive` or `git` source with a tag when there is a release to
# point at.
#
# `skip` is not tidiness. `target/` is tens of gigabytes and `.git` with
# LFS objects is not small; flatpak-builder copies a `dir` source
# wholesale, so without these two lines the copy is the slowest part of
# the build by a wide margin.
- type: dir
path: ../..
skip:
- target
- target-android
- .git
- build