diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c7203a4..2ebcc7c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,6 +59,7 @@ jobs: ./tests/partial-release.sh ./tests/published-build-plan.sh ./tests/settings-boot-config.sh + ./tests/settings-runtime-profile.sh ./tests/pinned-sources.sh ./tests/controller.sh ./tests/artifact-helpers.sh diff --git a/pkgbuilds/omarchy-settings/PKGBUILD b/pkgbuilds/omarchy-settings/PKGBUILD index 2043463..7a2cb4a 100644 --- a/pkgbuilds/omarchy-settings/PKGBUILD +++ b/pkgbuilds/omarchy-settings/PKGBUILD @@ -13,14 +13,17 @@ pkgname='omarchy-settings' _tag='v4.0.4' _commit='c668141e9c42b13c80c9ca4ea108e11708c5e8a5' pkgver=4.0.4 -pkgrel=3 +pkgrel=4 pkgdesc='Omarchy user defaults, /etc/skel content, fonts, plymouth theme, and support helpers' # Arch-specific because the shipped /etc tree is not the same on every -# architecture: the zram and oomd drop-ins belong to the x86_64 memory stack -# and are left out of the aarch64 package (see package()). The Limine and -# mkinitcpio drop-ins ship on both: UEFI aarch64 installs (DGX Spark, -# Snapdragon X) boot with Limine and an encrypted root exactly like x86_64. -# makepkg only honours the arch-suffixed arrays below on arch-specific packages. +# architecture for older sources: their zram and oomd drop-ins belong to the +# x86_64 memory stack and are left out of the aarch64 package (see package()). +# The Limine and mkinitcpio drop-ins ship on both: UEFI aarch64 installs (DGX +# Spark, Snapdragon X) boot with Limine and an encrypted root exactly like +# x86_64. A source with default/settings-runtime-profile decides at runtime +# which platform-specific files apply, and its aarch64 package ships the same +# files as x86_64. makepkg only honours the arch-suffixed arrays below on +# arch-specific packages. arch=('x86_64' 'aarch64') url='https://github.com/basecamp/omarchy' license=('MIT') @@ -86,14 +89,16 @@ backup+=( 'etc/limine-entry-tool.d/omarchy-uki.conf' ) # backup has no arch-suffixed form, so the x86_64-only drop-ins join it here. -# Each of these paths is removed from the aarch64 package in package(). +# Each of these paths is removed from an older source's aarch64 package in +# package(), which adds them back for a runtime-profile source. +_x86_64_backup=( + 'etc/mkinitcpio.conf.d/thunderbolt_module.conf' + 'etc/modprobe.d/omarchy-usb-autosuspend.conf' + 'etc/systemd/oomd.conf.d/10-omarchy.conf' + 'etc/systemd/zram-generator.conf' +) if [[ $CARCH == x86_64 ]]; then - backup+=( - 'etc/mkinitcpio.conf.d/thunderbolt_module.conf' - 'etc/modprobe.d/omarchy-usb-autosuspend.conf' - 'etc/systemd/oomd.conf.d/10-omarchy.conf' - 'etc/systemd/zram-generator.conf' - ) + backup+=("${_x86_64_backup[@]}") fi optdepends=( @@ -160,6 +165,20 @@ _omarchy_settings_hooks_after() { package() { cd "$srcdir/omarchy" + # A source that decides at runtime which platform-specific files apply (see + # default/settings-runtime-profile in it) ships its whole tree on aarch64, + # with the same backup and optdepends as x86_64. Older sources still leave + # the x86_64 memory stack out there. + local legacy_aarch64=0 + if [[ $CARCH == aarch64 ]]; then + if [[ -f default/settings-runtime-profile ]]; then + backup+=("${_x86_64_backup[@]}") + optdepends+=("${optdepends_x86_64[@]}") + else + legacy_aarch64=1 + fi + fi + # /etc/skel/.config from config/** — system-wide default user config. # Package-owned defaults that live elsewhere in the system belong under # default/** or etc/** instead. @@ -202,12 +221,16 @@ package() { install -Dm644 default/systemd/user/omarchy-tailscale-receive.service "$pkgdir/usr/lib/systemd/user/omarchy-tailscale-receive.service" install -Dm644 default/systemd/user/omarchy-fcitx5.service "$pkgdir/usr/lib/systemd/user/omarchy-fcitx5.service" install -Dm644 default/systemd/user/omarchy-crash-watch.service "$pkgdir/usr/lib/systemd/user/omarchy-crash-watch.service" + # First-run enables this unit, so it ships wherever the source has it. + if [[ -f default/systemd/user/omarchy-brightness-keyboard-auto.service ]]; then + install -Dm644 default/systemd/user/omarchy-brightness-keyboard-auto.service "$pkgdir/usr/lib/systemd/user/omarchy-brightness-keyboard-auto.service" + fi # Marks app.slice (and only app.slice) as a systemd-oomd kill candidate, so # memory pressure costs one app scope instead of the compositor session. # Thresholds live in etc/systemd/oomd.conf.d/10-omarchy.conf. Both this and - # the zram vendor drop-in belong to the x86_64 memory stack: the aarch64 - # install neither enables systemd-oomd nor configures zram swap. - if [[ $CARCH == x86_64 ]]; then + # the zram vendor drop-in belong to the x86_64 memory stack: an older + # source's aarch64 install neither enables systemd-oomd nor configures zram. + if (( ! legacy_aarch64 )); then install -Dm644 default/systemd/user/app.slice.d/10-oomd.conf "$pkgdir/usr/lib/systemd/user/app.slice.d/10-oomd.conf" install -Dm644 default/systemd/zram-generator.conf.d/90-omarchy.conf "$pkgdir/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf" fi @@ -234,22 +257,25 @@ package() { if [[ $CARCH == aarch64 ]]; then # Keep omarchy_hooks.conf and the Limine entry-tool config: without them a # kernel update on an encrypted aarch64 install rebuilds an initramfs with - # no encrypt hook and the machine cannot unlock its root. Only the + # no encrypt hook and the machine cannot unlock its root. An older source's # Thunderbolt module request is x86-specific; ARM kernels lack the module - # and mkinitcpio treats a missing explicit module as an error. - rm -f "$pkgdir/etc/mkinitcpio.conf.d/thunderbolt_module.conf" + # and mkinitcpio treats a missing explicit module as an error. A + # runtime-profile source adds it only where the kernel has the module. + (( ! legacy_aarch64 )) || rm -f "$pkgdir/etc/mkinitcpio.conf.d/thunderbolt_module.conf" # Apple Silicon Macs install this package too. Their initramfs needs the # asahi hook, which omarchy-mac-boot's 90-94 fragments (Aurora) or # mkinitcpio.conf (legacy GRUB Macs) set, and an unconditional HOOKS= here - # would replace it. A source that sets HOOKS outright (v4.0.4) gets its line - # wrapped so it applies only when the hooks loaded so far lack asahi; one that - # already decides per platform (omacom/omarchy#13362) ships as it is. The - # wrapper reads configuration, not the running machine, so it also holds - # when the image is built in a chroot. + # would replace it. An older source that sets HOOKS outright (v4.0.4) gets + # its line wrapped so it applies only when the hooks loaded so far lack + # asahi; one that already decides per platform (omacom/omarchy#13362), and + # every runtime-profile source, ships as it is. The wrapper reads + # configuration, not the running machine, so it also holds when the image + # is built in a chroot. local hooks_conf hooks_confs=() for hooks_conf in "$pkgdir"/etc/mkinitcpio.conf.d/{00-omarchy-hooks,omarchy_hooks}.conf; do [[ -f $hooks_conf ]] || continue hooks_confs+=("$hooks_conf") + (( legacy_aarch64 )) || continue sed -i 's/^\(HOOKS=([^#]*)\)[[:space:]]*$/if [[ " ${HOOKS[*]:-} " != *" asahi "* ]]; then\n \1\nfi/' "$hooks_conf" if grep -q '^HOOKS=' "$hooks_conf"; then echo "${hooks_conf#"$pkgdir"/}: cannot guard this HOOKS= line for Apple Silicon" >&2 @@ -266,9 +292,12 @@ package() { echo "etc/mkinitcpio.conf.d: the aarch64 hooks must keep a Mac's asahi line and set everyone else's" >&2 return 1 fi - # Memory stack: no zram device or zswap on the aarch64 install, and - # systemd-oomd is not enabled there, so the vm.* reclaim tuning written - # for zram would be wrong for it. Keep only the network tuning. + fi + if (( legacy_aarch64 )); then + # Memory stack: no zram device or zswap on an older source's aarch64 + # install, and systemd-oomd is not enabled there, so the vm.* reclaim + # tuning written for zram would be wrong for it. Keep only the network + # tuning. rm -rf "$pkgdir/etc/systemd/oomd.conf.d" rm -f "$pkgdir/etc/systemd/zram-generator.conf" "$pkgdir/etc/tmpfiles.d/omarchy-zswap.conf" cat >"$pkgdir/etc/sysctl.d/99-omarchy-sysctl.conf" <<'EOF' diff --git a/tests/settings-runtime-profile.sh b/tests/settings-runtime-profile.sh new file mode 100755 index 0000000..0fd375b --- /dev/null +++ b/tests/settings-runtime-profile.sh @@ -0,0 +1,214 @@ +#!/bin/bash +# Run the omarchy-settings recipe's package() against synthetic source trees: +# an older source keeps today's per-architecture package, and a source that +# selects its platform profile at runtime ships the same files, backup and +# optdepends on aarch64 as on x86_64. +set -euo pipefail +export LC_ALL=C + +BUILD_ROOT=$(realpath "${BASH_SOURCE[0]%/*}/..") +scratch=$(mktemp -d) +trap 'rm -rf "$scratch"' EXIT + +fail() { + printf 'FAIL: %s\n' "$@" >&2 + exit 1 +} + +files=( + applications/example.desktop + bin/omarchy-debug + bin/omarchy-debug-idle + bin/omarchy-hw-platform + bin/omarchy-upload-log + config/autostart/limine-snapper-notify.desktop + config/hypr/hyprland.lua + default/applications/mimeapps.list + default/bashrc + default/environment.d/10-omarchy-fcitx.conf + default/fontconfig/conf.avail/50-omarchy.conf + default/fonts/omarchy/omarchy.ttf + default/hypr/toggles/flags.lua + default/libalpm/hooks/00-omarchy-platform-guard.hook + default/libalpm/scripts/omarchy-platform-guard + default/limine/default.conf + default/limine/limine.conf + default/nautilus-python/extensions/localsend.py + default/nautilus-python/extensions/transcode.py + default/plymouth/omarchy.plymouth + default/sddm/hyprland.lua + default/sddm/omarchy/Main.qml + default/snapper/root + default/systemd/system-sleep/unmount-fuse + default/systemd/system/plocate-updatedb.service.d/10-omarchy.conf + default/systemd/user/app.slice.d/10-oomd.conf + default/systemd/user/bt-agent.service + default/systemd/user/omarchy-crash-watch.service + default/systemd/user/omarchy-fcitx5.service + default/systemd/user/omarchy-migrate-notify.service + default/systemd/user/omarchy-recover-internal-monitor.service + default/systemd/user/omarchy-sleep-lock.service + default/systemd/user/omarchy-tailscale-receive.service + default/systemd/zram-generator.conf.d/90-omarchy.conf + default/tensaku/state.toml + default/uwsm/env.d/10-omarchy + default/wayland-sessions/omarchy.desktop + default/xdg-terminal-exec/hyprland-xdg-terminals.list + etc/cups/cups-browsed.conf + etc/cups/cups-files.conf + etc/fastfetch/config.jsonc + etc/limine-entry-tool.d/omarchy-defaults.conf + etc/limine-entry-tool.d/omarchy-uki.conf + etc/mkinitcpio.conf.d/omarchy_hooks.conf + etc/mkinitcpio.conf.d/thunderbolt_module.conf + etc/modprobe.d/omarchy-usb-autosuspend.conf + etc/nsswitch.conf + etc/plymouth/plymouthd.conf + etc/security/faillock.conf + etc/sysctl.d/99-omarchy-sysctl.conf + etc/systemd/oomd.conf.d/10-omarchy.conf + etc/systemd/zram-generator.conf + etc/tmpfiles.d/omarchy-zswap.conf + icon.png + icon.txt + logo.svg + logo.txt +) +# Left out of an older source's aarch64 package, and nothing else is. Its boot +# drop-ins ship on both (omacom/omarchy-pkgs#380). +legacy_aarch64_absent=( + etc/mkinitcpio.conf.d/thunderbolt_module.conf + etc/modprobe.d/omarchy-usb-autosuspend.conf + etc/systemd/oomd.conf.d/10-omarchy.conf + etc/systemd/zram-generator.conf + etc/tmpfiles.d/omarchy-zswap.conf + usr/lib/systemd/user/app.slice.d/10-oomd.conf + usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf +) +x86_backup=( + etc/mkinitcpio.conf.d/thunderbolt_module.conf + etc/modprobe.d/omarchy-usb-autosuspend.conf + etc/systemd/oomd.conf.d/10-omarchy.conf + etc/systemd/zram-generator.conf +) +keyboard_unit=default/systemd/user/omarchy-brightness-keyboard-auto.service +platform_guard=( + usr/share/libalpm/hooks/00-omarchy-platform-guard.hook + usr/share/libalpm/scripts/omarchy-hw-platform + usr/share/libalpm/scripts/omarchy-platform-guard +) + +# $1: source tree. Extra arguments are files to add to it. +make_source() { + local tree=$1 path + shift + for path in "${files[@]}" "$@"; do + mkdir -p "$(dirname "$tree/$path")" + printf 'fixture for %s\n' "$path" >"$tree/$path" + done +} + +# Runs package() as makepkg would for one architecture (arch-specific arrays +# merged first) and records the package tree and its metadata. $1: recipe, +# $2: source tree, $3: CARCH, $4: output name, $5: "checkout" to build through +# OMARCHY_SRC, "pinned" for the git source. +package_as() { + local recipe=$1 tree=$2 carch=$3 name=$4 mode=$5 + ( + unset OMARCHY_SRC + [[ $mode == "pinned" ]] || export OMARCHY_SRC=$tree + export CARCH=$carch srcdir=$scratch/$name-src pkgdir=$scratch/$name + mkdir -p "$srcdir" "$pkgdir" + ln -sfn "$tree" "$srcdir/omarchy" + backup=() + # shellcheck disable=SC1090 # Exercise the recipe's own package function. + source "$BUILD_ROOT/pkgbuilds/$recipe/PKGBUILD" + eval "optdepends+=(\"\${optdepends_${carch}[@]}\")" + package + printf '%s\n' "${backup[@]}" | sort >"$scratch/$name.backup" + # shellcheck disable=SC2154 # Set by the recipe. + printf '%s\n' "${optdepends[@]}" >"$scratch/$name.optdepends" + (cd "$pkgdir" && find . \( -type f -o -type l \) | sed 's|^\./||' | sort) >"$scratch/$name.files" + ) +} + +in_list() { + grep -Fxq -- "$1" "$2" +} + +fixtures=$BUILD_ROOT/tests/fixtures/settings-boot +make_source "$scratch/legacy" +cp "$fixtures/omarchy_hooks-v4.0.4.conf" "$scratch/legacy/etc/mkinitcpio.conf.d/omarchy_hooks.conf" +make_source "$scratch/profile" default/settings-runtime-profile "$keyboard_unit" +cp "$fixtures"/omarchy-13362/*.conf "$scratch/profile/etc/mkinitcpio.conf.d/" + +for recipe in omarchy-settings; do + rm -rf "${scratch:?}"/legacy-* "${scratch:?}"/profile-* + # An older source keeps the per-architecture package it has always had. + package_as "$recipe" "$scratch/legacy" x86_64 legacy-x86_64 pinned + package_as "$recipe" "$scratch/legacy" aarch64 legacy-aarch64 pinned + for path in "${legacy_aarch64_absent[@]}"; do + in_list "$path" "$scratch/legacy-x86_64.files" || fail "older source ships $path on x86_64" + ! in_list "$path" "$scratch/legacy-aarch64.files" || fail "older source leaves $path out on aarch64" + done + missing=$(comm -23 "$scratch/legacy-x86_64.files" "$scratch/legacy-aarch64.files") + [[ $missing == "$(printf '%s\n' "${legacy_aarch64_absent[@]}" | sort)" ]] || + fail "older source's aarch64 package differs from x86_64 only by the boot and memory drop-ins" "$missing" + grep -Fxq 'if [[ " ${HOOKS[*]:-} " != *" asahi "* ]]; then' "$scratch/legacy-aarch64/etc/mkinitcpio.conf.d/omarchy_hooks.conf" || + fail "older source's aarch64 HOOKS line applies only without asahi" + cmp -s "$scratch/legacy/etc/mkinitcpio.conf.d/omarchy_hooks.conf" "$scratch/legacy-x86_64/etc/mkinitcpio.conf.d/omarchy_hooks.conf" || + fail 'x86_64 ships the source HOOKS line as it is' + cmp -s "$scratch/legacy/etc/sysctl.d/99-omarchy-sysctl.conf" "$scratch/legacy-x86_64/etc/sysctl.d/99-omarchy-sysctl.conf" || + fail 'x86_64 ships the source sysctl file' + ! cmp -s "$scratch/legacy/etc/sysctl.d/99-omarchy-sysctl.conf" "$scratch/legacy-aarch64/etc/sysctl.d/99-omarchy-sysctl.conf" || + fail 'older source keeps only the network tuning on aarch64' + for path in "${x86_backup[@]}"; do + in_list "$path" "$scratch/legacy-x86_64.backup" || fail "x86_64 backs up $path" + ! in_list "$path" "$scratch/legacy-aarch64.backup" || fail "older source's aarch64 backup leaves out $path" + done + for path in etc/mkinitcpio.conf.d/omarchy_hooks.conf etc/limine-entry-tool.d/omarchy-defaults.conf; do + in_list "$path" "$scratch/legacy-aarch64.backup" || fail "older source's aarch64 package backs up $path" + done + grep -q '^limine:' "$scratch/legacy-x86_64.optdepends" || fail 'x86_64 suggests the boot stack its drop-ins are for' + ! grep -q '^limine:' "$scratch/legacy-aarch64.optdepends" || fail "older source's aarch64 package suggests no boot stack" + ! in_list usr/lib/systemd/user/omarchy-brightness-keyboard-auto.service "$scratch/legacy-x86_64.files" || + fail 'a source without the keyboard unit ships none' + echo "PASS: $recipe: an older source keeps its per-architecture package" + + # A runtime-profile source ships the same tree and metadata on both. + package_as "$recipe" "$scratch/profile" x86_64 profile-x86_64 checkout + package_as "$recipe" "$scratch/profile" aarch64 profile-aarch64 pinned + # The pacman platform guard is the profile's one exception: aarch64 only + # where the recipe says so (omacom/omarchy-pkgs#691). + for path in "${platform_guard[@]}"; do + in_list "$path" "$scratch/profile-aarch64.files" || fail "aarch64 ships the platform guard's $path" + done + grep -Fxv -f <(printf '%s\n' "${platform_guard[@]}") "$scratch/profile-x86_64.files" >"$scratch/profile-x86_64.compared" + grep -Fxv -f <(printf '%s\n' "${platform_guard[@]}") "$scratch/profile-aarch64.files" >"$scratch/profile-aarch64.compared" + cmp -s "$scratch/profile-x86_64.compared" "$scratch/profile-aarch64.compared" || + fail 'runtime-profile source ships the same files on both architectures' \ + "$(diff "$scratch/profile-x86_64.compared" "$scratch/profile-aarch64.compared")" + while IFS= read -r path; do + if [[ -L $scratch/profile-x86_64/$path ]]; then + [[ $(readlink "$scratch/profile-x86_64/$path") == "$(readlink "$scratch/profile-aarch64/$path")" ]] + else + cmp -s "$scratch/profile-x86_64/$path" "$scratch/profile-aarch64/$path" + fi || fail "runtime-profile source ships the same $path on both architectures" + done <"$scratch/profile-x86_64.files" + cmp -s "$scratch/profile-x86_64.backup" "$scratch/profile-aarch64.backup" || + fail 'runtime-profile source backs up the same files on both architectures' + cmp -s "$scratch/profile-x86_64.optdepends" "$scratch/profile-aarch64.optdepends" || + fail 'runtime-profile source has the same optdepends on both architectures' + in_list etc/mkinitcpio.conf.d/00-omarchy-hooks.conf "$scratch/profile-x86_64.backup" || + fail 'the HOOKS baseline drop-in is backed up where the source has it' + in_list usr/lib/systemd/user/omarchy-brightness-keyboard-auto.service "$scratch/profile-aarch64.files" || + fail 'the keyboard unit first-run enables ships when the source has it' + comm -13 "$scratch/legacy-x86_64.files" "$scratch/profile-x86_64.files" >"$scratch/added" + for conf in 00-omarchy-hooks.conf omarchy_hooks.conf; do + cmp -s "$fixtures/omarchy-13362/$conf" "$scratch/profile-aarch64/etc/mkinitcpio.conf.d/$conf" || + fail "runtime-profile source ships its $conf as it is on aarch64" + done + [[ $(cat "$scratch/added") == "$(printf '%s\n' usr/lib/systemd/user/omarchy-brightness-keyboard-auto.service usr/share/omarchy/default/settings-runtime-profile "usr/share/omarchy/$keyboard_unit" etc/mkinitcpio.conf.d/00-omarchy-hooks.conf | sort)" ]] || + fail 'x86_64 gains only the new source files from a runtime-profile source' "$(cat "$scratch/added")" + echo "PASS: $recipe: a runtime-profile source ships the full set on aarch64" +done