Files
voculinux/packaging/void/README.md
T
soubarnak e6c9069e0b fix(void): use concrete release-download URL for xbps client registration
Replace the self-referential <repo-url-from-release-notes> placeholder
in the root README, the release-notes template, and the Void packaging
README with the concrete per-tag download prefix the build-xbps job
attaches the signed repo to. Static docs default TAG to the current
version; release.yml renders github.ref_name at publish time.

Fixes #29
2026-11-06 09:42:12 +05:30

185 lines
8.3 KiB
Markdown

# Void packaging
Void Linux (glibc, x86_64) templates in void-packages layout, built with the
standard Void source tooling. Submission to upstream void-packages is out of
scope for spec #16; these templates serve the signed personal xbps
repository first.
## Layout
```
packaging/void/
├── README.md this file
├── build.sh podman harness: lint + xbps-src build + import smoke
├── smoke.sh ticket #28 gate: every template, one command
├── repo.sh ticket #29 pipeline: build all, index, sign
├── container-repo.sh ticket #29 container half (index + sign + verify)
├── tool_checksums.txt pinned base image and void-packages commit
└── srcpkgs/
├── python3-pywhispercpp/ ticket #26: whisper.cpp Python binding
├── ... ticket #25: small Python dependencies
└── voculinux ticket #27: the application
```
`srcpkgs/` mirrors void-packages so the tree overlays cleanly:
`cp -r packaging/void/srcpkgs/. /path/to/void-packages/srcpkgs/`
(`build.sh` does this inside the container.)
## Templates
| Template | Ticket | Notes |
|---|---|---|
| `python3-pywhispercpp` | #26 | Vulkan backend on by default; see below |
| `voculinux` | #27 | The app, from the canonical release sdist; see below |
## python3-pywhispercpp
Version `1.5.0`, pinned to the same version `install.sh`
(`PYWHISPERCPP_VERSION`) and `uv.lock` pin — never newest upstream.
The sdist checksum in the template must equal the `sha256` uv.lock records
for the sdist; `tests/test_void_pywhispercpp_template.py` fails otherwise.
- **Vulkan** is a build option, on by default. Rebuild CPU-only with
`build.sh python3-pywhispercpp -- -o ~vulkan pkg`. There is no CUDA
build: Void ships no CUDA toolkit package. Rebuilding locally with a
hand-installed toolkit (`GGML_CUDA=1`) is a documented, unsupported
escape hatch.
- **Portable CPU flags**: every ggml SIMD option is pinned off
(`-DGGML_NATIVE=OFF -DGGML_SSE42=OFF ...`), the plain x86-64 baseline
already used by the Flatpak (`#938`, `#957`). The offline test asserts
each pin in the template (the build configuration), and the harness
scans the shipped `libggml-cpu` (`.GCC.command.line`, `.comment`) for
recorded `-march=native`/`-mcpu=native`/`-mtune=native` flags and fails
on a match. The recorded-flags scan is a tripwire, not a proof: the
proof is the pinned configuration plus `setup.py`'s documented
`CMAKE_ARGS` passthrough.
- **Shared libraries**: `BUILD_SHARED_LIBS=ON` with an `$ORIGIN` rpath
(as `install.sh` does), so the extension resolves the whisper.cpp
libraries installed beside it with no `LD_LIBRARY_PATH`.
- **Offline build**: the sdist vendors whisper.cpp, pybind11, and the
ggml sources; the build fetches nothing beyond the declared distfiles.
`PYWHISPERCPP_VERSION` is injected because the sdist carries no
`version.txt` (its version otherwise comes from git metadata).
- **Runtime deps** (`python3-numpy`, `python3-requests`, `python3-tqdm`,
`python3-platformdirs`) are the sdist's own `install_requires` and were
verified to exist in current void-packages; the container build
re-verifies via dependency resolution.
## voculinux
Version `0.18.5`, matching `src/vocalinux/version.py` — never newest
upstream. The template builds the canonical release source distribution
(the `releases/download` sdist, the same bytes published to PyPI) with a
pinned `checksum`; `tests/test_void_app_template.py` fails otherwise.
The 0.18.5 asset still carries the pre-rename archive root; xbps-src
moves the single top-level directory to `pkgname-version` itself, so no
`wrksrc` override is needed (`wrksrc` is deprecated and `xlint` rejects
it). The first release cut after the rename points `distfiles` at the
renamed asset.
- **Runtime deps** are Void's own interpreter, GTK and desktop bindings
(`python3`, `python3-gobject`, `python3-cairo`, `gtk+3`,
`libayatana-appindicator`, `ibus`, `gobject-introspection`), the
packaged Python libraries, and the three templates from tickets #25
and #26 (`python3-pynput`, `python3-PyAudio`, `python3-pywhispercpp`).
Every name was verified to exist in current void-packages; the
container build re-verifies via dependency resolution.
- **No payload beyond the app**: no speech models (they download on
first run), no vendored wheels, no pip at build or install time. The
container smoke fails the build if the payload carries model weights
or wheels.
- **Renamed paths**: the `voculinux.desktop` entry, the hicolor icons,
and a `usr/share/voculinux/packaged` marker the app reads to present
package-manager updates. The 0.18.5 sdist predates the rename, so
`post_install` promotes the old file names at install time; the payload
smoke rejects any pre-rename leftovers in the OS-visible paths.
- **INSTALL.msg** covers what xbps cannot express: the `input` group for
the evdev hotkey backend, first-run model downloads, optional engines
as manual additions (vosk, OpenAI whisper, Parakeet, faster-whisper,
onnxruntime), the absent `ydotool` rung, and updating through xbps.
- **Update checker**: packaged installs keep background checks as a
signal, but every update affordance (tray entry, notification, About
page) presents the package-manager path
(`src/vocalinux/utils/packaging.py`).
## Building
```sh
packaging/void/build.sh python3-pywhispercpp
packaging/void/build.sh python3-pywhispercpp -- -o ~vulkan pkg
packaging/void/build.sh voculinux
```
Podman only, never Docker. The base image digest and the void-packages
commit come from `tool_checksums.txt`; bump them there, never in the
script.
## Smoke gate
One command runs the whole gate from a clean checkout — no host Void
install — linting, building, installing and smoke-testing every
template under `srcpkgs` in dependency order (the app last):
```sh
packaging/void/smoke.sh
# or: just void-smoke
```
Each package delegates to `build.sh`, so the pinned container and the
per-package stages (xlint, xbps-src, install, payload/version/import
smoke) stay implemented once. The gate fails fast: a broken package
prints `FAIL: <pkgname>` naming which package broke, above it the
harness echoes which stage broke. `tests/test_void_smoke_gate.py`
asserts offline that the gate stays wired to every `srcpkgs` template,
so a renamed or added template cannot silently drop out.
## Signed repository
`packaging/void/repo.sh` builds every template in smoke-gate order, indexes
the full repository (`x86_64-repodata`), and signs every binary package
(`*.sig2`) plus the repository metadata with the RSA4096 repository key —
one command, same pinned container via podman, no host Void install:
```sh
# Run the smoke gate first: the repo assembles tested packages.
packaging/void/smoke.sh
# or: just void-smoke
printf '%s' "$XBPS_SIGNING_KEY" > /tmp/xbps-sign-key.pem
XBPS_SIGNING_KEY_FILE=/tmp/xbps-sign-key.pem packaging/void/repo.sh
# or: XBPS_SIGNING_KEY_FILE=/tmp/xbps-sign-key.pem just void-repo
```
The pipeline stages `publish/xbps/repo/` (packages, signatures, repodata)
plus `publish/xbps/keys/` (the client `.plist` named by key fingerprint,
and a `FINGERPRINT` file carrying the signer identity and fingerprint for
release notes). `publish/` is local build output and stays uncommitted.
Fail-closed: a missing, unreadable, or non-RSA4096 key aborts before any
container runs, so an unsigned repository can never publish. CI holds the
PEM-encoded key in the `XBPS_SIGNING_KEY` secret and writes it to a file
first (a file keeps newlines intact and the key out of process listings).
**Maintainer key setup (one time):**
```sh
openssl genrsa -out xbps-sign-key.pem 4096
# back the key up somewhere safe, then store it as XBPS_SIGNING_KEY
```
**Client setup:**
```sh
# as root on the Void system (the release notes carry the repo URL):
cp <fingerprint>.plist /var/db/xbps/keys/
TAG=v0.18.5 # match the release you install from
echo "repository=https://github.com/VocaHQ/vocalinux/releases/download/${TAG}/" > /etc/xbps.d/voculinux.conf
xbps-install -Sy voculinux
```
Answer `Y` when xbps shows the fingerprint prompt on first sync, and check
it matches the published `FINGERPRINT` file. `tests/test_void_signed_repo.py`
asserts offline that the pipeline stays wired to every `srcpkgs` template,
stays podman-only on the pinned inputs, and keeps the fail-closed key
contract.