diff --git a/.github/workflows/aur.yml b/.github/workflows/aur.yml new file mode 100644 index 0000000..1f65448 --- /dev/null +++ b/.github/workflows/aur.yml @@ -0,0 +1,80 @@ +name: AUR + +# Nightly, and on demand: when the latest release differs from the version of the AUR package that the repository +# variable AUR_PACKAGE names, update that package to the release from an Arch container. Until the variable is set, +# nothing runs. The SSH key is a secret of the aur environment, deployable from main only. GitHub turns scheduled +# workflows off after 60 days without activity in a public repository; Actions shows how to turn this one on again. +on: + schedule: + - cron: '17 9 * * *' + workflow_dispatch: + +concurrency: + group: aur + cancel-in-progress: false + +permissions: + contents: read + +jobs: + check: + if: vars.AUR_PACKAGE != '' + runs-on: ubuntu-latest + timeout-minutes: 10 + outputs: + version: ${{ steps.compare.outputs.version }} + sha256: ${{ steps.compare.outputs.sha256 }} + steps: + - name: Compare the latest release with the AUR package + id: compare + env: + GH_TOKEN: ${{ github.token }} + PACKAGE: ${{ vars.AUR_PACKAGE }} + run: | + tag=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName --jq .tagName) + aur=$(curl -fsS "https://aur.archlinux.org/rpc/v5/info?arg[]=$PACKAGE" | jq -r '.results[0].Version // ""') + echo "latest release $tag, AUR $PACKAGE ${aur:-not found}" + if [ "${aur%-*}" != "${tag#v}" ]; then + sha=$(gh release download "$tag" --repo "$GITHUB_REPOSITORY" --pattern '*.tar.gz.sha256' --output - | cut -d' ' -f1) + test "${#sha}" = 64 + echo "version=$tag" >> "$GITHUB_OUTPUT" + echo "sha256=$sha" >> "$GITHUB_OUTPUT" + fi + + publish: + needs: check + if: needs.check.outputs.version != '' + runs-on: ubuntu-latest + environment: aur + container: archlinux:base-devel + timeout-minutes: 30 + steps: + - name: Install tools + run: pacman -Syu --noconfirm --needed git openssh + + - name: Checkout + uses: actions/checkout@v4 + + - name: Update the AUR package + env: + AUR_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }} + PACKAGE: ${{ vars.AUR_PACKAGE }} + VERSION: ${{ needs.check.outputs.version }} + SHA256: ${{ needs.check.outputs.sha256 }} + run: | + useradd -m builder + home=~builder + install -d -m 700 "$home/.ssh" + printf '%s\n' "$AUR_KEY" > "$home/.ssh/aur" + chmod 600 "$home/.ssh/aur" + # The AUR's ED25519 host key, matching the fingerprint aur.archlinux.org publishes. + echo 'aur.archlinux.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEuBKrPzbawxA/k2g6NcyV5jmqwJ2s+zpgZGZ7tpLIcN' \ + > "$home/.ssh/known_hosts" + printf 'Host aur.archlinux.org\n User aur\n IdentityFile ~/.ssh/aur\n IdentitiesOnly yes\n StrictHostKeyChecking yes\n' \ + > "$home/.ssh/config" + cp aur.sh "$home/aur.sh" + chown -R builder: "$home" + runuser -u builder -- env HOME="$home" bash -c "cd ~ && git clone -q ssh://aur@aur.archlinux.org/$PACKAGE.git package \ + && git -C package config user.name jbsco \ + && git -C package config user.email 90524106+Jbsco@users.noreply.github.com \ + && ./aur.sh package ${VERSION#v} $SHA256 --push" diff --git a/README.md b/README.md index b0a8db4..43e5e9f 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Every coded stream is decoded again and compared sample for sample. - `haskell/src/BlockCodec.hs`, `Stream.hs`, `Checksum.hs`, `RangeCoder.hs`: block codec, stream, CRC-16 and range coder in Haskell, groups coded in parallel. `haskell/hybrid/`: same stream around the SPARK library. `haskell/src/Blocks.hs`, `Tiers.hs`: parallel versions of experiment schemes. - `corpus/`: test files, `make_corpus.sh` and `SHA256SUMS`. - `extra.sh`: the codec on the wider corpus in `corpus/extra/`, results in `results/extra.tsv`. -- `release.sh`, `.github/workflows/release.yml`: release package and its publication from a version tag. +- `release.sh`, `.github/workflows/release.yml`: release package and its publication from a version tag. `aur.sh`: AUR package update to a release. - `seek_timing.sh` with `capi/seek_bench.c`: seek times through the FLAC, WavPack and block codec libraries, results in `results/seek_timing.tsv`. - `run.sh`, `compare.sh`, `bench.sh`, `tool_timing.sh`, `levels.sh`, `segments.sh`, `multichannel.sh`, `sizes.sh`, `tables.sh`: every coder, common lossless tools, timing, timing against FLAC and WavPack, encoder levels, segment lengths, a four-channel file, tool sizes and tables. Output in `results/`. - `vectors/`: format version 2 test streams, intact and damaged, with a manifest of decoded MD5s and `check.sh` to test a decoder; `edge_audio.py` writes edge-case inputs for the encoder. @@ -388,6 +388,14 @@ The library builds the units proved free of run-time errors without run-time che Once the repository variable `RELEASE_NAME` is set, every merge to main runs `.github/workflows/release.yml` on a hosted runner. It tags the merge as the next version, runs `release.sh` with that name, and publishes a GitHub release with generated notes. Releases are numbered from v0.1.0, and each one raises the last number only: v0.1.1, v0.1.2, and on past v0.1.9 to v0.1.10. +On Arch Linux the AUR package `blockcodec-bin` installs a release's programs, library, header and documents: + + yay -S blockcodec-bin + +Or clone `https://aur.archlinux.org/blockcodec-bin.git` and run `makepkg -si` in it. + +With the repository variable `AUR_PACKAGE` set, `.github/workflows/aur.yml` checks every night whether the latest release is newer than that package, and can also be started by hand. When it is, `aur.sh` runs in an Arch container to set the version and SHA-256, write `.SRCINFO` and build the package from the release before it pushes. Its SSH key is a secret of the `aur` environment, which only main can deploy, and the AUR's host key is pinned. GitHub turns scheduled workflows off after 60 days without activity in a public repository, and Actions shows how to turn this one on again. + ## References - RFC 1951, DEFLATE: canonical Huffman codes, section 3.2.2. https://www.rfc-editor.org/rfc/rfc1951 diff --git a/aur.sh b/aur.sh new file mode 100755 index 0000000..bf77e0b --- /dev/null +++ b/aur.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Update a clone of an AUR package to a release: pkgver, pkgrel 1 and the release tarball's sha256 in the PKGBUILD, +# .SRCINFO written again, the package built from the release to check it, and the change committed. With --push the +# commit goes to the clone's origin. Runs as a user that may run makepkg, not root. +# Usage: aur.sh [--push] +set -euo pipefail +dir=$1 version=$2 sha=$3 push=${4:-} +cd "$dir" +name=$(sed -n 's/^pkgname=//p' PKGBUILD) +if [ "$(sed -n 's/^pkgver=//p' PKGBUILD)" = "$version" ] && grep -qx "sha256sums=('$sha')" PKGBUILD; then + echo "aur.sh: $name $version is already packaged" + exit 0 +fi +sed -i -e "s/^pkgver=.*/pkgver=$version/" -e "s/^pkgrel=.*/pkgrel=1/" -e "s/^sha256sums=(.*)$/sha256sums=('$sha')/" PKGBUILD +grep -qx "sha256sums=('$sha')" PKGBUILD +makepkg --printsrcinfo > .SRCINFO +work=$(mktemp -d -p "${TMPDIR:-/var/tmp}") +trap 'rm -rf "$work"' EXIT +if ! BUILDDIR=$work/build SRCDEST=$work/src PKGDEST=$work/out makepkg -f --noconfirm > "$work/makepkg.log" 2>&1; then + cat "$work/makepkg.log" + exit 1 +fi +git add PKGBUILD .SRCINFO +git commit -q -m "Update $name to $version" +echo "aur.sh: $name $version built and committed" +if [ "$push" = --push ]; then + git push -q origin HEAD:master + echo "aur.sh: pushed" +fi