From a090edeb7fed2f923ce843305bf47943a7daf271 Mon Sep 17 00:00:00 2001 From: Marcelo Alcantara Date: Fri, 25 Sep 2026 17:42:53 +1000 Subject: [PATCH 1/4] Carry aquamarine 0.15.1 on edge for Apple Silicon and rebuild Hyprland Carry Arch's aquamarine 0.15.1-1 with one patch that re-reads a connector's possible CRTCs on rescan, so a Type-C port the Apple DCP fabric reroutes to another pipeline gets a CRTC without restarting the compositor. aarch64 and edge only; pkgrel 1.1 sits above Arch Linux ARM's 0.15.1-1. Bump Hyprland for aquamarine 0.15.1 and make rebuild detection see aarch64. sync-rebuilds followed PUBLISHED_ARCHES (x86_64 by default), so the scheduled run skipped every aarch64-only package, and it read aarch64 triggers from Arch Linux ARM even when this repository carries them. It now follows the architectures a merge builds, and reads a carried trigger from its recipe once edge publishes that version. --- README.md | 7 +- bin/build-matrix | 2 +- bin/sync-rebuilds | 201 +++++++++++++++--- helpers/paths.sh | 14 ++ pkgbuilds/aquamarine/.omarchy/package.json | 6 + ...ble-CRTCs-when-rescanning-connectors.patch | 36 ++++ pkgbuilds/aquamarine/PKGBUILD | 58 +++++ pkgbuilds/hyprland/.omarchy/package.json | 2 +- pkgbuilds/hyprland/PKGBUILD | 2 +- 9 files changed, 293 insertions(+), 35 deletions(-) create mode 100644 pkgbuilds/aquamarine/.omarchy/package.json create mode 100644 pkgbuilds/aquamarine/0001-drm-re-read-possible-CRTCs-when-rescanning-connectors.patch create mode 100644 pkgbuilds/aquamarine/PKGBUILD diff --git a/README.md b/README.md index 8823595e..6920a143 100644 --- a/README.md +++ b/README.md @@ -520,7 +520,8 @@ A package names those dependencies in `.omarchy/package.json`: ``` `bin/sync-rebuilds` reads each named package's version from the official -repositories for every published architecture the package supports and compares +repositories for every architecture a merge builds (`CI_ARCHES` in +`helpers/paths.sh`, both by default) that the package supports and compares it to `rebuilt_against`. Records are kept per architecture because Arch and Arch Linux ARM can carry different dependency versions. pkgrel is bumped once when any recorded version moves; that one source revision is then rebuilt by @@ -539,6 +540,8 @@ repository database, which is also what the ARM builder uses. Testing and staging repositories do not count. A legacy flat `rebuilt_against` record is read as x86_64 and is migrated naturally the next time a rebuild is needed. +A dependency this repository carries for an architecture (a recipe here that builds for edge on it, such as aquamarine on aarch64) shadows the distribution's, because the builder lists `[omarchy]` first. Its version is the recipe's, and it counts only once edge publishes that version: until then the builder still links against the previous one, so dependents are left alone for that run. + ### Other ```bash @@ -726,7 +729,7 @@ Fields: - `skip_build`: optional boolean; defaults to `false`. Set `true` to exclude a package from scheduled version checks and unscoped builds. The package can still be built explicitly with `bin/repo release --package `. - `pkgrel`: legacy import customization metadata. Maintained recipes keep their complete package release directly in PKGBUILD; rebuilds increment it there. - `rebuild_on`: optional array of package names this package links against closely enough that it must be rebuilt when they change, independent of its own source. Read by `bin/sync-rebuilds`. -- `rebuilt_against`: written by `bin/sync-rebuilds`. Maps each published architecture to the versions of its `rebuild_on` packages that the current pkgrel was bumped for. +- `rebuilt_against`: written by `bin/sync-rebuilds`. Maps each built architecture to the versions of its `rebuild_on` packages that the current pkgrel was bumped for. - `upstream_commit`: legacy AUR metadata, superseded by `origin.commit`. `bin/package-worktree` can use historical provenance to inspect the original recipe. ### Build Matrix diff --git a/bin/build-matrix b/bin/build-matrix index e7723499..584a3bd1 100755 --- a/bin/build-matrix +++ b/bin/build-matrix @@ -19,7 +19,7 @@ BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..") source "$BUILD_ROOT/helpers/paths.sh" source "$BUILD_ROOT/helpers/package-metadata.sh" -ARCHES=${CI_ARCHES:-x86_64 aarch64} +ARCHES=$CI_ARCHES if [[ "${1:-}" == --arch ]]; then [[ $2 == all ]] || ARCHES=$2; shift 2; fi for a in $ARCHES; do require_valid_arch "$a"; done diff --git a/bin/sync-rebuilds b/bin/sync-rebuilds index 3009b898..d99277f8 100755 --- a/bin/sync-rebuilds +++ b/bin/sync-rebuilds @@ -67,8 +67,10 @@ Examples: $0 quickshell-git # Update specific packages x86_64 trigger versions come from the local pacman database; aarch64 versions -come from the live Arch Linux ARM repository database. Only architectures in -PUBLISHED_ARCHES that the package supports are considered. +come from the live Arch Linux ARM repository database. A trigger this +repository carries for an architecture shadows both, so its version is the +checked-in recipe's once edge publishes it. Every architecture in CI_ARCHES +(what a merge builds) that the package supports is considered. EOF } @@ -167,6 +169,8 @@ repo_version() { # repo_version } declare -A PUBLISHED_VERSION=() +declare -A EDGE_VERSION=() +declare -A EDGE_READ=() PUBLISHED_LOADED=false remember_published() { @@ -190,7 +194,7 @@ load_published_versions() { local arch mirror db name base version - for arch in $(published_arches); do + for arch in $(ci_arches); do for mirror in "${PUBLISHED_MIRRORS[@]}"; do db="$TEMP_DIR/published-$mirror-$arch.db.tar.zst" @@ -199,10 +203,19 @@ load_published_versions() { print_warning "Could not read the published $mirror/$arch database; bumps are not checked against it this run" continue fi + if ! tar -tf "$db" >/dev/null 2>&1; then + print_warning "Unreadable published $mirror/$arch database; bumps are not checked against it this run" + continue + fi + [[ "$mirror" == edge ]] && EDGE_READ["$arch"]=1 while IFS=$'\t' read -r name base version; do [[ -n "$name" && -n "$version" ]] && remember_published "$name" "$version" [[ -n "$base" && -n "$version" ]] && remember_published "$base" "$version" + if [[ "$mirror" == edge && -n "$version" ]]; then + [[ -z "$name" ]] || EDGE_VERSION["$arch/$name"]="$version" + [[ -z "$base" ]] || EDGE_VERSION["$arch/$base"]="$version" + fi done < <( tar -xOf "$db" --wildcards '*/desc' 2>/dev/null | awk ' function emit() { @@ -227,6 +240,27 @@ published_version() { echo "${PUBLISHED_VERSION[$package]:-}" } +# A trigger this repository builds for the architecture. The builder lists +# [omarchy] ahead of the distribution repositories, so this recipe, not Arch or +# Arch Linux ARM, decides what a dependent links against. +carried_trigger_dir() { # carried_trigger_dir + local pkgdir + pkgdir=$(package_dir_for_name "$2") || return 1 + package_has_metadata "$pkgdir" || return 1 + package_builds_for_mirror "$pkgdir" edge || return 1 + package_supports_arch "$pkgdir" "$1" || return 1 + echo "$pkgdir" +} + +carried_version() { # carried_version + local epoch pkgver pkgrel + epoch=$(package_pkgbuild_var "$2" epoch "$1") || return 1 + pkgver=$(package_pkgbuild_var "$2" pkgver "$1") || return 1 + pkgrel=$(package_pkgbuild_var "$2" pkgrel "$1") || return 1 + [[ -n "$pkgver" && -n "$pkgrel" ]] || return 1 + echo "${epoch:+$epoch:}$pkgver-$pkgrel" +} + # The pkgver of a full version string, with any epoch and pkgrel removed. version_pkgver() { local version="${1#*:}" @@ -368,13 +402,33 @@ sync_package() { print_info "Checking $package against ${triggers[*]}..." - local current="{}" arch arch_current trigger version considered=0 - for arch in $(published_arches); do + local current="{}" arch arch_current trigger version carried considered=0 + for arch in $(ci_arches); do package_supports_arch "$package_dir" "$arch" || continue considered=$((considered + 1)) arch_current="{}" for trigger in "${triggers[@]}"; do - if ! version=$(repo_version "$arch" "$trigger"); then + if carried=$(carried_trigger_dir "$arch" "$trigger"); then + if ! version=$(carried_version "$arch" "$carried"); then + print_error " Could not read the $arch version of $trigger from its recipe; leaving $package alone" + ((++FAILED)) + return 0 + fi + load_published_versions + if [[ -z "${EDGE_READ[$arch]:-}" ]]; then + print_error " Could not read the published edge/$arch database for $trigger; leaving $package alone" + ((++FAILED)) + return 0 + fi + # Until edge publishes the recipe's version the builder still links + # against the previous one, and recording the new version now would + # certify a build that never saw it. + if [[ "${EDGE_VERSION[$arch/$trigger]:-}" != "$version" ]]; then + print_warning " $trigger $version is not published on edge/$arch yet; leaving $package alone until it is" + ((++SKIPPED)) + return 0 + fi + elif ! version=$(repo_version "$arch" "$trigger"); then print_error " Could not read $arch repository versions; leaving $package alone" ((++FAILED)) return 0 @@ -479,6 +533,7 @@ sync_package() { # checkout that has fallen behind the repository can otherwise be bumped to # something pacman orders below what it would replace. local floor + load_published_versions floor=$(published_version "$package") if [[ -n "$floor" && "$(version_pkgver "$floor")" == "$pkgver" ]]; then if [[ "$(vercmp "$new_version" "$floor")" -le 0 ]]; then @@ -584,26 +639,33 @@ STUB chmod +x "$root/stub/pacman" } -# Serves a repository database assembled by hand from name=version pairs. With -# none given the stub fails, which is how the unreachable-repository path is +# A repository database assembled by hand from name=version pairs. +selftest_db() { + local out="$1" + shift + local staging="$out.d" entry name version + + rm -rf "$staging" + mkdir -p "$staging" + for entry in "$@"; do + name="${entry%=*}" + version="${entry#*=}" + mkdir -p "$staging/$name-$version" + printf '%%FILENAME%%\n%s-%s-x86_64.pkg.tar.zst\n\n%%NAME%%\n%s\n\n%%BASE%%\n%s\n\n%%VERSION%%\n%s\n' \ + "$name" "$version" "$name" "$name" "$version" > "$staging/$name-$version/desc" + done + tar --zstd -cf "$out" -C "$staging" . +} + +# Serves one published database for every channel and architecture. With no +# pairs given the stub fails, which is how the unreachable-repository path is # exercised. selftest_published() { local root="$1" shift - local staging="$root/stub/db" - local entry name version if [[ $# -gt 0 ]]; then - rm -rf "$staging" - mkdir -p "$staging" - for entry in "$@"; do - name="${entry%=*}" - version="${entry#*=}" - mkdir -p "$staging/$name-$version" - printf '%%FILENAME%%\n%s-%s-x86_64.pkg.tar.zst\n\n%%NAME%%\n%s\n\n%%BASE%%\n%s\n\n%%VERSION%%\n%s\n' \ - "$name" "$version" "$name" "$name" "$version" > "$staging/$name-$version/desc" - done - tar --zstd -cf "$root/stub/omarchy.db.tar.zst" -C "$staging" . + selftest_db "$root/stub/omarchy.db.tar.zst" "$@" fi cat > "$root/stub/curl" <<'STUB' @@ -616,19 +678,33 @@ while [[ $# -gt 0 ]]; do *) url="$1"; shift ;; esac done -if [[ "$url" == */aarch64/* ]]; then - repo="${url%/*}" - repo="${repo##*/}" - db="$(dirname "$0")/alarm-$repo.db" -else - db="$(dirname "$0")/omarchy.db.tar.zst" -fi +case "$url" in + */omarchy.db.tar.zst) + channel="${url%/omarchy.db.tar.zst}" + arch="${channel##*/}" + channel="${channel%/*}" + db="$(dirname "$0")/omarchy-${channel##*/}-$arch.db.tar.zst" + [[ -f "$db" ]] || db="$(dirname "$0")/omarchy.db.tar.zst" + ;; + */aarch64/*) + repo="${url%/*}" + db="$(dirname "$0")/alarm-${repo##*/}.db" + ;; + *) db="" ;; +esac [[ -f "$db" && -n "$out" ]] || exit 22 cp "$db" "$out" STUB chmod +x "$root/stub/curl" } +# Serves one channel and architecture its own published database. +selftest_channel() { # selftest_channel [name=version...] + local root="$1" channel="$2" arch="$3" + shift 3 + selftest_db "$root/stub/omarchy-$channel-$arch.db.tar.zst" "$@" +} + selftest_alarm() { local root="$1" shift @@ -668,12 +744,15 @@ cmd_self_test() { fi } + # SELFTEST_ARCHES stands in for CI_ARCHES; "default" leaves it unset, as the + # scheduled workflow does. run_case() { local root="$1" shift - local status=0 - OMARCHY_ARCHES="${SELFTEST_ARCHES:-x86_64}" \ - PATH="$root/stub:$PATH" "$root/bin/sync-rebuilds" "$@" > "$root/output" 2>&1 || status=$? + local status=0 arches=(CI_ARCHES="${SELFTEST_ARCHES:-x86_64}") + [[ "${SELFTEST_ARCHES:-}" != default ]] || arches=(-u CI_ARCHES) + env "${arches[@]}" PATH="$root/stub:$PATH" \ + "$root/bin/sync-rebuilds" "$@" > "$root/output" 2>&1 || status=$? echo "$status" } @@ -781,6 +860,68 @@ cmd_self_test() { unset SELFTEST_ARCHES check "pkgrel untouched" 1 "$(pkgrel_of "$root/pkgbuilds/t-x86")" + echo "An ARM-only package is checked when no architecture list is given:" + root=$(selftest_root arm-default) + selftest_package "$root" t-arm-default 1 '{"source":"local","rebuild_on":["dep-a"],"rebuilt_against":{"aarch64":{"dep-a":"1-1"}}}' 1.0 aarch64 + selftest_pacman "$root" + selftest_published "$root" + selftest_alarm "$root" dep-a=2-1 + SELFTEST_ARCHES=default + check "run succeeds" 0 "$(run_case "$root")" + unset SELFTEST_ARCHES + check "pkgrel bumped" 2 "$(pkgrel_of "$root/pkgbuilds/t-arm-default")" + check "ARM trigger recorded" "2-1" \ + "$(jq -r '.rebuilt_against.aarch64["dep-a"]' "$root/pkgbuilds/t-arm-default/.omarchy/package.json")" + + echo "A dependency carried here for ARM is read from its recipe once edge publishes it:" + root=$(selftest_root carried) + selftest_package "$root" t-carried 1.1 '{"source":"local","channels":["edge"]}' 0.15.1 aarch64 + selftest_package "$root" t-linked 3 '{"source":"local","rebuild_on":["t-carried"],"rebuilt_against":{"x86_64":{"t-carried":"0.15.1-1"},"aarch64":{"t-carried":"0.15.0-2"}}}' 1.0 'x86_64 aarch64' + selftest_pacman "$root" t-carried=0.15.1-1 + selftest_published "$root" + selftest_alarm "$root" t-carried=0.15.1-1 + selftest_channel "$root" edge aarch64 t-carried=0.15.1-1.1 + SELFTEST_ARCHES=default + check "run succeeds" 0 "$(run_case "$root")" + check "pkgrel bumped" 4 "$(pkgrel_of "$root/pkgbuilds/t-linked")" + check "the carried version is recorded, not Arch Linux ARM's" "0.15.1-1.1" \ + "$(jq -r '.rebuilt_against.aarch64["t-carried"]' "$root/pkgbuilds/t-linked/.omarchy/package.json")" + check "x86_64, where nothing is carried, still reads the distribution" "0.15.1-1" \ + "$(jq -r '.rebuilt_against.x86_64["t-carried"]' "$root/pkgbuilds/t-linked/.omarchy/package.json")" + check "a second run succeeds" 0 "$(run_case "$root")" + unset SELFTEST_ARCHES + check "a second run leaves it alone" 4 "$(pkgrel_of "$root/pkgbuilds/t-linked")" + + echo "A carried dependency that edge does not publish yet leaves its dependents alone:" + root=$(selftest_root carried-in-flight) + selftest_package "$root" t-carried 1.2 '{"source":"local","channels":["edge"]}' 0.15.1 aarch64 + selftest_package "$root" t-linked 4 '{"source":"local","rebuild_on":["t-carried"],"rebuilt_against":{"aarch64":{"t-carried":"0.15.1-1.1"}}}' 1.0 aarch64 + selftest_pacman "$root" + selftest_published "$root" + selftest_alarm "$root" t-carried=0.15.1-1 + selftest_channel "$root" edge aarch64 t-carried=0.15.1-1.1 + SELFTEST_ARCHES=aarch64 + check "run succeeds" 0 "$(run_case "$root")" + unset SELFTEST_ARCHES + check "pkgrel untouched" 4 "$(pkgrel_of "$root/pkgbuilds/t-linked")" + check "record untouched" "0.15.1-1.1" \ + "$(jq -r '.rebuilt_against.aarch64["t-carried"]' "$root/pkgbuilds/t-linked/.omarchy/package.json")" + + echo "A carried dependency whose edge database cannot be read fails the run:" + root=$(selftest_root carried-unreadable) + selftest_package "$root" t-carried 1.1 '{"source":"local","channels":["edge"]}' 0.15.1 aarch64 + selftest_package "$root" t-linked 3 '{"source":"local","rebuild_on":["t-carried"],"rebuilt_against":{"aarch64":{"t-carried":"0.15.0-2"}}}' 1.0 aarch64 + selftest_pacman "$root" + selftest_published "$root" + selftest_alarm "$root" t-carried=0.15.1-1 + SELFTEST_ARCHES=aarch64 + check "run fails" 1 "$(run_case "$root")" + check "pkgrel untouched" 3 "$(pkgrel_of "$root/pkgbuilds/t-linked")" + printf 'not a database\n' > "$root/stub/omarchy-edge-aarch64.db.tar.zst" + check "a corrupt download fails the run too" 1 "$(run_case "$root")" + unset SELFTEST_ARCHES + check "pkgrel still untouched" 3 "$(pkgrel_of "$root/pkgbuilds/t-linked")" + echo "A PKGBUILD that branches on CARCH at file scope still reads its version:" root=$(selftest_root carch-branch) mkdir -p "$root/pkgbuilds/t-carch/.omarchy" diff --git a/helpers/paths.sh b/helpers/paths.sh index 5d6191c3..1d734a9a 100644 --- a/helpers/paths.sh +++ b/helpers/paths.sh @@ -43,6 +43,20 @@ reference_arch() { published_arches | head -1 } +# Architectures a merge to master builds and publishes: bin/build-matrix plans +# a PR build for each one a package supports, and publish.yml ships them. This +# is independent of PUBLISHED_ARCHES, so anything deciding what a merge has to +# rebuild (bin/sync-rebuilds) follows this list. CI_ARCHES overrides it. +CI_ARCHES="${CI_ARCHES:-x86_64 aarch64}" + +ci_arches() { + local arch + for arch in $CI_ARCHES; do + require_valid_arch "$arch" + echo "$arch" + done +} + # Scheduled-pipeline state, one file per channel and architecture, so one # architecture's queue or backoff never gates another's. STATE_DIR="${OMARCHY_STATE_DIR:-/root/.state}" diff --git a/pkgbuilds/aquamarine/.omarchy/package.json b/pkgbuilds/aquamarine/.omarchy/package.json new file mode 100644 index 00000000..7ddd3305 --- /dev/null +++ b/pkgbuilds/aquamarine/.omarchy/package.json @@ -0,0 +1,6 @@ +{ + "source": "local", + "channels": [ + "edge" + ] +} diff --git a/pkgbuilds/aquamarine/0001-drm-re-read-possible-CRTCs-when-rescanning-connectors.patch b/pkgbuilds/aquamarine/0001-drm-re-read-possible-CRTCs-when-rescanning-connectors.patch new file mode 100644 index 00000000..bbf70430 --- /dev/null +++ b/pkgbuilds/aquamarine/0001-drm-re-read-possible-CRTCs-when-rescanning-connectors.patch @@ -0,0 +1,36 @@ +From 375e80ec3826b54618fdd5f2db708c0f2bb936ae Mon Sep 17 00:00:00 2001 +From: Marcelo Alcantara +Date: Wed, 16 Sep 2026 00:39:04 +1000 +Subject: [PATCH] drm: re-read possible CRTCs when rescanning connectors + +A driver can change a connector's possible CRTCs at runtime. Apple's DCP +driver narrows a Type-C port's encoder to the display pipeline the fabric +routed it to and relies on the following hotplug for userspace to re-read +it. possibleCrtcs was only read when the connector was first created, so a +rerouted port kept a stale mask and was never assigned its now-free CRTC +until the compositor restarted. +--- + src/backend/drm/DRM.cpp | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp +index 6618a26..b492dac 100644 +--- a/src/backend/drm/DRM.cpp ++++ b/src/backend/drm/DRM.cpp +@@ -1287,6 +1287,13 @@ void Aquamarine::CDRMBackend::scanConnectors() { + } else { + backend->log(AQ_LOG_DEBUG, std::format("drm: Connector id {} already initialized", connectorID)); + conn = *it; ++ ++ // drivers may narrow or widen these on hotplug, e.g. when a Type-C port is rerouted to another pipeline ++ const auto possibleCrtcs = drmModeConnectorGetPossibleCrtcs(gpu->fd, drmConn); ++ if (possibleCrtcs && possibleCrtcs != conn->possibleCrtcs) { ++ backend->log(AQ_LOG_DEBUG, std::format("drm: Connector {} possible CRTCs changed {:#x} -> {:#x}", conn->szName, conn->possibleCrtcs, possibleCrtcs)); ++ conn->possibleCrtcs = possibleCrtcs; ++ } + } + + conn->status = drmConn->connection; +-- +2.50.1 (Apple Git-155) + diff --git a/pkgbuilds/aquamarine/PKGBUILD b/pkgbuilds/aquamarine/PKGBUILD new file mode 100644 index 00000000..2941ebdd --- /dev/null +++ b/pkgbuilds/aquamarine/PKGBUILD @@ -0,0 +1,58 @@ +# Maintainer: Caleb Maclennan +# Contributor: Aaron Blasko +# +# Arch's aquamarine 0.15.1-1 plus one patch, carried on edge for Apple Silicon: +# re-read a connector's possible CRTCs when rescanning, so a Type-C port the +# DCP fabric reroutes to another display pipeline gets a CRTC without +# restarting the compositor. Drop the carry once hyprwm releases the fix. +# Hyprland is rebuilt whenever this package changes (its rebuild_on). + +pkgname=aquamarine +pkgver=0.15.1 +pkgrel=1.1 +pkgdesc='a very light linux rendering backend library' +arch=(aarch64) +url="https://github.com/hyprwm/$pkgname" +license=(BSD-3-Clause) +depends=(libgcc + libstdc++ + glibc # libc.so libm.so + hyprutils libhyprutils.so + libdisplay-info libdisplay-info.so + libdrm # libdrm.so + libglvnd libEGL.so + libinput # libinput.so + mesa # libgbm.so + opengl-driver + pixman + seatd libseat.so + systemd-libs libudev.so + wayland libwayland-client.so + wayland-protocols) +makedepends=(cmake + hyprwayland-scanner) +provides=("lib$pkgname.so") +_archive="$pkgname-$pkgver" +source=("$url/archive/v$pkgver/$_archive.tar.gz" + 0001-drm-re-read-possible-CRTCs-when-rescanning-connectors.patch) +sha256sums=('2f9de98c0bd1b7b1b09c576e390a2fef436449762fb334163c414f0c300296f2' + '50e9e38ff915b18074dc9b5dd1d07d7f24e340e99f254476d6abe578eece7864') + +prepare() { + cd "$_archive" + patch -Np1 -i ../0001-drm-re-read-possible-CRTCs-when-rescanning-connectors.patch +} + +build() { + cd "$_archive" + cmake -B build \ + -D CMAKE_INSTALL_PREFIX=/usr \ + -D CMAKE_BUILD_TYPE=Release + cmake --build build +} + +package() { + cd "$_archive" + DESTDIR="$pkgdir" cmake --install build + install -Dm0644 -t "$pkgdir/usr/share/licenses/$pkgname" LICENSE +} diff --git a/pkgbuilds/hyprland/.omarchy/package.json b/pkgbuilds/hyprland/.omarchy/package.json index 9dd97453..0642ff78 100644 --- a/pkgbuilds/hyprland/.omarchy/package.json +++ b/pkgbuilds/hyprland/.omarchy/package.json @@ -15,7 +15,7 @@ ], "rebuilt_against": { "aarch64": { - "aquamarine": "0.15.0-2" + "aquamarine": "0.15.1-1" } } } diff --git a/pkgbuilds/hyprland/PKGBUILD b/pkgbuilds/hyprland/PKGBUILD index cbb70ed8..4a5f41cd 100644 --- a/pkgbuilds/hyprland/PKGBUILD +++ b/pkgbuilds/hyprland/PKGBUILD @@ -5,7 +5,7 @@ pkgname=(hyprland hyprpm) pkgver=0.56.2 -pkgrel=3 +pkgrel=4 pkgdesc='a highly customizable dynamic tiling Wayland compositor' arch=(aarch64) url="https://github.com/hyprwm/${pkgname^}" From 584fa5732e5a972206e2c32e8a75892cdbd3c955 Mon Sep 17 00:00:00 2001 From: Marcelo Alcantara Date: Fri, 25 Sep 2026 17:46:06 +1000 Subject: [PATCH 2/4] Leave Hyprland and rebuild detection to their own changes PR builds link against published edge, so a Hyprland bump in the same merge cannot see the carry, and as a fast-ring package it would reach every aarch64 channel. The rebuild detection fix that bumps it once the carry publishes moves to its own PR, so this change only adds the aquamarine carry. --- README.md | 7 +- bin/build-matrix | 2 +- bin/sync-rebuilds | 201 ++++------------------- helpers/paths.sh | 14 -- pkgbuilds/hyprland/.omarchy/package.json | 2 +- pkgbuilds/hyprland/PKGBUILD | 2 +- 6 files changed, 35 insertions(+), 193 deletions(-) diff --git a/README.md b/README.md index 6920a143..8823595e 100644 --- a/README.md +++ b/README.md @@ -520,8 +520,7 @@ A package names those dependencies in `.omarchy/package.json`: ``` `bin/sync-rebuilds` reads each named package's version from the official -repositories for every architecture a merge builds (`CI_ARCHES` in -`helpers/paths.sh`, both by default) that the package supports and compares +repositories for every published architecture the package supports and compares it to `rebuilt_against`. Records are kept per architecture because Arch and Arch Linux ARM can carry different dependency versions. pkgrel is bumped once when any recorded version moves; that one source revision is then rebuilt by @@ -540,8 +539,6 @@ repository database, which is also what the ARM builder uses. Testing and staging repositories do not count. A legacy flat `rebuilt_against` record is read as x86_64 and is migrated naturally the next time a rebuild is needed. -A dependency this repository carries for an architecture (a recipe here that builds for edge on it, such as aquamarine on aarch64) shadows the distribution's, because the builder lists `[omarchy]` first. Its version is the recipe's, and it counts only once edge publishes that version: until then the builder still links against the previous one, so dependents are left alone for that run. - ### Other ```bash @@ -729,7 +726,7 @@ Fields: - `skip_build`: optional boolean; defaults to `false`. Set `true` to exclude a package from scheduled version checks and unscoped builds. The package can still be built explicitly with `bin/repo release --package `. - `pkgrel`: legacy import customization metadata. Maintained recipes keep their complete package release directly in PKGBUILD; rebuilds increment it there. - `rebuild_on`: optional array of package names this package links against closely enough that it must be rebuilt when they change, independent of its own source. Read by `bin/sync-rebuilds`. -- `rebuilt_against`: written by `bin/sync-rebuilds`. Maps each built architecture to the versions of its `rebuild_on` packages that the current pkgrel was bumped for. +- `rebuilt_against`: written by `bin/sync-rebuilds`. Maps each published architecture to the versions of its `rebuild_on` packages that the current pkgrel was bumped for. - `upstream_commit`: legacy AUR metadata, superseded by `origin.commit`. `bin/package-worktree` can use historical provenance to inspect the original recipe. ### Build Matrix diff --git a/bin/build-matrix b/bin/build-matrix index 584a3bd1..e7723499 100755 --- a/bin/build-matrix +++ b/bin/build-matrix @@ -19,7 +19,7 @@ BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..") source "$BUILD_ROOT/helpers/paths.sh" source "$BUILD_ROOT/helpers/package-metadata.sh" -ARCHES=$CI_ARCHES +ARCHES=${CI_ARCHES:-x86_64 aarch64} if [[ "${1:-}" == --arch ]]; then [[ $2 == all ]] || ARCHES=$2; shift 2; fi for a in $ARCHES; do require_valid_arch "$a"; done diff --git a/bin/sync-rebuilds b/bin/sync-rebuilds index d99277f8..3009b898 100755 --- a/bin/sync-rebuilds +++ b/bin/sync-rebuilds @@ -67,10 +67,8 @@ Examples: $0 quickshell-git # Update specific packages x86_64 trigger versions come from the local pacman database; aarch64 versions -come from the live Arch Linux ARM repository database. A trigger this -repository carries for an architecture shadows both, so its version is the -checked-in recipe's once edge publishes it. Every architecture in CI_ARCHES -(what a merge builds) that the package supports is considered. +come from the live Arch Linux ARM repository database. Only architectures in +PUBLISHED_ARCHES that the package supports are considered. EOF } @@ -169,8 +167,6 @@ repo_version() { # repo_version } declare -A PUBLISHED_VERSION=() -declare -A EDGE_VERSION=() -declare -A EDGE_READ=() PUBLISHED_LOADED=false remember_published() { @@ -194,7 +190,7 @@ load_published_versions() { local arch mirror db name base version - for arch in $(ci_arches); do + for arch in $(published_arches); do for mirror in "${PUBLISHED_MIRRORS[@]}"; do db="$TEMP_DIR/published-$mirror-$arch.db.tar.zst" @@ -203,19 +199,10 @@ load_published_versions() { print_warning "Could not read the published $mirror/$arch database; bumps are not checked against it this run" continue fi - if ! tar -tf "$db" >/dev/null 2>&1; then - print_warning "Unreadable published $mirror/$arch database; bumps are not checked against it this run" - continue - fi - [[ "$mirror" == edge ]] && EDGE_READ["$arch"]=1 while IFS=$'\t' read -r name base version; do [[ -n "$name" && -n "$version" ]] && remember_published "$name" "$version" [[ -n "$base" && -n "$version" ]] && remember_published "$base" "$version" - if [[ "$mirror" == edge && -n "$version" ]]; then - [[ -z "$name" ]] || EDGE_VERSION["$arch/$name"]="$version" - [[ -z "$base" ]] || EDGE_VERSION["$arch/$base"]="$version" - fi done < <( tar -xOf "$db" --wildcards '*/desc' 2>/dev/null | awk ' function emit() { @@ -240,27 +227,6 @@ published_version() { echo "${PUBLISHED_VERSION[$package]:-}" } -# A trigger this repository builds for the architecture. The builder lists -# [omarchy] ahead of the distribution repositories, so this recipe, not Arch or -# Arch Linux ARM, decides what a dependent links against. -carried_trigger_dir() { # carried_trigger_dir - local pkgdir - pkgdir=$(package_dir_for_name "$2") || return 1 - package_has_metadata "$pkgdir" || return 1 - package_builds_for_mirror "$pkgdir" edge || return 1 - package_supports_arch "$pkgdir" "$1" || return 1 - echo "$pkgdir" -} - -carried_version() { # carried_version - local epoch pkgver pkgrel - epoch=$(package_pkgbuild_var "$2" epoch "$1") || return 1 - pkgver=$(package_pkgbuild_var "$2" pkgver "$1") || return 1 - pkgrel=$(package_pkgbuild_var "$2" pkgrel "$1") || return 1 - [[ -n "$pkgver" && -n "$pkgrel" ]] || return 1 - echo "${epoch:+$epoch:}$pkgver-$pkgrel" -} - # The pkgver of a full version string, with any epoch and pkgrel removed. version_pkgver() { local version="${1#*:}" @@ -402,33 +368,13 @@ sync_package() { print_info "Checking $package against ${triggers[*]}..." - local current="{}" arch arch_current trigger version carried considered=0 - for arch in $(ci_arches); do + local current="{}" arch arch_current trigger version considered=0 + for arch in $(published_arches); do package_supports_arch "$package_dir" "$arch" || continue considered=$((considered + 1)) arch_current="{}" for trigger in "${triggers[@]}"; do - if carried=$(carried_trigger_dir "$arch" "$trigger"); then - if ! version=$(carried_version "$arch" "$carried"); then - print_error " Could not read the $arch version of $trigger from its recipe; leaving $package alone" - ((++FAILED)) - return 0 - fi - load_published_versions - if [[ -z "${EDGE_READ[$arch]:-}" ]]; then - print_error " Could not read the published edge/$arch database for $trigger; leaving $package alone" - ((++FAILED)) - return 0 - fi - # Until edge publishes the recipe's version the builder still links - # against the previous one, and recording the new version now would - # certify a build that never saw it. - if [[ "${EDGE_VERSION[$arch/$trigger]:-}" != "$version" ]]; then - print_warning " $trigger $version is not published on edge/$arch yet; leaving $package alone until it is" - ((++SKIPPED)) - return 0 - fi - elif ! version=$(repo_version "$arch" "$trigger"); then + if ! version=$(repo_version "$arch" "$trigger"); then print_error " Could not read $arch repository versions; leaving $package alone" ((++FAILED)) return 0 @@ -533,7 +479,6 @@ sync_package() { # checkout that has fallen behind the repository can otherwise be bumped to # something pacman orders below what it would replace. local floor - load_published_versions floor=$(published_version "$package") if [[ -n "$floor" && "$(version_pkgver "$floor")" == "$pkgver" ]]; then if [[ "$(vercmp "$new_version" "$floor")" -le 0 ]]; then @@ -639,33 +584,26 @@ STUB chmod +x "$root/stub/pacman" } -# A repository database assembled by hand from name=version pairs. -selftest_db() { - local out="$1" - shift - local staging="$out.d" entry name version - - rm -rf "$staging" - mkdir -p "$staging" - for entry in "$@"; do - name="${entry%=*}" - version="${entry#*=}" - mkdir -p "$staging/$name-$version" - printf '%%FILENAME%%\n%s-%s-x86_64.pkg.tar.zst\n\n%%NAME%%\n%s\n\n%%BASE%%\n%s\n\n%%VERSION%%\n%s\n' \ - "$name" "$version" "$name" "$name" "$version" > "$staging/$name-$version/desc" - done - tar --zstd -cf "$out" -C "$staging" . -} - -# Serves one published database for every channel and architecture. With no -# pairs given the stub fails, which is how the unreachable-repository path is +# Serves a repository database assembled by hand from name=version pairs. With +# none given the stub fails, which is how the unreachable-repository path is # exercised. selftest_published() { local root="$1" shift + local staging="$root/stub/db" + local entry name version if [[ $# -gt 0 ]]; then - selftest_db "$root/stub/omarchy.db.tar.zst" "$@" + rm -rf "$staging" + mkdir -p "$staging" + for entry in "$@"; do + name="${entry%=*}" + version="${entry#*=}" + mkdir -p "$staging/$name-$version" + printf '%%FILENAME%%\n%s-%s-x86_64.pkg.tar.zst\n\n%%NAME%%\n%s\n\n%%BASE%%\n%s\n\n%%VERSION%%\n%s\n' \ + "$name" "$version" "$name" "$name" "$version" > "$staging/$name-$version/desc" + done + tar --zstd -cf "$root/stub/omarchy.db.tar.zst" -C "$staging" . fi cat > "$root/stub/curl" <<'STUB' @@ -678,33 +616,19 @@ while [[ $# -gt 0 ]]; do *) url="$1"; shift ;; esac done -case "$url" in - */omarchy.db.tar.zst) - channel="${url%/omarchy.db.tar.zst}" - arch="${channel##*/}" - channel="${channel%/*}" - db="$(dirname "$0")/omarchy-${channel##*/}-$arch.db.tar.zst" - [[ -f "$db" ]] || db="$(dirname "$0")/omarchy.db.tar.zst" - ;; - */aarch64/*) - repo="${url%/*}" - db="$(dirname "$0")/alarm-${repo##*/}.db" - ;; - *) db="" ;; -esac +if [[ "$url" == */aarch64/* ]]; then + repo="${url%/*}" + repo="${repo##*/}" + db="$(dirname "$0")/alarm-$repo.db" +else + db="$(dirname "$0")/omarchy.db.tar.zst" +fi [[ -f "$db" && -n "$out" ]] || exit 22 cp "$db" "$out" STUB chmod +x "$root/stub/curl" } -# Serves one channel and architecture its own published database. -selftest_channel() { # selftest_channel [name=version...] - local root="$1" channel="$2" arch="$3" - shift 3 - selftest_db "$root/stub/omarchy-$channel-$arch.db.tar.zst" "$@" -} - selftest_alarm() { local root="$1" shift @@ -744,15 +668,12 @@ cmd_self_test() { fi } - # SELFTEST_ARCHES stands in for CI_ARCHES; "default" leaves it unset, as the - # scheduled workflow does. run_case() { local root="$1" shift - local status=0 arches=(CI_ARCHES="${SELFTEST_ARCHES:-x86_64}") - [[ "${SELFTEST_ARCHES:-}" != default ]] || arches=(-u CI_ARCHES) - env "${arches[@]}" PATH="$root/stub:$PATH" \ - "$root/bin/sync-rebuilds" "$@" > "$root/output" 2>&1 || status=$? + local status=0 + OMARCHY_ARCHES="${SELFTEST_ARCHES:-x86_64}" \ + PATH="$root/stub:$PATH" "$root/bin/sync-rebuilds" "$@" > "$root/output" 2>&1 || status=$? echo "$status" } @@ -860,68 +781,6 @@ cmd_self_test() { unset SELFTEST_ARCHES check "pkgrel untouched" 1 "$(pkgrel_of "$root/pkgbuilds/t-x86")" - echo "An ARM-only package is checked when no architecture list is given:" - root=$(selftest_root arm-default) - selftest_package "$root" t-arm-default 1 '{"source":"local","rebuild_on":["dep-a"],"rebuilt_against":{"aarch64":{"dep-a":"1-1"}}}' 1.0 aarch64 - selftest_pacman "$root" - selftest_published "$root" - selftest_alarm "$root" dep-a=2-1 - SELFTEST_ARCHES=default - check "run succeeds" 0 "$(run_case "$root")" - unset SELFTEST_ARCHES - check "pkgrel bumped" 2 "$(pkgrel_of "$root/pkgbuilds/t-arm-default")" - check "ARM trigger recorded" "2-1" \ - "$(jq -r '.rebuilt_against.aarch64["dep-a"]' "$root/pkgbuilds/t-arm-default/.omarchy/package.json")" - - echo "A dependency carried here for ARM is read from its recipe once edge publishes it:" - root=$(selftest_root carried) - selftest_package "$root" t-carried 1.1 '{"source":"local","channels":["edge"]}' 0.15.1 aarch64 - selftest_package "$root" t-linked 3 '{"source":"local","rebuild_on":["t-carried"],"rebuilt_against":{"x86_64":{"t-carried":"0.15.1-1"},"aarch64":{"t-carried":"0.15.0-2"}}}' 1.0 'x86_64 aarch64' - selftest_pacman "$root" t-carried=0.15.1-1 - selftest_published "$root" - selftest_alarm "$root" t-carried=0.15.1-1 - selftest_channel "$root" edge aarch64 t-carried=0.15.1-1.1 - SELFTEST_ARCHES=default - check "run succeeds" 0 "$(run_case "$root")" - check "pkgrel bumped" 4 "$(pkgrel_of "$root/pkgbuilds/t-linked")" - check "the carried version is recorded, not Arch Linux ARM's" "0.15.1-1.1" \ - "$(jq -r '.rebuilt_against.aarch64["t-carried"]' "$root/pkgbuilds/t-linked/.omarchy/package.json")" - check "x86_64, where nothing is carried, still reads the distribution" "0.15.1-1" \ - "$(jq -r '.rebuilt_against.x86_64["t-carried"]' "$root/pkgbuilds/t-linked/.omarchy/package.json")" - check "a second run succeeds" 0 "$(run_case "$root")" - unset SELFTEST_ARCHES - check "a second run leaves it alone" 4 "$(pkgrel_of "$root/pkgbuilds/t-linked")" - - echo "A carried dependency that edge does not publish yet leaves its dependents alone:" - root=$(selftest_root carried-in-flight) - selftest_package "$root" t-carried 1.2 '{"source":"local","channels":["edge"]}' 0.15.1 aarch64 - selftest_package "$root" t-linked 4 '{"source":"local","rebuild_on":["t-carried"],"rebuilt_against":{"aarch64":{"t-carried":"0.15.1-1.1"}}}' 1.0 aarch64 - selftest_pacman "$root" - selftest_published "$root" - selftest_alarm "$root" t-carried=0.15.1-1 - selftest_channel "$root" edge aarch64 t-carried=0.15.1-1.1 - SELFTEST_ARCHES=aarch64 - check "run succeeds" 0 "$(run_case "$root")" - unset SELFTEST_ARCHES - check "pkgrel untouched" 4 "$(pkgrel_of "$root/pkgbuilds/t-linked")" - check "record untouched" "0.15.1-1.1" \ - "$(jq -r '.rebuilt_against.aarch64["t-carried"]' "$root/pkgbuilds/t-linked/.omarchy/package.json")" - - echo "A carried dependency whose edge database cannot be read fails the run:" - root=$(selftest_root carried-unreadable) - selftest_package "$root" t-carried 1.1 '{"source":"local","channels":["edge"]}' 0.15.1 aarch64 - selftest_package "$root" t-linked 3 '{"source":"local","rebuild_on":["t-carried"],"rebuilt_against":{"aarch64":{"t-carried":"0.15.0-2"}}}' 1.0 aarch64 - selftest_pacman "$root" - selftest_published "$root" - selftest_alarm "$root" t-carried=0.15.1-1 - SELFTEST_ARCHES=aarch64 - check "run fails" 1 "$(run_case "$root")" - check "pkgrel untouched" 3 "$(pkgrel_of "$root/pkgbuilds/t-linked")" - printf 'not a database\n' > "$root/stub/omarchy-edge-aarch64.db.tar.zst" - check "a corrupt download fails the run too" 1 "$(run_case "$root")" - unset SELFTEST_ARCHES - check "pkgrel still untouched" 3 "$(pkgrel_of "$root/pkgbuilds/t-linked")" - echo "A PKGBUILD that branches on CARCH at file scope still reads its version:" root=$(selftest_root carch-branch) mkdir -p "$root/pkgbuilds/t-carch/.omarchy" diff --git a/helpers/paths.sh b/helpers/paths.sh index 1d734a9a..5d6191c3 100644 --- a/helpers/paths.sh +++ b/helpers/paths.sh @@ -43,20 +43,6 @@ reference_arch() { published_arches | head -1 } -# Architectures a merge to master builds and publishes: bin/build-matrix plans -# a PR build for each one a package supports, and publish.yml ships them. This -# is independent of PUBLISHED_ARCHES, so anything deciding what a merge has to -# rebuild (bin/sync-rebuilds) follows this list. CI_ARCHES overrides it. -CI_ARCHES="${CI_ARCHES:-x86_64 aarch64}" - -ci_arches() { - local arch - for arch in $CI_ARCHES; do - require_valid_arch "$arch" - echo "$arch" - done -} - # Scheduled-pipeline state, one file per channel and architecture, so one # architecture's queue or backoff never gates another's. STATE_DIR="${OMARCHY_STATE_DIR:-/root/.state}" diff --git a/pkgbuilds/hyprland/.omarchy/package.json b/pkgbuilds/hyprland/.omarchy/package.json index 0642ff78..9dd97453 100644 --- a/pkgbuilds/hyprland/.omarchy/package.json +++ b/pkgbuilds/hyprland/.omarchy/package.json @@ -15,7 +15,7 @@ ], "rebuilt_against": { "aarch64": { - "aquamarine": "0.15.1-1" + "aquamarine": "0.15.0-2" } } } diff --git a/pkgbuilds/hyprland/PKGBUILD b/pkgbuilds/hyprland/PKGBUILD index 4a5f41cd..cbb70ed8 100644 --- a/pkgbuilds/hyprland/PKGBUILD +++ b/pkgbuilds/hyprland/PKGBUILD @@ -5,7 +5,7 @@ pkgname=(hyprland hyprpm) pkgver=0.56.2 -pkgrel=4 +pkgrel=3 pkgdesc='a highly customizable dynamic tiling Wayland compositor' arch=(aarch64) url="https://github.com/hyprwm/${pkgname^}" From b27a8c609edfd5d79e07a6086ad4d7536a4fc88b Mon Sep 17 00:00:00 2001 From: Marcelo Alcantara Date: Fri, 25 Sep 2026 17:46:20 +1000 Subject: [PATCH 3/4] Drop the aquamarine comment that depends on rebuild detection --- pkgbuilds/aquamarine/PKGBUILD | 1 - 1 file changed, 1 deletion(-) diff --git a/pkgbuilds/aquamarine/PKGBUILD b/pkgbuilds/aquamarine/PKGBUILD index 2941ebdd..a9ed9e0d 100644 --- a/pkgbuilds/aquamarine/PKGBUILD +++ b/pkgbuilds/aquamarine/PKGBUILD @@ -5,7 +5,6 @@ # re-read a connector's possible CRTCs when rescanning, so a Type-C port the # DCP fabric reroutes to another display pipeline gets a CRTC without # restarting the compositor. Drop the carry once hyprwm releases the fix. -# Hyprland is rebuilt whenever this package changes (its rebuild_on). pkgname=aquamarine pkgver=0.15.1 From 4e58d1c77fbf89aad99e86504a2ab5555784047c Mon Sep 17 00:00:00 2001 From: Marcelo Alcantara Date: Fri, 25 Sep 2026 20:45:29 +1000 Subject: [PATCH 4/4] Give cc1plus enough stack for aquamarine under emulation DRM.cpp needs more than 8 MiB of compiler stack. GCC raises its own limit natively, but the aarch64 builder runs under QEMU user-mode emulation, which fixes the guest stack at exec and ignores setrlimit, so cc1plus segfaulted. Unpatched 0.15.1 fails the same way. QEMU_STACK_SIZE sizes it at exec; native builds ignore it and the object code is identical. --- pkgbuilds/aquamarine/PKGBUILD | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkgbuilds/aquamarine/PKGBUILD b/pkgbuilds/aquamarine/PKGBUILD index a9ed9e0d..2b16e747 100644 --- a/pkgbuilds/aquamarine/PKGBUILD +++ b/pkgbuilds/aquamarine/PKGBUILD @@ -44,6 +44,12 @@ prepare() { build() { cd "$_archive" + # cc1plus needs more than 8 MiB of stack for DRM.cpp. GCC raises its own + # limit natively, but under QEMU user-mode emulation (the aarch64 builder) + # the guest stack is fixed at exec and setrlimit is ignored, so the compiler + # segfaults. QEMU reads this at exec; native builds ignore it. The object + # code is identical either way. + export QEMU_STACK_SIZE=64M cmake -B build \ -D CMAKE_INSTALL_PREFIX=/usr \ -D CMAKE_BUILD_TYPE=Release