Debian packages for software Debian does not carry, built on GitHub Actions and served as a signed apt repository from GitHub Pages.
packages/<name>/package.env pinned version + sha256
|
v
.github/workflows/<name>.yml build in a debian:sid container
|
v
.github/workflows/publish.yml apt-ftparchive + gpg --clearsign
|
v
gh-pages branch
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://apt.xeyes.org/key.gpg \
| sudo tee /etc/apt/keyrings/apt.xeyes.org.gpg > /dev/null
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/apt.xeyes.org.gpg] https://apt.xeyes.org sid main" \
| sudo tee /etc/apt/sources.list.d/apt.xeyes.org.list
sudo apt update| Package | Source | Built how |
|---|---|---|
ghostty |
release.files.ghostty.org source tarball |
compiled with a pinned Zig, dpkg-buildpackage |
zig |
ziglang.org official static tarball |
repackaged, nothing compiled |
packages/<name>/package.env is the whole recipe: an upstream version, a
sha256 for every tarball fetched, and a Debian revision. Nothing floats — a
build is reproducible from the recipe alone, and every download is checked
against its recorded hash before use.
The two Zig versions in the tree are unrelated:
packages/zig/package.env— the Zig that gets published, tracking latest stable.packages/ghostty/package.envZIG_VERSION— the Zig ghostty is built with.
Ghostty compiles against exactly one Zig release. build-ghostty.sh reads
minimum_zig_version from the release tarball and refuses to build if it
disagrees with the recipe, so a silent compiler mismatch is not possible.
Versions are <upstream>-<revision>~<suite>. Bump DEBIAN_REVISION when the
packaging changes but upstream has not; an upstream bump resets it to 1.
check-upstream.yml runs daily. It compares each recipe against upstream,
rewrites package.env where something is newer — recomputing the sha256, and
for ghostty also the required Zig — and opens a pull request. Merging it
triggers the build.
It is a pull request rather than a direct commit because an upstream bump can need packaging changes too, and a failed build should not be the first sign.
Everything runs in the same container the workflow uses:
docker run --rm -v "$PWD:/w" -w /w debian:sid ./scripts/build-zig.sh
docker run --rm -v "$PWD:/w" -w /w debian:sid ./scripts/build-ghostty.shArtifacts land in build/. publish.sh takes an incoming directory and a site
directory, and needs GPG_KEY_ID set to an imported secret key.
packages/<name>/package.envwithUPSTREAM_VERSION,UPSTREAM_SHA256,DEBIAN_REVISION.- A
debian/directory if it needsdpkg-buildpackage; nothing if the upstream artifact can be repackaged likezig. scripts/build-<name>.sh, modelled on the closer of the two..github/workflows/<name>.yml, copied fromzig.yml. Trigger onpackages/<name>/**and its own build script — not on the workflow file itself, so editing how a job runs does not rebuild the artifact.- Teach
scripts/check-upstream.shhow to find its latest version.
- The build container must match
DISTRIBUTIONinconfig.env.shlibs:Dependsis generated against whatever the build ran in.assert_build_suitefails the build rather than trusting the two to agree. - Do not build on a newer suite than you install on, or the generated dependency floors will be unsatisfiable.
apt-ftparchive releasehashes everything underdists/, including a previous run'sRelease.publish.shremoves the old signatures first; otherwise the file signs a digest of itself.- GitHub Pages runs Jekyll, which drops paths beginning with
_or.. The.nojekyllmarker keeps the pool intact. publish.shwrites theCNAMEfile on every publish, so the custom domain survives the branch being recreated.- The pool keeps one version per package. A new build deletes the old
.deb; there is no rollback target in the repository. - The repository is
amd64only, so the sources line carriesarch=amd64. Without it a client that has enabled a foreign architecture (dpkg --add-architecture i386) asks for an i386 index on everyapt updateand getsSkipping acquire of configured file 'main/binary-i386/Packages'. Harmless, but the restriction is what every other single-architecture repository ships and it keeps the notice off. - Never republish a version string that has already shipped. apt dispatches
on the version alone, so a rebuilt
.debcarrying the same<upstream>-<revision>~<suite>reaches no machine that already installed the old one:apt upgradecompares equal and does nothing, and onlyapt install --reinstallcrosses the gap.zig 0.16.0-2~sidwent out twice and the two builds disagree onInstalled-Size(405332 against 405336, onedublock from a different builder filesystem), which shows up client-side as two records inapt show -a zig. BumpDEBIAN_REVISIONfor any rebuild that leaves the pool.