diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index 19f8839..800af22 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -8,9 +8,8 @@ on: push: branches: [main] paths: - - '*/PKGBUILD' - - '*/pkg.sh' - - 'scripts/**' + # any package file (PKGBUILD, pkg.sh, .desktop, ...) and the shared script + - '*/*' - '.github/workflows/update.yml' permissions: diff --git a/.gitignore b/.gitignore index 7fae042..badc302 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # makepkg build leftovers and downloaded/built artifacts *.tar.zst +*.tar.gz *.pkg.tar.* */src/ */pkg/ diff --git a/README.md b/README.md index 76257d3..134b60b 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ users don't need any build dependencies. | Package | Upstream | AUR | |---|---|---| | `timetable-bin` | [ostfriese4/untis](https://codeberg.org/ostfriese4/untis) — "Timetable", a GTK4 + LibAdwaita client for WebUntis | [timetable-bin](https://aur.archlinux.org/packages/timetable-bin) | +| `fluxer-bin` | [fluxer.app](https://fluxer.app) — Fluxer desktop client (Electron) | [fluxer-bin](https://aur.archlinux.org/packages/fluxer-bin) | ## Setup (one-time) @@ -44,12 +45,21 @@ Create a new directory named after the AUR package containing: - **`PKGBUILD`** — sources the prebuilt asset from `https://github.com/Felitendo/PKGBUILDS/releases/download/-/-.tar.zst`. `pkgver`, `pkgrel` and `sha256sums` are maintained by CI. -- **`pkg.sh`** — bash sourced by [scripts/update-package.sh](scripts/update-package.sh), - providing: - - `BUILD_DEPS` — array of Arch packages installed before building, - - `latest_version` — prints the latest upstream version (no `v` prefix), - - `build_artifact ` — downloads/builds upstream and - writes the install tree (a tarball containing `usr/`) to ``. +- **`pkg.sh`** — bash sourced by [scripts/update-package.sh](scripts/update-package.sh). + Always provides `latest_version` (prints the latest upstream version, no + `v` prefix), plus one of two modes: + - *upstream has no binaries* (e.g. `timetable-bin`): define + `build_artifact ` (build upstream and write the + install tree as a tarball containing `usr/`) and `BUILD_DEPS` (array of + Arch packages needed to build). CI hosts the result as a GitHub release + asset which the PKGBUILD downloads. + - *upstream hosts binaries* (e.g. `fluxer-bin`): define + `refresh_checksums ` which updates the + `sha256sums*` lines for the new version. The PKGBUILD sources upstream + URLs directly and nothing is hosted here. + + Other local source files in the directory (`.desktop` files, etc.) are + pushed to the AUR alongside `PKGBUILD` and `.SRCINFO`. The workflow discovers package directories automatically. Trigger a run manually via *Actions → Update AUR packages → Run workflow* to publish it diff --git a/fluxer-bin/.SRCINFO b/fluxer-bin/.SRCINFO new file mode 100644 index 0000000..3c106d8 --- /dev/null +++ b/fluxer-bin/.SRCINFO @@ -0,0 +1,20 @@ +pkgbase = fluxer-bin + pkgdesc = Fluxer Desktop Application + pkgver = 0.0.8 + pkgrel = 1 + url = https://fluxer.app + arch = x86_64 + arch = aarch64 + license = AGPL-3.0-only + depends = gtk3 + depends = nss + depends = alsa-lib + options = !strip + source = fluxer.desktop + sha256sums = 981daa8015b823fef254bb8e79fe6b28f77dda02cdc374796443bd64f5041de1 + source_x86_64 = fluxer-0.0.8-x64.tar.gz::https://api.fluxer.app/dl/desktop/stable/linux/x64/0.0.8/tar_gz + sha256sums_x86_64 = acf6398fa6810720fed85b06c011b324e7db4fec6bf2fc7ad93c2446c3600f2d + source_aarch64 = fluxer-0.0.8-arm64.tar.gz::https://api.fluxer.app/dl/desktop/stable/linux/arm64/0.0.8/tar_gz + sha256sums_aarch64 = 77b874a98caf48de5bc4ccf03119f45262fe26fd7be085b57d7b40b1505d0ec8 + +pkgname = fluxer-bin diff --git a/fluxer-bin/PKGBUILD b/fluxer-bin/PKGBUILD new file mode 100644 index 0000000..3d82d56 --- /dev/null +++ b/fluxer-bin/PKGBUILD @@ -0,0 +1,54 @@ +# Maintainer: Felitendo +# Contributor: Cosmo +# This PKGBUILD is updated automatically: +# https://github.com/Felitendo/PKGBUILDS + +pkgname=fluxer-bin +pkgver=0.0.8 +pkgrel=1 +pkgdesc="Fluxer Desktop Application" +arch=('x86_64' 'aarch64') +url="https://fluxer.app" +license=('AGPL-3.0-only') +depends=('gtk3' 'nss' 'alsa-lib') +options=('!strip') + +source=("fluxer.desktop") +sha256sums=('981daa8015b823fef254bb8e79fe6b28f77dda02cdc374796443bd64f5041de1') + +source_x86_64=("fluxer-${pkgver}-x64.tar.gz::https://api.fluxer.app/dl/desktop/stable/linux/x64/${pkgver}/tar_gz") +sha256sums_x86_64=('acf6398fa6810720fed85b06c011b324e7db4fec6bf2fc7ad93c2446c3600f2d') + +source_aarch64=("fluxer-${pkgver}-arm64.tar.gz::https://api.fluxer.app/dl/desktop/stable/linux/arm64/${pkgver}/tar_gz") +sha256sums_aarch64=('77b874a98caf48de5bc4ccf03119f45262fe26fd7be085b57d7b40b1505d0ec8') + +package() { + local _dir + case "$CARCH" in + x86_64) _dir="fluxer-stable-${pkgver}-x64" ;; + aarch64) _dir="fluxer-stable-${pkgver}-arm64" ;; + esac + # upstream has changed the archive layout before - fall back to a glob + if [ ! -d "$srcdir/$_dir" ]; then + _dir=$(cd "$srcdir" && ls -d [Ff]luxer*"${pkgver}"*/ 2>/dev/null | head -n1) + _dir="${_dir%/}" + fi + if [ -z "$_dir" ] || [ ! -d "$srcdir/$_dir" ]; then + echo "Error: could not find extracted directory for $CARCH" >&2 + ls -la "$srcdir" >&2 + return 1 + fi + + install -d "$pkgdir/opt/$pkgname" + cp -a "$srcdir/$_dir/." "$pkgdir/opt/$pkgname/" + + install -d "$pkgdir/usr/bin" + ln -s "/opt/$pkgname/fluxer" "$pkgdir/usr/bin/fluxer" + + install -Dm644 "$srcdir/fluxer.desktop" "$pkgdir/usr/share/applications/fluxer.desktop" + + if [ -f "$pkgdir/opt/$pkgname/resources/512x512.png" ]; then + install -Dm644 "$pkgdir/opt/$pkgname/resources/512x512.png" \ + "$pkgdir/usr/share/icons/hicolor/512x512/apps/fluxer.png" + fi +} diff --git a/fluxer-bin/fluxer.desktop b/fluxer-bin/fluxer.desktop new file mode 100644 index 0000000..40f47e1 --- /dev/null +++ b/fluxer-bin/fluxer.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=Fluxer +Comment=Fluxer Desktop App +Exec=/usr/bin/fluxer +Icon=fluxer +Terminal=false +Type=Application +Categories=Network; diff --git a/fluxer-bin/pkg.sh b/fluxer-bin/pkg.sh new file mode 100644 index 0000000..b523465 --- /dev/null +++ b/fluxer-bin/pkg.sh @@ -0,0 +1,30 @@ +# fluxer-bin - Fluxer Desktop (https://fluxer.app), an Electron app. +# +# Upstream hosts versioned prebuilt binaries itself, so there is no +# build_artifact() here: on a new version only pkgver and the checksums +# are refreshed and the result is pushed to the AUR. + +DL_BASE="https://api.fluxer.app/dl/desktop/stable/linux" + +latest_version() { + # the download API exposes the current version in the attachment filename, + # e.g. content-disposition: attachment; filename="fluxer-stable-0.0.8-x64.tar.gz" + curl -sfI "$DL_BASE/x64/latest/tar_gz" \ + | grep -oiP 'filename="fluxer-(stable-)?\K[0-9][^"]*(?=-x64\.tar\.gz)' +} + +# refresh_checksums +refresh_checksums() { + local ver="$1" pkgbuild="$2" + local sha_desktop sha_x64 sha_arm64 + + sha_desktop="$(sha256sum "$(dirname "$pkgbuild")/fluxer.desktop" | cut -d' ' -f1)" + sha_x64="$(curl -sfL "$DL_BASE/x64/$ver/tar_gz" | sha256sum | cut -d' ' -f1)" + sha_arm64="$(curl -sfL "$DL_BASE/arm64/$ver/tar_gz" | sha256sum | cut -d' ' -f1)" + + sed -i \ + -e "s|^sha256sums=.*|sha256sums=('$sha_desktop')|" \ + -e "s|^sha256sums_x86_64=.*|sha256sums_x86_64=('$sha_x64')|" \ + -e "s|^sha256sums_aarch64=.*|sha256sums_aarch64=('$sha_arm64')|" \ + "$pkgbuild" +} diff --git a/scripts/update-package.sh b/scripts/update-package.sh index 9038eb9..1c5ee9e 100644 --- a/scripts/update-package.sh +++ b/scripts/update-package.sh @@ -1,12 +1,15 @@ #!/usr/bin/env bash # Update one package directory: # 1. determine the latest upstream version (pkg.sh: latest_version) -# 2. build the binary artifact if the matching GitHub release asset is -# missing (pkg.sh: build_artifact), otherwise reuse the published one -# 3. refresh PKGBUILD (pkgver/pkgrel/sha256sums), test-build it with -# makepkg and regenerate .SRCINFO -# 4. commit changes back to this repository -# 5. push PKGBUILD + .SRCINFO to the AUR +# 2. bring the PKGBUILD up to date: +# - packages we build ourselves (pkg.sh defines build_artifact): make +# sure the GitHub release asset for that version exists - building and +# uploading it if necessary - and sync pkgver/sha256sums with it +# - packages prebuilt by upstream (no build_artifact): on a new version, +# set pkgver and let pkg.sh's refresh_checksums update the sums +# 3. if the PKGBUILD changed: set pkgrel and run a makepkg test build +# 4. regenerate .SRCINFO and commit changes back to this repository +# 5. push the package files to the AUR if it differs # # Requires: GH_TOKEN (GitHub release + repo push), AUR_SSH_PRIVATE_KEY. # Optional: AUR_GIT_NAME / AUR_GIT_EMAIL for the AUR commit identity. @@ -23,6 +26,7 @@ if [[ "${CI:-}" == "true" ]]; then git config --global --add safe.directory "$repo_root" fi +BUILD_DEPS=() source "$pkg/pkg.sh" ver="$(latest_version || true)" @@ -34,60 +38,81 @@ echo "$pkg: latest upstream version is $ver" oldver="$(grep -Po '^pkgver=\K.*' "$pkg/PKGBUILD")" oldrel="$(grep -Po '^pkgrel=\K.*' "$pkg/PKGBUILD")" -oldsha="$(grep -Po "^sha256sums=\('\K[0-9a-f]{64}" "$pkg/PKGBUILD" || true)" -tag="$pkg-$ver" -asset="$pkg-$ver.tar.zst" +### 2: bring the PKGBUILD up to date ######################################## -### 1+2: make sure the release asset exists, get a local copy of it ######### +if declare -f build_artifact >/dev/null; then + # We build the binary artifact and host it as a GitHub release asset. + tag="$pkg-$ver" + asset="$pkg-$ver.tar.zst" -if gh release view "$tag" --json assets -q '.assets[].name' 2>/dev/null | grep -qxF "$asset"; then - echo "$pkg: release $tag already contains $asset - reusing it" - gh release download "$tag" --pattern "$asset" --dir "$pkg" --clobber + if gh release view "$tag" --json assets -q '.assets[].name' 2>/dev/null | grep -qxF "$asset"; then + echo "$pkg: release $tag already contains $asset - reusing it" + gh release download "$tag" --pattern "$asset" --dir "$pkg" --clobber + else + echo "$pkg: building $asset" + if [[ "${CI:-}" == "true" && "${#BUILD_DEPS[@]}" -gt 0 ]]; then + pacman -S --noconfirm --needed "${BUILD_DEPS[@]}" + fi + build_artifact "$ver" "$repo_root/$pkg/$asset" + gh release view "$tag" >/dev/null 2>&1 || \ + gh release create "$tag" --title "$tag" \ + --notes "Automated build of $pkg $ver (upstream: ${UPSTREAM_REPO:-unknown})." + gh release upload "$tag" "$pkg/$asset" --clobber + fi + + sha="$(sha256sum "$pkg/$asset" | cut -d' ' -f1)" + sed -i \ + -e "s|^pkgver=.*|pkgver=$ver|" \ + -e "s|^sha256sums=.*|sha256sums=('$sha')|" \ + "$pkg/PKGBUILD" else - echo "$pkg: building $asset" - if [[ "${CI:-}" == "true" && "${#BUILD_DEPS[@]}" -gt 0 ]]; then - pacman -S --noconfirm --needed "${BUILD_DEPS[@]}" + # Upstream publishes the binaries itself; only refresh version + checksums. + if [[ "$ver" != "$oldver" ]]; then + sed -i "s|^pkgver=.*|pkgver=$ver|" "$pkg/PKGBUILD" + refresh_checksums "$ver" "$pkg/PKGBUILD" + else + echo "$pkg: $ver is current" fi - build_artifact "$ver" "$repo_root/$pkg/$asset" - gh release view "$tag" >/dev/null 2>&1 || \ - gh release create "$tag" --title "$tag" \ - --notes "Automated build of $pkg $ver (upstream: ${UPSTREAM_REPO:-unknown})." - gh release upload "$tag" "$pkg/$asset" --clobber fi -sha="$(sha256sum "$pkg/$asset" | cut -d' ' -f1)" +### 3: pkgrel + test build if the PKGBUILD changed ########################## -### 3: refresh PKGBUILD, test-build, regenerate .SRCINFO #################### +# makepkg refuses to run as root (the CI container), so hand it to an +# unprivileged user there. +run_makepkg() { + if [[ "$EUID" -eq 0 ]]; then + useradd -m builder 2>/dev/null || true + chown -R builder "$pkg" + (cd "$pkg" && runuser -u builder -- makepkg "$@") + else + (cd "$pkg" && makepkg "$@") + fi +} -if [[ "$ver" != "$oldver" ]]; then - rel=1 -elif [[ "$sha" != "$oldsha" ]]; then - rel=$((oldrel + 1)) -else +if git diff --quiet -- "$pkg/PKGBUILD"; then rel="$oldrel" -fi - -sed -i \ - -e "s|^pkgver=.*|pkgver=$ver|" \ - -e "s|^pkgrel=.*|pkgrel=$rel|" \ - -e "s|^sha256sums=.*|sha256sums=('$sha')|" \ - "$pkg/PKGBUILD" - -# makepkg refuses to run as root (the CI container), so hand the build to an -# unprivileged user there. -d: the runner only needs to package, not run. -if [[ "$EUID" -eq 0 ]]; then - useradd -m builder 2>/dev/null || true - chown -R builder "$pkg" - (cd "$pkg" && runuser -u builder -- makepkg -fdc) - (cd "$pkg" && runuser -u builder -- makepkg --printsrcinfo > .SRCINFO) - chown -R 0:0 "$pkg" else - (cd "$pkg" && makepkg -fdc) - (cd "$pkg" && makepkg --printsrcinfo > .SRCINFO) + if [[ "$ver" != "$oldver" ]]; then + rel=1 + else + rel=$((oldrel + 1)) + fi + sed -i "s|^pkgrel=.*|pkgrel=$rel|" "$pkg/PKGBUILD" + + # -d: the runner only needs to package, not run the result + run_makepkg -fdc + echo "$pkg: makepkg test build succeeded" fi -echo "$pkg: makepkg test build succeeded" -rm -f "$pkg/$asset" "$pkg"/*.pkg.tar.* + +# .SRCINFO regeneration is cheap - do it every run so it can never go stale +run_makepkg --printsrcinfo > "$pkg/.SRCINFO.new" +mv "$pkg/.SRCINFO.new" "$pkg/.SRCINFO" +[[ "$EUID" -eq 0 ]] && chown -R 0:0 "$pkg" + +# drop downloaded sources and build leftovers (all gitignored, never tracked) +rm -rf "$pkg/src" "$pkg/pkg" +rm -f "$pkg"/*.pkg.tar.* "$pkg"/*.tar.zst "$pkg"/*.tar.gz ### 4: commit back to this repository ######################################## @@ -126,12 +151,18 @@ export GIT_SSH_COMMAND="ssh -i $sshdir/key -o UserKnownHostsFile=$sshdir/known_h aurdir="$(mktemp -d)" git clone "ssh://aur@aur.archlinux.org/$pkg.git" "$aurdir" -cp "$pkg/PKGBUILD" "$pkg/.SRCINFO" "$aurdir/" + +# every tracked file of the package except our automation glue belongs on +# the AUR (PKGBUILD, .SRCINFO, .desktop files, .install files, ...) +while IFS= read -r f; do + [[ "$(basename "$f")" == "pkg.sh" ]] && continue + cp "$f" "$aurdir/" +done < <(git ls-files "$pkg") cd "$aurdir" git config user.name "${AUR_GIT_NAME:-Felitendo}" git config user.email "${AUR_GIT_EMAIL:-95575686+Felitendo@users.noreply.github.com}" -git add PKGBUILD .SRCINFO +git add -A if git diff --cached --quiet && [[ -n "$(git ls-remote origin)" ]]; then echo "$pkg: AUR package is already up to date" else