feat(packaging): the trial's Linux column and the Linux packages (P11a steps 1 and 3)
The Linux half of the packaging trial, run on this machine and in Debian, Fedora and Arch containers, and the recipes it produced (docs/packaging.md holds the table and what it found): - mise.toml pins cargo-packager 0.11.8 and cargo-generate-rpm 0.21.1, now that `just package-linux` calls them. cargo-packager-updater is a library, not a tool, so it is not pinned (update.rs does the checking with minisign-verify, which is what the updater uses). - deploy/packaging/: packager.toml (.deb, AppImage, the pacman tarball and its PKGBUILD), the rpm table in crates/ledger-cli/Cargo.toml, the AUR's own PKGBUILD (repacks the release tarball), build-linux.sh, repo-indexes.sh (the apt and dnf indexes, unsigned until the signing step), local-release.sh (a throwaway-keyed feed to try `update`), test-linux-packages.sh (linux_packages_install_and_upgrade: install 0.1.0, open books as an ordinary user, upgrade to 0.1.1, check the host restarted onto the new file, the books' last journal line unchanged and `update` refuses; passes on Debian trixie, Fedora and Arch). A package marks itself package-managed with share/wanderbooks/install-method. - The icon is a placeholder square (the AppImage cannot be built without one). - .github/workflows/release.yml: on a version tag, build on ubuntu-24.04 (the oldest glibc the packages claim: a program linked on this machine needs GLIBC_2.43 and does not start on Debian 13), attach the packages to the release, and add them to the apt and dnf repositories on gh-pages. No signing and no macOS or Windows job yet. - The release profile strips symbols. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
1 parent
4b5f44689d
commit
3058b5c229
20 files changed
+669
-18
No files matched your search
@@ -0,0 +1,77 @@
|
||||
# Releases (plan P11a, D-24, D-26): on a version tag, build the Linux
|
||||
# packages on the oldest system they claim (ubuntu-24.04, glibc 2.39; a
|
||||
# program linked on a newer one does not start on an older one), attach
|
||||
# them to the GitHub release, and add them to the apt and dnf repositories
|
||||
# on the gh-pages branch (GitHub Pages serves them). Unsigned: step 5 of
|
||||
# the unit (the release key, Q-4) signs the manifest and the indexes, and
|
||||
# step 6 adds the macOS and Windows jobs. The release holds no key today.
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ["v*"]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: ubuntu-24.04
|
||||
# Same disk discipline as check.yml: no incremental caches.
|
||||
env:
|
||||
CARGO_INCREMENTAL: "0"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Room for the build (the image ships toolchains we never use)
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
|
||||
/opt/hostedtoolcache/CodeQL /usr/local/.ghcup
|
||||
df -h / | tail -1
|
||||
- uses: jdx/mise-action@v2
|
||||
with:
|
||||
# Only what packaging needs, not the proof and fuzz tools.
|
||||
install_args: "rust just cargo:cargo-packager cargo:cargo-generate-rpm"
|
||||
- name: GUI build dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libxkbcommon-dev libgtk-3-dev apt-utils createrepo-c
|
||||
- name: The tag is the program's version
|
||||
id: version
|
||||
run: |
|
||||
own=$(sed -n 's/^version = "\(.*\)"/\1/p' crates/ledger-cli/Cargo.toml | head -n1)
|
||||
tag="${GITHUB_REF_NAME#v}"
|
||||
if [ "${GITHUB_REF_TYPE}" = tag ] && [ "$tag" != "$own" ]; then
|
||||
echo "tag $GITHUB_REF_NAME is not version $own" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "version=$own" >> "$GITHUB_OUTPUT"
|
||||
- name: Build the packages
|
||||
run: just package-linux ${{ steps.version.outputs.version }}
|
||||
- name: Attach them to the release
|
||||
if: github.ref_type == 'tag'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
v=${{ steps.version.outputs.version }}
|
||||
gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1 || gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes "wanderbooks $v"
|
||||
gh release upload "$GITHUB_REF_NAME" --clobber target/packages/$v/*.AppImage target/packages/$v/*.deb target/packages/$v/*.rpm target/packages/$v/*.tar.gz
|
||||
- name: Add them to the apt and dnf repositories (gh-pages)
|
||||
if: github.ref_type == 'tag'
|
||||
run: |
|
||||
v=${{ steps.version.outputs.version }}
|
||||
git fetch origin gh-pages || true
|
||||
if git rev-parse --verify origin/gh-pages >/dev/null 2>&1; then
|
||||
git worktree add repo origin/gh-pages
|
||||
else
|
||||
git worktree add --detach repo && git -C repo checkout --orphan gh-pages && git -C repo rm -rfq . || true
|
||||
fi
|
||||
mkdir -p repo/apt/pool repo/dnf
|
||||
cp target/packages/$v/*.deb repo/apt/pool/
|
||||
cp target/packages/$v/*.rpm repo/dnf/
|
||||
deploy/packaging/repo-indexes.sh apt repo/apt
|
||||
deploy/packaging/repo-indexes.sh dnf repo/dnf
|
||||
cd repo
|
||||
git config user.name "wanderbooks release"
|
||||
git config user.email "release@wanderbooks.ai"
|
||||
git add -A
|
||||
git commit -m "wanderbooks $v"
|
||||
git push origin HEAD:gh-pages
|
||||
@@ -95,6 +95,15 @@ create acme`, `wanderbooks connect claude --book acme` (or `connect codex`).
|
||||
Then talk to the agent; `wanderbooks gui acme` shows the books, and its
|
||||
Books menu backs them up, restores, starts new books and closes them.
|
||||
|
||||
Updating: an AppImage, or a `wanderbooks` you put somewhere yourself, brings
|
||||
itself to the newest release with `wanderbooks update` (it checks the
|
||||
download against our release key, keeps the version it replaces, and the
|
||||
open books restart onto the new one when idle); `wanderbooks rollback` goes
|
||||
back, unless a book has since moved to a newer journal format. A `.deb`,
|
||||
`.rpm` or AUR install is updated by its package manager and `update` says
|
||||
so. The Linux packages are built here with `just package-linux`
|
||||
(docs/packaging.md); none is published yet.
|
||||
|
||||
## Developing
|
||||
|
||||
Every tool the recipes use (Rust, just, Kani, Lean, cargo-mutants,
|
||||
|
||||
+4
-2
@@ -32,8 +32,10 @@ sudo install -D -m 0644 deploy/wanderbooks-server.service \
|
||||
```
|
||||
|
||||
The executable is the server-only build: no viewer, no window libraries.
|
||||
On a Linux package install (P11) this is the same binary and the package
|
||||
manager writes the file; until then, copy it as above.
|
||||
The Linux packages (`.deb`, `.rpm`, AUR; `just package-linux`, docs/packaging.md)
|
||||
carry the viewer build, which also serves: on a package install the package
|
||||
manager writes the file and `wanderbooks update` refuses. A server with no
|
||||
window libraries is still this server-only build, copied as above.
|
||||
|
||||
## 2. Make the data root, once
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Maintainer: Stephen Waits
|
||||
# The AUR package (P11a step 3, D-24, D-26): it repacks the tarball of the
|
||||
# release's files that GitHub Releases serves; nothing is built from source.
|
||||
# `updpkgsums` fills the checksum when a release is published.
|
||||
pkgname=wanderbooks-bin
|
||||
pkgver=0.1.0
|
||||
pkgrel=1
|
||||
pkgdesc="Double-entry bookkeeping your agent keeps and you can read"
|
||||
arch=('x86_64')
|
||||
url="https://wanderbooks.ai"
|
||||
license=('MIT' 'Apache-2.0')
|
||||
depends=('gcc-libs' 'glibc')
|
||||
provides=('wanderbooks')
|
||||
conflicts=('wanderbooks')
|
||||
options=('!lto' '!strip')
|
||||
# The tarball holds usr/bin/wanderbooks, usr/share/applications/ and
|
||||
# usr/share/wanderbooks/install-method (which makes `wanderbooks update`
|
||||
# refuse and send the owner to pacman).
|
||||
source=("wanderbooks_${pkgver}_x86_64.tar.gz::https://github.com/swaits/wanderbooks/releases/download/v${pkgver}/wanderbooks_${pkgver}_x86_64.tar.gz")
|
||||
sha256sums=('SKIP')
|
||||
noextract=()
|
||||
|
||||
package() {
|
||||
cp -r "${srcdir}/usr" "${pkgdir}/usr"
|
||||
}
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# The Linux packages (P11a step 3), from the release program already built
|
||||
# at target/release/wanderbooks (`cargo build --release -p ledger-cli`).
|
||||
#
|
||||
# build-linux.sh [VERSION] [FORMATS]
|
||||
#
|
||||
# Puts into target/packages/VERSION/: the .deb, the AppImage and the
|
||||
# pacman tarball with its PKGBUILD (cargo-packager), and the .rpm
|
||||
# (cargo-generate-rpm). VERSION defaults to the program's own; a different
|
||||
# one repackages the same program under that version, which is how the
|
||||
# install-and-upgrade test gets its second release. FORMATS is
|
||||
# cargo-packager's list (default deb,appimage,pacman); the .rpm is always
|
||||
# built. Run from the repository root.
|
||||
#
|
||||
# The program is target/release/wanderbooks, or the file WB_PROGRAM names:
|
||||
# a package must run on the oldest system it claims, and a program linked
|
||||
# on a newer one (this machine's glibc) fails there with "GLIBC_2.43 not
|
||||
# found". CI builds on ubuntu-24.04; `just test-linux-packages` builds in a
|
||||
# Debian trixie container.
|
||||
set -euo pipefail
|
||||
own=$(sed -n 's/^version = "\(.*\)"/\1/p' crates/ledger-cli/Cargo.toml | head -n1)
|
||||
version=${1:-$own}
|
||||
formats=${2:-deb,appimage,pacman}
|
||||
out="target/packages/$version"
|
||||
program=${WB_PROGRAM:-target/release/wanderbooks}
|
||||
test -x "$program" || { echo "build the release program first: cargo build --release -p ledger-cli" >&2; exit 1; }
|
||||
rm -rf "$out"; mkdir -p "$out"
|
||||
stage="target/packages/.stage-$version"
|
||||
rm -rf "$stage"; mkdir -p "$stage"
|
||||
cp "$program" "$stage/wanderbooks"
|
||||
config=$(mktemp --suffix=.toml)
|
||||
trap 'rm -f "$config"' EXIT
|
||||
# cargo-packager reads paths relative to the config file, which is in /tmp
|
||||
# here, so they are made absolute.
|
||||
sed "s/^version = \".*\"/version = \"$version\"/
|
||||
s#^out-dir = .*#out-dir = \"$PWD/$out\"#
|
||||
s#\"target/release\"#\"$PWD/$stage\"#
|
||||
s#\"deploy/packaging/#\"$PWD/deploy/packaging/#
|
||||
s#\"LICENSE-MIT\"#\"$PWD/LICENSE-MIT\"#" \
|
||||
deploy/packaging/packager.toml >"$config"
|
||||
# The AppImage tools are themselves AppImages; run them without FUSE.
|
||||
export APPIMAGE_EXTRACT_AND_RUN=1
|
||||
cargo packager --config "$config" --formats "$formats" --release
|
||||
assets='assets = [
|
||||
{ source = "'$PWD/$stage'/wanderbooks", dest = "/usr/bin/wanderbooks", mode = "0755" },
|
||||
{ source = "deploy/packaging/install-method-rpm", dest = "/usr/share/wanderbooks/install-method", mode = "0644" },
|
||||
{ source = "deploy/packaging/wanderbooks-static.desktop", dest = "/usr/share/applications/wanderbooks.desktop", mode = "0644" },
|
||||
]'
|
||||
cargo generate-rpm -p crates/ledger-cli --set-metadata "version=\"$version\"" --set-metadata "$assets" -o "$out/"
|
||||
rm -rf "$stage"
|
||||
ls -l "$out"
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1 @@
|
||||
aur
|
||||
@@ -0,0 +1 @@
|
||||
deb
|
||||
@@ -0,0 +1 @@
|
||||
rpm
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
# A release folder on this machine, for trying `wanderbooks update` without
|
||||
# a network or the owner's keys (P11a step 2; docs/packaging.md).
|
||||
#
|
||||
# local-release.sh FILE VERSION OUTDIR
|
||||
#
|
||||
# Makes a throwaway signing key in OUTDIR/key (never a release key), signs
|
||||
# FILE with it through cargo-packager, copies it beside a manifest.json in
|
||||
# the shape `wanderbooks update` reads, and leaves the key's public half in
|
||||
# OUTDIR/release.pub. Then:
|
||||
#
|
||||
# wanderbooks update --feed file://OUTDIR/manifest.json \
|
||||
# --trusted-key OUTDIR/release.pub
|
||||
set -euo pipefail
|
||||
file=${1:?usage: local-release.sh FILE VERSION OUTDIR}
|
||||
version=${2:?usage: local-release.sh FILE VERSION OUTDIR}
|
||||
out=${3:?usage: local-release.sh FILE VERSION OUTDIR}
|
||||
mkdir -p "$out"
|
||||
if [ ! -f "$out/key" ]; then
|
||||
cargo packager signer generate --path "$out/key" --password "" --ci >/dev/null
|
||||
cp "$out/key.pub" "$out/release.pub"
|
||||
fi
|
||||
case "$(uname -m)" in arm64) arch=aarch64 ;; *) arch=$(uname -m) ;; esac
|
||||
platform="$(uname -s | tr '[:upper:]' '[:lower:]')-$arch"
|
||||
name="wanderbooks-$version-$platform"
|
||||
cp "$file" "$out/$name"
|
||||
cargo packager signer sign "$out/$name" --private-key "$out/key" --password "" >/dev/null
|
||||
sha=$(sha256sum "$out/$name" | cut -d' ' -f1)
|
||||
sig=$(tr -d '\n' <"$out/$name.sig")
|
||||
printf '{"version":"%s","notes":"a local release","platforms":{"%s":{"url":"%s","sha256":"%s","signature":"%s"}}}\n' \
|
||||
"$version" "$platform" "$name" "$sha" "$sig" >"$out/manifest.json"
|
||||
echo "feed: file://$(cd "$out" && pwd)/manifest.json key: $out/release.pub"
|
||||
@@ -0,0 +1,36 @@
|
||||
# cargo-packager's description of the Linux bundles (P11a step 3; D-25).
|
||||
# `just package-linux` builds the release program and runs
|
||||
# cargo packager --config deploy/packaging/packager.toml
|
||||
# from the repository root. The .rpm is cargo-generate-rpm's, from the
|
||||
# [package.metadata.generate-rpm] table of crates/ledger-cli/Cargo.toml.
|
||||
name = "wanderbooks"
|
||||
product-name = "Wanderbooks"
|
||||
version = "0.1.0"
|
||||
identifier = "ai.wanderbooks.app"
|
||||
description = "Double-entry bookkeeping your agent keeps and you can read."
|
||||
long-description = "One program: the viewer, the books server, and the bridge that lets Claude Code or Codex keep the books."
|
||||
homepage = "https://wanderbooks.ai"
|
||||
authors = ["Stephen Waits"]
|
||||
license-file = "LICENSE-MIT"
|
||||
category = "Finance"
|
||||
binaries-dir = "target/release"
|
||||
out-dir = "target/packages"
|
||||
icons = ["deploy/packaging/icons/512x512.png"]
|
||||
formats = ["deb", "appimage", "pacman"]
|
||||
binaries = [{ path = "wanderbooks", main = true }]
|
||||
|
||||
[deb]
|
||||
section = "utils"
|
||||
# A deb marks itself package-managed: `wanderbooks update` refuses on it
|
||||
# and says to use apt (plan 3.9).
|
||||
desktop-template = "deploy/packaging/wanderbooks.desktop"
|
||||
depends = ["libc6", "libgcc-s1"]
|
||||
|
||||
[deb.files]
|
||||
"deploy/packaging/install-method-deb" = "usr/share/wanderbooks/install-method"
|
||||
|
||||
[pacman]
|
||||
depends = ["gcc-libs", "glibc"]
|
||||
|
||||
[pacman.files]
|
||||
"deploy/packaging/install-method-aur" = "usr/share/wanderbooks/install-method"
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# The apt and dnf repository indexes (P11a step 3), served from GitHub
|
||||
# Pages (D-26). Unsigned until step 5 gives them the release key.
|
||||
#
|
||||
# repo-indexes.sh apt DIR DIR/pool/*.deb -> DIR/dists/stable/...
|
||||
# repo-indexes.sh dnf DIR DIR/*.rpm -> DIR/repodata/
|
||||
#
|
||||
# Every release stays in the pool: a downgrade is the package manager's
|
||||
# (plan 3.9). apt needs apt-utils (`apt-ftparchive`), dnf needs
|
||||
# createrepo_c.
|
||||
set -euo pipefail
|
||||
kind=${1:?usage: repo-indexes.sh apt|dnf DIR}
|
||||
dir=${2:?usage: repo-indexes.sh apt|dnf DIR}
|
||||
case "$kind" in
|
||||
apt)
|
||||
cd "$dir"
|
||||
arch=binary-amd64
|
||||
mkdir -p "dists/stable/main/$arch"
|
||||
apt-ftparchive packages pool >"dists/stable/main/$arch/Packages"
|
||||
gzip -9 -kf "dists/stable/main/$arch/Packages"
|
||||
apt-ftparchive \
|
||||
-o APT::FTPArchive::Release::Origin=wanderbooks \
|
||||
-o APT::FTPArchive::Release::Suite=stable \
|
||||
-o APT::FTPArchive::Release::Codename=stable \
|
||||
-o APT::FTPArchive::Release::Architectures=amd64 \
|
||||
-o APT::FTPArchive::Release::Components=main \
|
||||
release dists/stable >dists/stable/Release.tmp
|
||||
mv dists/stable/Release.tmp dists/stable/Release
|
||||
;;
|
||||
dnf)
|
||||
createrepo_c --update "$dir"
|
||||
;;
|
||||
*)
|
||||
echo "usage: repo-indexes.sh apt|dnf DIR" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
# linux_packages_install_and_upgrade (P11a step 3): in a clean Debian,
|
||||
# Fedora and Arch container, install release 0.1.0 from its package,
|
||||
# open the books as an ordinary user, upgrade to 0.1.1 as root, and check
|
||||
# that the books' head is unchanged, that the host the books were open
|
||||
# under restarted onto the new file, and that `wanderbooks update` refuses
|
||||
# (a package manager owns the program). The containers run with
|
||||
# seccomp=unconfined: the host refuses to run under a filter (host.rs
|
||||
# INVARIANT 2), and Docker's default profile is one. Run from the repository root after
|
||||
# `just test-linux-packages` built both releases (target/packages/).
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
old=0.1.0 new=0.1.1
|
||||
pk=$PWD/target/packages
|
||||
mount=(-v "$pk:/packages:ro")
|
||||
|
||||
# The steps every distro shares, run inside the container: `install` and
|
||||
# `upgrade` are shell snippets for that distro.
|
||||
common() { cat <<'INNER'
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
useradd -m tester
|
||||
as_tester() { su tester -c "$*"; }
|
||||
install_old
|
||||
test -x /usr/bin/wanderbooks
|
||||
grep -q . /usr/share/wanderbooks/install-method
|
||||
as_tester 'wanderbooks --help' >/dev/null 2>&1 || true
|
||||
as_tester 'wanderbooks setup' >/dev/null
|
||||
as_tester 'wanderbooks books create acme' >/dev/null
|
||||
head_of() { as_tester 'tail -n1 ~/.local/share/wanderbooks/books/acme/journal.jsonl | sha256sum'; }
|
||||
before=$(as_tester 'wanderbooks books list')
|
||||
head_before=$(head_of)
|
||||
echo "before: $before head $head_before"
|
||||
# The books open: a holder keeps the host and server running.
|
||||
as_tester 'nohup wanderbooks serve >/tmp/serve.log 2>&1 &'
|
||||
for _ in $(seq 50); do pgrep -u tester -x wanderbooks -a | grep -q ' host' && break; sleep 0.2; done
|
||||
host_before=$(pgrep -u tester -f 'wanderbooks host' | head -n1)
|
||||
test -n "$host_before"
|
||||
upgrade_new
|
||||
# The host notices the replaced file and restarts onto it.
|
||||
for _ in $(seq 150); do
|
||||
host_after=$(pgrep -u tester -f 'wanderbooks host' | head -n1 || true)
|
||||
[ -n "$host_after" ] && [ "$host_after" != "$host_before" ] && break
|
||||
sleep 0.2
|
||||
done
|
||||
test -n "$host_after" && test "$host_after" != "$host_before"
|
||||
! readlink "/proc/$host_after/exe" | grep -q deleted
|
||||
after=$(as_tester 'wanderbooks books list')
|
||||
echo "after: $after head $(head_of)"
|
||||
test "$before" = "$after"
|
||||
test "$head_before" = "$(head_of)"
|
||||
if as_tester 'wanderbooks update' >/tmp/update.out 2>&1; then echo "update did not refuse" >&2; exit 1; fi
|
||||
grep -q 'package manager' /tmp/update.out
|
||||
as_tester 'wanderbooks close' >/dev/null 2>&1 || true
|
||||
echo "OK"
|
||||
INNER
|
||||
}
|
||||
|
||||
run() { # name image install_old upgrade_new
|
||||
local name=$1 image=$2
|
||||
echo "== $name ($image)"
|
||||
docker run --rm --security-opt seccomp=unconfined -e DEBIAN_FRONTEND=noninteractive "${mount[@]}" "$image" bash -c "
|
||||
$3
|
||||
$4
|
||||
$(common)"
|
||||
}
|
||||
|
||||
# Debian and Fedora install from a repository built by repo-indexes.sh
|
||||
# (the one GitHub Pages serves), the new release added to it afterwards.
|
||||
mount+=(-v "$PWD/deploy/packaging:/tools:ro")
|
||||
run debian debian:trixie-slim \
|
||||
"apt-get update -qq && apt-get install -y -qq apt-utils procps >/dev/null
|
||||
mkdir -p /repo/apt/pool && cp /packages/$old/*.deb /repo/apt/pool/ && /tools/repo-indexes.sh apt /repo/apt
|
||||
echo 'deb [trusted=yes] file:///repo/apt stable main' >/etc/apt/sources.list.d/wanderbooks.list
|
||||
install_old() { apt-get update -qq && apt-get install -y -qq wanderbooks >/dev/null; }" \
|
||||
"upgrade_new() { cp /packages/$new/*.deb /repo/apt/pool/ && /tools/repo-indexes.sh apt /repo/apt && apt-get update -qq && apt-get install -y -qq --only-upgrade wanderbooks >/dev/null; }"
|
||||
|
||||
run fedora fedora:latest \
|
||||
"dnf install -y -q procps-ng util-linux createrepo_c >/dev/null
|
||||
mkdir -p /repo/dnf && cp /packages/$old/*.rpm /repo/dnf/ && /tools/repo-indexes.sh dnf /repo/dnf
|
||||
printf '[wanderbooks]\nname=wanderbooks\nbaseurl=file:///repo/dnf\ngpgcheck=0\n' >/etc/yum.repos.d/wanderbooks.repo
|
||||
install_old() { dnf install -y -q wanderbooks >/dev/null; }" \
|
||||
"upgrade_new() { cp /packages/$new/*.rpm /repo/dnf/ && /tools/repo-indexes.sh dnf /repo/dnf && dnf upgrade -y -q --refresh wanderbooks >/dev/null; }"
|
||||
|
||||
# Arch: the AUR's own PKGBUILD (deploy/packaging/aur), its source pointed at
|
||||
# the tarball just built instead of the release URL, makes the package as
|
||||
# an ordinary user.
|
||||
arch_build='build() { rm -rf /build/$1 && mkdir -p /build/$1 && cp /packages/$1/*.tar.gz /build/$1/ && cp /tools/aur/PKGBUILD /build/$1/PKGBUILD && sed -i "s/^pkgver=.*/pkgver=$1/; s|^source=.*|source=(wanderbooks_$1_x86_64.tar.gz)|" /build/$1/PKGBUILD && chown -R builder /build/$1 && su builder -c "cd /build/$1 && makepkg -f --nodeps >/dev/null 2>&1"; }'
|
||||
run arch archlinux:latest \
|
||||
"useradd -m builder; pacman -Sy --noconfirm --needed base-devel procps-ng >/dev/null 2>&1; $arch_build; install_old() { build $old; pacman -U --noconfirm /build/$old/*.pkg.tar.zst >/dev/null 2>&1; }" \
|
||||
"upgrade_new() { build $new; pacman -U --noconfirm /build/$new/*.pkg.tar.zst >/dev/null 2>&1; }"
|
||||
echo "all packages install and upgrade"
|
||||
@@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Categories=Office;Finance;
|
||||
Comment=Double-entry bookkeeping your agent keeps and you can read.
|
||||
Exec=wanderbooks
|
||||
Name=Wanderbooks
|
||||
Terminal=false
|
||||
Type=Application
|
||||
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Categories={{categories}}
|
||||
{{#if comment}}
|
||||
Comment={{comment}}
|
||||
{{/if}}
|
||||
Exec={{exec}}
|
||||
Icon={{icon}}
|
||||
Name={{name}}
|
||||
Terminal=false
|
||||
Type=Application
|
||||
+41
-1
@@ -36,7 +36,7 @@ the specification in `bookspec/` (which never depends on the engine).
|
||||
| `ledger-import` | formats: QuickBooks CSV in; IIF, XLSX, Typst PDFs (statements, the invoice, labels) out | `ledger-core`, `ledger-reader` |
|
||||
| `ledger-package` | the shared read-only view over `Store` or `Snapshot` (`PackageBooks`): the CPA package, the 1099 worksheet, the invoice document, Needs attention | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-vault` |
|
||||
| `ledger-mcp` | the books server: the MCP tools (122), resources, the handbook, scopes, the door and the access log, backups' scheduling | all of the above |
|
||||
| `ledger-host` | the host and its leases, the agent bridge (`wanderbooks mcp`), tokens in 0600 files under the data root (D-63), the owner's commands, uploads and downloads | `ledger-store`, `ledger-mcp`, `ledger-config` |
|
||||
| `ledger-host` | the host and its leases, the agent bridge (`wanderbooks mcp`), tokens in 0600 files under the data root (D-63), the owner's commands, uploads and downloads, `update` and `rollback` (P11a) | `ledger-store`, `ledger-mcp`, `ledger-config` |
|
||||
| `ledger-gui` | the viewer: read-only, live, egui; the Books menu hands work to the server | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-package`, `ledger-vault`, `ledger-host` |
|
||||
| `ledger-cli` | `wanderbooks`, the one executable: every mode (`serve`, `server`, `host`, `mcp`, `gui`, `setup`, `books`, `token`, `connect`, `doctor`, …) and the over-the-wire test suites | everything |
|
||||
| `bookspec/checker`, `bookspec/runner` | the example schema and parser, the rule catalogue, the `Engine` trait; the per-rule runner | nothing of ours (the adapter in `ledger-core`'s tests depends on them) |
|
||||
@@ -313,3 +313,43 @@ still run on the server). The recipe, the head check for the move and the
|
||||
two-account CI job are in `deploy/README.md`, `deploy/wanderbooks-server.service`
|
||||
and `.github/workflows/two-user.yml`; the checks are
|
||||
`crates/ledger-cli/tests/two_user.rs`.
|
||||
|
||||
## Packaging and updates (`ledger-host`'s `update.rs`, `deploy/packaging/`, P11a)
|
||||
|
||||
One program, installed one of two ways, updated one of two ways
|
||||
(plan D-24). The install says which: a package ships
|
||||
`share/wanderbooks/install-method` beside `bin/`, and a file there makes
|
||||
the program package-managed; `wanderbooks update` and `rollback` refuse it
|
||||
and name the manager (apt, dnf and the AUR keep every release, so
|
||||
downgrading is theirs). Anything else (an AppImage, whose file is named by
|
||||
`$APPIMAGE`; an executable put somewhere by hand) updates itself:
|
||||
|
||||
- the feed is a `manifest.json` (a version, and per platform a file's
|
||||
address, sha256 and minisign signature; the shape `cargo-packager`'s
|
||||
updater reads, with the sha256 added) at GitHub Releases' fixed address
|
||||
(D-26); `--feed` reads another, and only with a `file://` feed may
|
||||
`--trusted-key` name the key;
|
||||
- the key a release is checked against is compiled in
|
||||
(`WANDERBOOKS_RELEASE_PUBKEY`, set by the release workflow once the
|
||||
owner's key exists; step 5): a build without one updates from nothing;
|
||||
- a download is accepted only if its sha256 matches AND its signature
|
||||
verifies; then it is staged, the running version kept under
|
||||
`<root>/updates/previous/` with the journal format it understood, and the
|
||||
file replaced by a rename of a complete copy made beside it;
|
||||
- nothing tells the books to stop. The host notices its executable's file
|
||||
was replaced and restarts as it does for a package upgrade (host.rs
|
||||
INVARIANT 7), finishing calls in progress; bridges reconnect upstream
|
||||
without the agent noticing. The format gate stays the server's (3.9):
|
||||
`rollback` refuses while a book declares a format or feature the kept
|
||||
version does not know;
|
||||
- an AppImage is the exception to the restart: the host runs from the old
|
||||
image's mount, whose path does not change, so it keeps running the old
|
||||
version until the books are next closed and opened (docs/packaging.md).
|
||||
|
||||
`deploy/packaging/` holds the Linux packaging: `packager.toml`
|
||||
(cargo-packager: `.deb`, AppImage, the pacman tarball with its PKGBUILD),
|
||||
the rpm table in `crates/ledger-cli/Cargo.toml`, `aur/PKGBUILD` (the AUR
|
||||
package, which repacks the release's tarball), `build-linux.sh`,
|
||||
`repo-indexes.sh` (the apt and dnf indexes), `local-release.sh` (a
|
||||
throwaway-keyed feed on this machine) and `test-linux-packages.sh`.
|
||||
`.github/workflows/release.yml` builds them on a version tag.
|
||||
+133
-15
@@ -1,23 +1,141 @@
|
||||
# Packaging and updates: the trial (P11a step 1)
|
||||
|
||||
Status 2026-10-29: **the trial has not been run.** It needs clean Linux,
|
||||
macOS and Windows machines for the six formats (`.deb`, `.rpm`, AUR,
|
||||
AppImage, `.dmg`, NSIS `.exe`), and the one machine that built step 0 is a
|
||||
Linux desktop with neither a macOS nor a Windows target, no container
|
||||
runtime and none of the packager tools installed. The tools are pinned in
|
||||
`mise.toml` now (`cargo-packager` 0.11.8, `cargo-packager-updater` 0.2.3,
|
||||
`cargo-generate-rpm` 0.21.1), so the trial is `mise install` and the VMs.
|
||||
Nothing below is a result; it is what is known before the trial, and the
|
||||
table is filled by the person who runs it.
|
||||
Status 2026-10-29: **the Linux half of the trial is run** (on the Arch
|
||||
desktop that builds the project, with Debian, Fedora and Arch containers
|
||||
for the installs); **the macOS and Windows halves are not**: they need
|
||||
those machines (and for the `.dmg` and the NSIS `.exe`, the signing
|
||||
identities of step 5), and this machine has neither a macOS nor a Windows
|
||||
target. `cargo-packager` 0.11.8 and `cargo-generate-rpm` 0.21.1 are pinned in
|
||||
`mise.toml`; `cargo-packager-updater` is **not** pinned: it is a library
|
||||
(the program checks releases itself, `crates/ledger-host/src/update.rs`),
|
||||
not a tool, so there is nothing for a recipe to call.
|
||||
|
||||
| format | built by | installs as | updated by | signed by |
|
||||
|---|---|---|---|---|
|
||||
| `.deb` | `cargo packager` | (trial) | apt repository (step 3) | (trial) |
|
||||
| `.rpm` | `cargo-generate-rpm` | (trial) | dnf repository (step 3) | (trial) |
|
||||
| AUR `PKGBUILD` | hand-written | (trial) | the package manager | n/a |
|
||||
| AppImage | `cargo packager` | (trial) | `cargo-packager-updater` | (trial) |
|
||||
| `.dmg` | `cargo packager` | (trial) | `cargo-packager-updater` | Developer ID (step 5) |
|
||||
| NSIS `.exe` | `cargo packager` | (trial) | `cargo-packager-updater` | Windows identity (step 5) |
|
||||
| `.deb` | `cargo packager` (`deb`) | `/usr/bin/wanderbooks`, a menu entry, `/usr/share/wanderbooks/install-method` = `deb`; 47 MB | apt repository (`repo-indexes.sh apt`, GitHub Pages) | unsigned until step 5 (the repository's index is `trusted=yes` in the test) |
|
||||
| `.rpm` | `cargo-generate-rpm` (table in `crates/ledger-cli/Cargo.toml`) | same paths, marker `rpm`; 36 MB | dnf repository (`repo-indexes.sh dnf`) | unsigned until step 5 (`--signing-key` takes the PGP key then) |
|
||||
| AUR `PKGBUILD` | `cargo packager` makes the tarball (`pacman` format) and a PKGBUILD for it; ours is `deploy/packaging/aur/PKGBUILD`, which repacks the release's tarball (package `wanderbooks-bin`) | same paths, marker `aur`; built with `makepkg` | pacman (the AUR keeps old PKGBUILDs) | n/a (pacman trusts the AUR's checksums) |
|
||||
| AppImage | `cargo packager` (`appimage`); 44 MB | one file the owner puts anywhere and runs; needs no admin password | `wanderbooks update` (`$APPIMAGE` is the file replaced) against the manifest; minisign | minisign by the release key (step 5) |
|
||||
| `.dmg` | `cargo packager` (`dmg`) | (trial) needs a Mac | `wanderbooks update` | Developer ID and notarization (step 5) |
|
||||
| NSIS `.exe` | `cargo packager` (`nsis`) | (trial) needs Windows, and native Windows is unit P11c (D-62) | `wanderbooks update` | the Windows identity (step 5) |
|
||||
|
||||
`just package-linux` builds the first four (`deploy/packaging/build-linux.sh`,
|
||||
about a minute after the release build, itself 8 to 12 minutes on a
|
||||
loaded 16-core machine); `just test-linux-packages` is the install-and-upgrade test.
|
||||
|
||||
## Linux results (2026-10-29)
|
||||
|
||||
What the trial found, each of which is built around now:
|
||||
|
||||
1. **A program linked here does not start on Debian.** This machine's
|
||||
glibc is 2.44; the binary asks for `GLIBC_2.43` and Debian 13 (trixie)
|
||||
has 2.41. A package must be built on the oldest system it claims.
|
||||
`.github/workflows/release.yml` builds on `ubuntu-24.04` (glibc 2.39);
|
||||
`just release-trixie` builds in `rust:1.99-trixie` for the local test. The
|
||||
claim is therefore "Debian 13, Ubuntu 24.04 and newer, current Fedora and
|
||||
Arch"; Debian 12 and Ubuntu 22.04 are not claimed (they would need a
|
||||
build container of their own).
|
||||
2. **The books refuse to run under a seccomp filter** (`host.rs`
|
||||
INVARIANT 2), and Docker's default profile is one: in a container the
|
||||
host fails to start ("refusing to run under a seccomp filter"). The
|
||||
tests run containers with `--security-opt seccomp=unconfined`. Anyone
|
||||
running the books in Docker meets this; it is not a bug of the packages.
|
||||
3. **An AppImage's launcher runs the desktop file's `Exec` line and appends
|
||||
the arguments it was given.** With `Exec=wanderbooks gui`,
|
||||
`Wanderbooks.AppImage update` ran `wanderbooks gui update`. The desktop
|
||||
files say plain `Exec=wanderbooks`, and a launch with nothing to say and
|
||||
no terminal is the viewer (`main.rs::is_bare_launch`); at a terminal
|
||||
it is still the usage. So the AppImage is also the command line:
|
||||
`Wanderbooks.AppImage update`, `... mcp --book acme`.
|
||||
4. **cargo-packager's configuration** (0.11.8): paths in a config are
|
||||
relative to the *config file*, not the working directory (the build script
|
||||
writes an absolute-path copy); `files` maps *source to destination*;
|
||||
`category` is a fixed list (`Finance`); the AppImage needs a square icon
|
||||
(`deploy/packaging/icons/512x512.png`, **a placeholder the owner should
|
||||
replace**); the `pacman` format yields the tarball and PKGBUILD but not a
|
||||
package (that is `makepkg`'s); its `.deb` has `Depends` from the config.
|
||||
5. **The AppImage tools are downloaded when it is built** (`AppRun`,
|
||||
`linuxdeploy` and its AppImage plugin from tauri-apps' and linuxdeploy's
|
||||
GitHub releases, unverified by cargo-packager): a supply-chain edge of
|
||||
the release build, not of the installed app. They run with
|
||||
`APPIMAGE_EXTRACT_AND_RUN=1`, so the build needs no FUSE.
|
||||
6. **`cargo packager signer` signs in a format `update` verifies.** Its
|
||||
key and its `.sig` are the base64 of minisign's two-line text; the
|
||||
manifest's `signature` is that `.sig` as written, and `update` reads the
|
||||
public key in either form. Checked end to end by hand (below), and by
|
||||
`a_public_key_is_read_in_every_form_minisign_and_the_packager_write_it`.
|
||||
7. **The AppImage updates itself but the books it holds do not restart
|
||||
onto the new image.** `update` replaces `$APPIMAGE`, and an AppImage run
|
||||
from a shell (`Wanderbooks.AppImage update`, or the one that was running)
|
||||
proves the swap and the rollback: after `update`, the AppImage on disk
|
||||
is the new file, the old one is kept, and `rollback` restores it. But the
|
||||
host that is open runs from the old image's mount
|
||||
(`/tmp/.mount_*/usr/bin/wanderbooks`), a path that does not change, so
|
||||
`host.rs` never sees a replaced file and the open books keep the old
|
||||
version until they are closed and opened again (`wanderbooks close`).
|
||||
Fixing it means the host learning the image's path (its environment is
|
||||
scrubbed on purpose; `APPIMAGE` would join the allow-list of `start.rs`,
|
||||
or the path would come from the mount table) and starting its successor
|
||||
from it: a decision about what the host may trust, left to the EM (the
|
||||
unit's report names it). Package installs and a hand-placed executable
|
||||
restart as designed (`bridge_survives_update`).
|
||||
8. **Onboarding with no terminal does not exist yet.** The unit's Done-when
|
||||
(1) says an AppImage "opens, onboards and posts an entry with no
|
||||
terminal". The AppImage opens (a bare launch is the viewer), but the viewer
|
||||
opens only an existing book (`ledger_gui::book_in_root`), and a data root
|
||||
and a first book come from `wanderbooks setup` and `books create`, which
|
||||
need a terminal. A first-run path in the viewer ("New books…" is in its
|
||||
menu, but the menu is not reachable until a book is open) is not in P11a's
|
||||
steps. It is the gap between this wave's AppImage and Done-when (1).
|
||||
|
||||
By hand, on this machine, against a throwaway release folder made by `just
|
||||
local-release` (a key from `cargo packager signer generate`; the feed
|
||||
`file://…/manifest.json`; a scratch home made by `wanderbooks setup --home`,
|
||||
nothing of the owner's):
|
||||
|
||||
```text
|
||||
Wanderbooks.AppImage --help -> the usage (FUSE mount, and with APPIMAGE_EXTRACT_AND_RUN=1)
|
||||
Wanderbooks.AppImage setup --home H -> the private folder; books create acme -> books list: "acme open"
|
||||
Wanderbooks.AppImage update --check --feed F --trusted-key K
|
||||
-> "wanderbooks 0.2.0 is available (this is 0.1.0)"
|
||||
Wanderbooks.AppImage update --feed F --trusted-key K
|
||||
-> "Updated wanderbooks from 0.1.0 to 0.2.0."; the file's sha256
|
||||
is the release's; updates/previous/ holds the 0.1.0 image
|
||||
Wanderbooks.AppImage rollback -> "Went back to wanderbooks 0.1.0."; the file is the original again
|
||||
```
|
||||
|
||||
`linux_packages_install_and_upgrade` (`deploy/packaging/test-linux-packages.sh`),
|
||||
2026-10-29, 0.1.0 then 0.1.1, all three passing: in `debian:trixie-slim`
|
||||
and `fedora:latest` the package installs from a repository made by
|
||||
`repo-indexes.sh` (the release workflow runs the same script), in
|
||||
`archlinux:latest` from `makepkg` over `deploy/packaging/aur/PKGBUILD`; then
|
||||
books are made as an ordinary user and held open, 0.1.1 is added and
|
||||
upgraded to by the package manager (`apt-get install --only-upgrade`, `dnf
|
||||
upgrade`, `pacman -U`), the host restarts onto the new file (a new pid whose
|
||||
`/proc/PID/exe` is not deleted), the journal's last line (the head) is
|
||||
byte-for-byte unchanged, and `wanderbooks update` exits non-zero naming the
|
||||
package manager. Not tested: Ubuntu, openSUSE, a package-manager
|
||||
*downgrade* (the repositories keep every release by construction), and the
|
||||
`.rpm` and `.deb` under their real signatures (step 5).
|
||||
|
||||
## What `update` and `rollback` need from a release
|
||||
|
||||
`manifest.json` at `releases/latest/download/` (D-26):
|
||||
|
||||
```json
|
||||
{ "version": "0.2.0", "notes": "…",
|
||||
"platforms": { "linux-x86_64": { "url": "wanderbooks-0.2.0-linux-x86_64",
|
||||
"sha256": "…hex…", "signature": "…base64 of the .sig file…" } } }
|
||||
```
|
||||
|
||||
`url` is absolute or relative to the manifest; the platform key is
|
||||
`std::env::consts::OS-ARCH`; the file is the whole program (the AppImage
|
||||
on Linux). The program checks the version is higher, the sha256, and the
|
||||
minisign signature against `WANDERBOOKS_RELEASE_PUBKEY` (compiled in by the
|
||||
release workflow once the owner has a key: **step 5, Q-4**; today no build
|
||||
carries one, so a build updates only from a `file://` feed with
|
||||
`--trusted-key`). The two-key release manifest of D-25 would wrap this
|
||||
(rotation, expiry, a monotone version) and is step 5's.
|
||||
|
||||
## What step 0 found about the platforms (read before the macOS and Windows rows)
|
||||
|
||||
|
||||
@@ -3669,3 +3669,79 @@ it); the digest's `since_seq` comparison (`>`), its `as_of` bound, the
|
||||
`zero_net_accounts` branch and the `never_reconciled` split;
|
||||
`report_status`'s three open conditions; the open-drafts refusal's
|
||||
`<= as_of` and its decision; the attention `awaiting_evidence` branch.
|
||||
|
||||
## P11a steps 2 and 3: update, rollback, the Linux packages (2026-10-29)
|
||||
|
||||
`wanderbooks update` and `rollback` (`ledger-host/src/update.rs`) are
|
||||
tested over a local release folder (a `file://` feed) and a minisign key
|
||||
the test makes, with real programs: each test makes a home, a stripped
|
||||
copy of the program in its `bin/`, and a manifest naming a newer copy of
|
||||
it (the same program with a tail, so its hash differs). All in
|
||||
`crates/ledger-cli/tests/update.rs` (Linux only):
|
||||
|
||||
- `an_update_replaces_the_program_keeps_the_old_one_and_rollback_brings_it_back`:
|
||||
no key and no feed is refused ("no release key"); the same version is "the
|
||||
newest"; an older offer is refused and nothing is kept; an update puts
|
||||
the new bytes in place, keeps the old under `updates/previous/` with the
|
||||
format it understood, leaves no temporary or staged file; rollback puts
|
||||
the old bytes back and consumes what was kept; a second rollback says
|
||||
there is nothing to go back to.
|
||||
- `update_is_atomic`: a reader polling the program file all through the
|
||||
update sees, on every read, the old file whole or the new whole.
|
||||
- `failed_update_rolls_back`: a validly signed file that does not start
|
||||
(`exit 3`) is swapped in, fails `--help`, and the old program is put
|
||||
back; nothing is staged or left beside the program.
|
||||
- `unsigned_update_refused`: five bad manifests (a good signature by
|
||||
another key; a signature of other bytes; a sha256 that differs; an empty
|
||||
signature; a signature that is not one), each refused with the program
|
||||
unchanged and nothing kept or staged; `--trusted-key` with an `https`
|
||||
feed is refused.
|
||||
- `package_managed_install_refuses_update`: a
|
||||
`share/wanderbooks/install-method` marker beside `bin/` makes both
|
||||
commands refuse, naming the manager, with nothing made in the data root.
|
||||
- `rollback_refuses_after_a_book_consented_to_a_newer_format`: with a
|
||||
book that declares this version's format and a kept version that knows
|
||||
one feature less, rollback refuses and the program stays; with the kept
|
||||
version knowing everything the book declares, it goes back.
|
||||
- `bridge_survives_update` and `update_waits_for_a_running_call`: an
|
||||
agent's bridge session writes without pause while `update` runs and the
|
||||
host restarts onto the new file; every write is answered and made once
|
||||
(the account is in the chart exactly once), the session needs no
|
||||
reconnect, its tool list is unchanged, and the host and server run the
|
||||
file now on disk (not a deleted one). The host's own restart laws stay
|
||||
`open_while_held.rs`'s (`a_restart_is_not_a_close`).
|
||||
|
||||
Unit tests in `update.rs`: `versions_are_three_numbers_and_order_by_number`,
|
||||
`a_package_marker_beside_the_program_makes_it_package_managed`,
|
||||
`a_manifest_address_is_resolved_beside_the_manifest`,
|
||||
`a_swap_leaves_the_whole_new_file_and_no_temporary`,
|
||||
`a_public_key_is_read_in_every_form_minisign_and_the_packager_write_it`.
|
||||
`main.rs`: `only_nothing_at_all_with_no_terminal_is_the_viewer` (the bare
|
||||
launch an AppImage's launcher makes; it cannot be run as a test, because the
|
||||
viewer finds the account's real data root from the password database).
|
||||
|
||||
Not tests, run by hand on this machine and recorded in `docs/packaging.md`:
|
||||
the AppImage updating and rolling back itself against a feed signed by
|
||||
`cargo packager signer` (`just local-release`), which is the check that the
|
||||
packager's signature format is the one `update` verifies.
|
||||
|
||||
**`linux_packages_install_and_upgrade`** is `deploy/packaging/test-linux-packages.sh`
|
||||
(`just test-linux-packages`, needs docker; not part of `just check`): in a
|
||||
clean Debian, Fedora and Arch container it installs release 0.1.0 (Debian
|
||||
and Fedora from an apt and a dnf repository made by `repo-indexes.sh`, the
|
||||
same script the release workflow runs; Arch by `makepkg` from the
|
||||
packager's PKGBUILD), makes books as an ordinary user, holds them open,
|
||||
adds 0.1.1 to the repository and upgrades; then checks the host restarted
|
||||
onto the new file, `wanderbooks books list` is unchanged, and
|
||||
`wanderbooks update` refuses and names the package manager. The programs
|
||||
are built in a `rust:1.99-trixie` container (`just release-trixie`):
|
||||
see `docs/packaging.md` for why the build machine's own binary is not used.
|
||||
|
||||
**For P12 (mutation targets, none run, D-33):** `update.rs`'s `verify`
|
||||
(a mutant that drops the sha check or the signature check must die on
|
||||
`unsigned_update_refused`'s sha and key cases), `refuse_if_consented`'s
|
||||
two comparisons (`rollback_refuses_after_a_book_consented_to_a_newer_format`
|
||||
covers the feature one; a case with a higher format number is a gap to
|
||||
add), `swap_in`'s temporary-then-rename (`update_is_atomic`), `healthy`
|
||||
(`failed_update_rolls_back`), `install_kind` (the marker test), and
|
||||
`parse_version`'s rejections.
|
||||
@@ -263,3 +263,35 @@ deploy: site
|
||||
# Deploy a preview of the website and print its URL
|
||||
deploy-preview: site
|
||||
{{netlify}} deploy --dir site/dist --no-build
|
||||
|
||||
# The Linux packages (P11a step 3), in target/packages/VERSION. Builds the
|
||||
# release program first; needs the tools `mise install` pins. A VERSION other
|
||||
# than the program's repackages the same program under it (the upgrade
|
||||
# test's second release).
|
||||
# Build the AppImage, .deb, pacman tarball and .rpm
|
||||
package-linux version="" formats="deb,appimage,pacman":
|
||||
cargo build --release -p ledger-cli
|
||||
deploy/packaging/build-linux.sh {{version}} {{formats}}
|
||||
|
||||
# A release folder on this machine signed with a throwaway key; then
|
||||
# `wanderbooks update --feed file://DIR/manifest.json --trusted-key DIR/release.pub`
|
||||
# Make a local release feed to try `wanderbooks update` against
|
||||
local-release file version dir:
|
||||
deploy/packaging/local-release.sh {{file}} {{version}} {{dir}}
|
||||
|
||||
# A program linked here does not start on Debian (docs/packaging.md); this
|
||||
# builds it in rust:1.99-trixie, into target/container. Needs docker.
|
||||
# Build the release program in a Debian trixie container
|
||||
release-trixie:
|
||||
mkdir -p target/container
|
||||
docker run --rm --user "$(id -u):$(id -g)" -e HOME=/tmp -e CARGO_HOME=/tmp/cargo-home -e CARGO_TARGET_DIR=/target -v "$PWD:/src:ro" -v "$PWD/target/container:/target" -w /src rust:1.99-trixie cargo build --release --locked -p ledger-cli
|
||||
|
||||
# Install each Linux package in a clean Arch, Debian and Fedora container,
|
||||
# open the books, upgrade to the next release, and check the books' head is
|
||||
# unchanged and the open books restarted onto the new program. Builds the
|
||||
# program in a trixie container, then releases 0.1.0 and 0.1.1 of it.
|
||||
# Install and upgrade the Linux packages in Arch, Debian and Fedora containers
|
||||
test-linux-packages: release-trixie
|
||||
WB_PROGRAM=target/container/release/wanderbooks deploy/packaging/build-linux.sh 0.1.0 deb,pacman
|
||||
WB_PROGRAM=target/container/release/wanderbooks deploy/packaging/build-linux.sh 0.1.1 deb,pacman
|
||||
deploy/packaging/test-linux-packages.sh
|
||||
@@ -23,3 +23,7 @@ node = "26"
|
||||
# A compile cache shared by every jj workspace's target dir: point
|
||||
# cargo's build.rustc-wrapper at it (~/.cargo/config.toml).
|
||||
sccache = "0.18.0"
|
||||
# `just package-linux` (docs/packaging.md): the AppImage and .deb by
|
||||
# cargo-packager, the .rpm by cargo-generate-rpm (D-25).
|
||||
"cargo:cargo-packager" = "0.11.8"
|
||||
"cargo:cargo-generate-rpm" = "0.21.1"
|
||||
Reference in new issue
Block a user