diff --git a/.gitea/workflows/pin-check.yaml b/.gitea/workflows/pin-check.yaml new file mode 100644 index 0000000..2e0c6f4 --- /dev/null +++ b/.gitea/workflows/pin-check.yaml @@ -0,0 +1,26 @@ +name: Upstream pin check + +on: + schedule: + - cron: "0 6 * * 1" # Mondays 06:00 UTC — catches upstream/Qt drift between ISO builds + workflow_dispatch: + push: + paths: + - "localrepo/end4-pkgbuilds/quickshell-git/PKGBUILD" + - "localrepo/check-quickshell-pin.sh" + - "airootfs/root/customize_airootfs.sh" + - ".gitea/workflows/pin-check.yaml" + +jobs: + quickshell-pin: + runs-on: archlinux + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + # Tripwire for the failure mode that broke ISO build run 137: + # a quickshell pin (ours or end-4's) that predates a Qt compat fix + # or has simply gone stale. Fails the job so the drift is visible + # in Actions instead of surfacing as a 3-hour ISO build failure. + - name: Check quickshell pins + run: ./localrepo/check-quickshell-pin.sh diff --git a/AGENTS.md b/AGENTS.md index eb9b11c..752ad22 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,6 +57,8 @@ install them into the target without the network. | `airootfs/usr/local/bin/alvin-install` | Installer: partitions, pacstrap, LUKS (systemd initramfs **or** experimental unl0kr + optional TPM2 unlock), user, git identity + GitHub SSH keys, login manager (none/greetd/sddm/gdm) + autologin, optional sshd (default on), end-4 dotfiles (`--skip-alldeps`), boot | | `localrepo/build-end4-deps.sh` | Non-interactive AUR builds for end-4 dependencies | | `localrepo/update.sh` | Regenerates localrepo DB, syncs names to packages.x86_64, syncs `airootfs/opt/localrepo/` | +| `localrepo/check-quickshell-pin.sh` | Tripwire: our quickshell pin and end-4's must include the Qt 6.12 fix and stay <45d old (`QUICKSHELL_PIN_MAX_AGE_DAYS` overrides) | +| `.gitea/workflows/pin-check.yaml` | Runs the pin check weekly (Mon 06:00), on dispatch, and on pushes touching pins/`customize_airootfs.sh` | ## alvin-install (installer inside the ISO) @@ -107,6 +109,7 @@ whitespace. - **end4-pC** (`pctrade/end4-pC`) is the default quickshell config: cloned into `/etc/skel/.config/quickshell/end4-pC` at build time, selected by patching `hl.env("qsConfig", "ii")` → `"end4-pC"` in the **staged** `/opt/dots-hyprland/dots/.config/hypr/hyprland/variables.lua` (there is no `hypr/hyprland/` in this repo — `./setup install` copies it to the installed system). `alvin-install` re-copies end4-pC into the user's home *after* `./setup install`, because end-4's installer `rsync --delete`s all of `~/.config/quickshell`. - `airootfs/etc/skel/.config/illogical-impulse/presets/` carries the user's presets (`Laptop.json`, `Personal-Performance.json`, `Personal-Performance.zip`). They embed `/home/alvin/...` paths, so wallpapers/screenshots need fixing up after install. - End-4 metapackages are built from `localrepo/end4-pkgbuilds/` (quickshell-git, bibata-modern-classic-bin, microtex-git). +- **quickshell pin / Qt 6.12**: end-4 pins quickshell to `41651d7` (Sep 25), which predates upstream fix `5d5d498` (Oct 3, *"use MOC includes instead of opaque pointer definitions — … Qt 6.12 compatibility"*). Arch shipped qt6 6.12.0 on Oct 8 and the old pin died with `Meta Types must be fully defined` in the moc build of quickshell-hyprland-ipc (failed CI run 137). `customize_airootfs.sh` therefore rewrites end-4's `_commit` to `11ca60be` after cloning — but **only** while it still matches `^_commit='41651d7`, so once end-4 bumps their own pin the guard goes inert and theirs wins. `localrepo/check-quickshell-pin.sh` (weekly `pin-check.yaml` job) fails CI if either pin goes stale or loses the fix; it warns instead of failing when end-4's known-stale pin is covered by the override. - `packages.x86_64` is sorted alphabetically. Keep it sorted when adding/removing entries. - `airootfs/opt/localrepo/` is a build artifact (gitignored) — never commit it. - **Build stamp flow**: `profiledef.sh` (sourced by mkarchiso) stages the gitignored `airootfs/root/.iso-build-stamp` when a `.git` dir exists **or** `CI`/`GITEA_ACTIONS` is set — line reads `AlvinArch build | commit | <4-char hash>` (falls back to `commit unknown` if `git -c safe.directory` can't read the repo; without `.git`/CI no file is staged). `customize_airootfs.sh` keeps it as `/etc/alvin-build-stamp` on the live medium **and appends it to the live `/etc/motd`**, so the booted ISO identifies its build. The installed system's motd is never touched by us — `alvin-install` has no motd step (an earlier `install_motd` that copied the banner + stamp into the target was removed on purpose). diff --git a/airootfs/root/customize_airootfs.sh b/airootfs/root/customize_airootfs.sh index e2a4156..a569b47 100644 --- a/airootfs/root/customize_airootfs.sh +++ b/airootfs/root/customize_airootfs.sh @@ -89,6 +89,22 @@ if [[ ! -d "${DOTS_REPO}/.git" ]]; then git -C "${DOTS_REPO}" submodule update --init --depth=1 fi +# end-4 pins quickshell to 41651d7 (Sep 25), which predates quickshell's +# Qt 6.12 fix (5d5d498, Oct 3: "use MOC includes instead of opaque pointer +# definitions - Fixes linking issues and Qt 6.12 compatibility"). Arch +# shipped qt6 6.12.0 into extra on Oct 8; with the old pin qmetatype.h's +# "Meta Types must be fully defined" static_assert kills the moc build of +# quickshell-hyprland-ipc (failed CI run 137) and the whole ISO build with +# it. Force the fixed commit, but ONLY while end-4 still carries the old +# pin - once they bump it themselves the guard stops matching and their +# pin wins untouched. localrepo/check-quickshell-pin.sh (weekly CI) +# verifies both this pin and end-4's stay Qt 6.12-compatible. +QS_PKG="${DOTS_REPO}/sdata/dist-arch/illogical-impulse-quickshell-git/PKGBUILD" +if [[ -f "${QS_PKG}" ]] && grep -q "^_commit='41651d7" "${QS_PKG}"; then + echo "[customize] Bumping end-4 quickshell pin to 11ca60be (Qt 6.12 fix)..." + sed -i "s|^_commit='41651d7[^']*'|_commit='11ca60be22b063478ed9586ca1d7f92f0f261caf'|" "${QS_PKG}" +fi + # ── end4-pC: the default quickshell config, shipped in skel ────────────────── # pctrade/end4-pC is a fork of the ii shell config. It lives next to ii in # ~/.config/quickshell and does not modify it; which one runs is decided by diff --git a/localrepo/check-quickshell-pin.sh b/localrepo/check-quickshell-pin.sh new file mode 100755 index 0000000..ae452ed --- /dev/null +++ b/localrepo/check-quickshell-pin.sh @@ -0,0 +1,184 @@ +#!/usr/bin/env bash +# Verify that every quickshell pin we build against is current enough to +# survive the next Arch Qt update. +# +# Why this exists: CI run 137 (2026-10-08) failed because end-4 pinned +# quickshell to 41651d7 (Sep 25), which predates quickshell's Qt 6.12 fix +# (5d5d498, Oct 3: "use MOC includes instead of opaque pointer definitions +# - Fixes linking issues and Qt 6.12 compatibility"). Arch shipped +# qt6 6.12.0 the next day and the pinned commit stopped compiling +# ("Meta Types must be fully defined"). customize_airootfs.sh papers over +# end-4's stale pin at build time; this script is the tripwire that tells +# us when pins - ours OR end-4's - fall behind again BEFORE a build does. +# +# Checked pins: +# 1. localrepo/end4-pkgbuilds/quickshell-git/PKGBUILD (our own pin) +# 2. end-4/dots-hyprland sdata/dist-arch PKGBUILD (live from GitHub) +# +# Checks per pin: +# - commit exists upstream +# - includes the Qt 6.12 fix (5d5d498) +# - not older than QUICKSHELL_PIN_MAX_AGE_DAYS (default 45) +# +# Exit 1 on any failure so CI (pin-check.yaml) goes red. +# +# Usage: ./localrepo/check-quickshell-pin.sh +set -euo pipefail + +QT612_FIX='5d5d49873fe8cf1f99ddfd5006ceb2057c5c9b13' +QS_REPO='https://git.outfoxxed.me/quickshell/quickshell.git' +END4_STALE_PIN='41651d7' # the pin customize_airootfs.sh overrides +END4_PKGBUILD_URL='https://raw.githubusercontent.com/end-4/dots-hyprland/main/sdata/dist-arch/illogical-impulse-quickshell-git/PKGBUILD' +MAX_AGE_DAYS="${QUICKSHELL_PIN_MAX_AGE_DAYS:-45}" + +profile_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +LOCAL_PKGBUILD="${profile_dir}/localrepo/end4-pkgbuilds/quickshell-git/PKGBUILD" + +FAILED=0 + +fail() { + echo "❌ $1" >&2 + FAILED=1 +} + +# ── collect pins ──────────────────────────────────────────────────────────── + +pin_of() { # -> first _commit='...' value + sed -n "s/^_commit='\([0-9a-f]\{7,40\}\)'.*/\1/p" | head -n1 +} + +if [[ ! -f "$LOCAL_PKGBUILD" ]]; then + echo "❌ missing ${LOCAL_PKGBUILD}" >&2 + exit 1 +fi +local_pin=$(pin_of < "$LOCAL_PKGBUILD") +if [[ -z "$local_pin" ]]; then + echo "❌ no _commit= found in ${LOCAL_PKGBUILD}" >&2 + exit 1 +fi + +end4_pin='' +end4_pkgbuild='' +for try in 1 2 3 4 5; do + if end4_pkgbuild=$(curl -fsSL --max-time 30 "$END4_PKGBUILD_URL"); then + end4_pin=$(printf '%s\n' "$end4_pkgbuild" | pin_of) + break + fi + echo " ⏳ fetch of end-4 PKGBUILD failed (try $try/5), retrying in $(( try * 3 ))s..." >&2 + sleep $(( try * 3 )) +done +if [[ -z "$end4_pin" ]]; then + fail "could not fetch end-4's quickshell PKGBUILD from GitHub — network or path change?" + echo "" + echo "Result: FAILED" + exit 1 +fi + +# ── clone quickshell (blobless: commits+trees only, fast) ─────────────────── + +tmp=$(mktemp -d) +trap 'rm -rf "$tmp"' EXIT + +cloned=0 +for try in 1 2 3; do + if git clone --filter=blob:none --quiet "$QS_REPO" "$tmp/qs" 2>/dev/null; then + cloned=1 + break + fi + rm -rf "$tmp/qs" + echo " ⏳ clone of quickshell failed (try $try/3), retrying in $(( try * 5 ))s..." >&2 + sleep $(( try * 5 )) +done +if [[ "$cloned" -ne 1 ]]; then + fail "could not clone ${QS_REPO} — network or repo moved?" + echo "" + echo "Result: FAILED" + exit 1 +fi +QS="$tmp/qs" +qs_head=$(git -C "$QS" rev-parse HEAD) +qs_head_date=$(git -C "$QS" show -s --format=%cs HEAD) +echo "quickshell upstream master: ${qs_head:0:12} (${qs_head_date})" +echo "" + +now=$(date +%s) + +#