diff --git a/bin/omarchy-update-system-pkgs b/bin/omarchy-update-system-pkgs index 564f9548..7b197504 100755 --- a/bin/omarchy-update-system-pkgs +++ b/bin/omarchy-update-system-pkgs @@ -11,6 +11,10 @@ echo -e "\e[32m\nUpdate system packages\e[0m" # as unowned files; pacman would refuse the omarchy-settings upgrade on first # encounter. Drop each entry once the transition release is the baseline. # +# An entry has to ship at least one release before the package starts owning the +# path. pacman checks file conflicts during transaction prepare, so the copy of +# this script running the upgrade is the one already on disk. +# # The /usr/share/omarchy/* entry is permanent: that tree is wholly owned by # the omarchy packages, but files can land there unowned (in-place extension # work, script-written files), which would abort the whole upgrade. Packaged @@ -37,7 +41,6 @@ sudo env OMARCHY_UPDATE_PACMAN=1 pacman -Syu --noconfirm \ --overwrite '/etc/systemd/system/plocate-updatedb.service.d/ac-only.conf' \ --overwrite '/etc/systemd/system.conf.d/20-omarchy-nofile.conf' \ --overwrite '/etc/systemd/user.conf.d/20-omarchy-nofile.conf' \ - --overwrite '/etc/systemd/zram-generator.conf' \ --overwrite '/usr/lib/systemd/system-sleep/unmount-fuse' \ --overwrite '/usr/share/plymouth/themes/omarchy/*' \ --overwrite '/usr/share/sddm/hyprland.lua' \ diff --git a/bin/omarchy-upgrade-to-quattro b/bin/omarchy-upgrade-to-quattro index 69dccde5..b431ef34 100755 --- a/bin/omarchy-upgrade-to-quattro +++ b/bin/omarchy-upgrade-to-quattro @@ -1087,7 +1087,6 @@ run_final_system_package_upgrade() { --overwrite '/etc/systemd/system/plocate-updatedb.service.d/ac-only.conf' \ --overwrite '/etc/systemd/system.conf.d/20-omarchy-nofile.conf' \ --overwrite '/etc/systemd/user.conf.d/20-omarchy-nofile.conf' \ - --overwrite '/etc/systemd/zram-generator.conf' \ --overwrite '/usr/lib/systemd/system-sleep/unmount-fuse' \ --overwrite '/usr/share/plymouth/themes/omarchy/*' \ --overwrite '/usr/share/sddm/hyprland.lua' \ diff --git a/etc/systemd/zram-generator.conf b/default/systemd/zram-generator.conf.d/90-omarchy.conf similarity index 100% rename from etc/systemd/zram-generator.conf rename to default/systemd/zram-generator.conf.d/90-omarchy.conf diff --git a/docs/file-layout.md b/docs/file-layout.md index 321c13aa..2720d382 100644 --- a/docs/file-layout.md +++ b/docs/file-layout.md @@ -106,6 +106,7 @@ default/** ──► omarchy-settings /usr/share/omarchy ├─ applications/mimeapps.list /usr/share/applications/mimeapps.list ├─ systemd/user/*.{service,path} /usr/lib/systemd/user/ ├─ systemd/system-sleep/unmount-fuse /usr/lib/systemd/system-sleep/ + ├─ systemd/zram-generator.conf.d/90-omarchy.conf /usr/lib/systemd/zram-generator.conf.d/ ├─ fonts/omarchy/omarchy.ttf /usr/share/fonts/omarchy/ ├─ sddm/omarchy/ /usr/share/sddm/themes/omarchy/ ├─ sddm/hyprland.lua /usr/share/sddm/hyprland.lua @@ -290,6 +291,7 @@ return to the packaged default. | Runtime tweak that needs `$HOME` or live system state | extend `omarchy-finalize-user`, or add a per-user leaf under `install/user/` and wire into `install/user/all.sh` | | One-time root-side setup step | `install/config/*.sh` or `install/hardware/*.sh`, wire into `install/config/all.sh` or `install/hardware/all.sh` | | One-time fix for existing installs | `migrations/.sh` | +| Package-owned path something else may already write | Prefer a path nothing else writes, such as a vendor drop-in under `/usr/lib`. Otherwise the `--overwrite` entry in `bin/omarchy-update-system-pkgs` has to ship a release before the file | | User-facing `omarchy-*` command | `bin/omarchy--` — see `GROUP_DESCRIPTIONS` in `bin/omarchy` | | New stock theme | `themes//` (+ matching templates under `default/themed/` if they need theme colors) | | User-installed theme | `~/.config/omarchy/themes//` | diff --git a/migrations/1785013000.sh b/migrations/1785013000.sh new file mode 100644 index 00000000..b511f1a5 --- /dev/null +++ b/migrations/1785013000.sh @@ -0,0 +1,28 @@ +echo "Move zram tuning to a vendor drop-in" + +zram_conf="${OMARCHY_ZRAM_CONF:-/etc/systemd/zram-generator.conf}" + +# The tuning ships as /usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf. +# Drop-ins outrank the main config file, so a leftover /etc copy decides nothing +# and only implies /etc is where zram gets configured. + +[[ -f $zram_conf ]] || exit 0 + +# Package-owned copies go away with their package on upgrade. +pacman -Qo "$zram_conf" &>/dev/null && exit 0 + +# archinstall writes exactly a [zram0] section with one compression-algorithm +# line. Anything else is a deliberate local override. grep exits 1 on a config +# that sets nothing at all, which omarchy-migrate's -e would take as a failed +# migration and block every migration behind this one. +settings=$(grep -vE '^[[:space:]]*([#;]|$)' "$zram_conf" | tr -d '[:space:]') || true + +if [[ -z $settings || $settings =~ ^\[zram0\]compression-algorithm=[[:alnum:]-]+$ ]]; then + # A refused sudo just leaves the file for next time; tidying is not worth + # failing the migration chain over. + sudo rm -f "$zram_conf" || true +else + echo "Keeping $zram_conf; it has local edits." + echo "Omarchy's drop-in overrides it. Move your changes to" + echo "/etc/systemd/zram-generator.conf.d/99-local.conf to keep them in effect." +fi diff --git a/test/shell.d/config-test.sh b/test/shell.d/config-test.sh index 8a9f0471..905df673 100755 --- a/test/shell.d/config-test.sh +++ b/test/shell.d/config-test.sh @@ -122,6 +122,7 @@ package_defaults = [ ("default/systemd/user/omarchy-recover-internal-monitor.service", "/usr/lib/systemd/user/omarchy-recover-internal-monitor.service", "systemd/user/omarchy-recover-internal-monitor.service"), ("default/systemd/user/omarchy-update-user-notify.service", "/usr/lib/systemd/user/omarchy-update-user-notify.service", "systemd/user/omarchy-update-user-notify.service"), ("default/systemd/user/omarchy-update-user-notify.path", "/usr/lib/systemd/user/omarchy-update-user-notify.path", "systemd/user/omarchy-update-user-notify.path"), + ("default/systemd/zram-generator.conf.d/90-omarchy.conf", "/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf", "systemd/zram-generator.conf.d/90-omarchy.conf"), ("default/fonts/omarchy/omarchy.ttf", "/usr/share/fonts/omarchy/omarchy.ttf", "omarchy.ttf"), ("default/snapper/root", "/etc/snapper/config-templates/omarchy", "snapper/root"), ] diff --git a/test/shell.d/zram-migration-test.sh b/test/shell.d/zram-migration-test.sh new file mode 100644 index 00000000..f4fca7d9 --- /dev/null +++ b/test/shell.d/zram-migration-test.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh" + +migration=$(grep -rl 'Move zram tuning to a vendor drop-in' "$ROOT/migrations" | head -n 1 || true) +[[ -n $migration ]] || fail "zram drop-in migration exists" + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +# The migration shells out to pacman (ownership check) and sudo (removal). +# Stub both so the test never touches the real system, and let each case pick +# what `pacman -Qo` reports through PACMAN_OWNS. +stub_bin="$TMPDIR/bin" +mkdir -p "$stub_bin" + +cat >"$stub_bin/pacman" <<'STUB' +#!/bin/bash +[[ ${PACMAN_OWNS:-0} == 1 ]] +STUB + +cat >"$stub_bin/sudo" <<'STUB' +#!/bin/bash +exec "$@" +STUB + +chmod +x "$stub_bin/pacman" "$stub_bin/sudo" + +# omarchy-migrate runs each migration with `bash -euo pipefail` and stops the +# whole chain on a non-zero exit, so match that invocation exactly. +run_migration() { + local conf="$1" + PATH="$stub_bin:$PATH" OMARCHY_ZRAM_CONF="$conf" \ + bash -euo pipefail "$migration" >/dev/null || + fail "migration exits clean for $(basename "$conf")" +} + +# archinstall's own output: a [zram0] section with nothing but the algorithm. +conf="$TMPDIR/archinstall.conf" +printf '[zram0]\ncompression-algorithm = zstd\n' >"$conf" +run_migration "$conf" +[[ -f $conf ]] && fail "migration removes archinstall's generated config" +pass "migration removes archinstall's generated config" + +# Same shape, different algorithm, plus comments and blank lines. +conf="$TMPDIR/commented.conf" +printf '# written by archinstall\n\n[zram0]\ncompression-algorithm = lz4\n\n' >"$conf" +run_migration "$conf" +[[ -f $conf ]] && fail "migration ignores comments and a non-zstd algorithm" +pass "migration ignores comments and a non-zstd algorithm" + +# A config that sets nothing decides nothing, and must not take the migration +# chain down with it. +conf="$TMPDIR/comments-only.conf" +printf '# nothing to see here\n\n' >"$conf" +run_migration "$conf" +[[ -f $conf ]] && fail "migration removes a config that sets nothing" +pass "migration removes a config that sets nothing" + +conf="$TMPDIR/empty.conf" +: >"$conf" +run_migration "$conf" +[[ -f $conf ]] && fail "migration removes an empty config" +pass "migration removes an empty config" + +# A local override must survive. +conf="$TMPDIR/local.conf" +printf '[zram0]\ncompression-algorithm = zstd\nzram-size = ram / 4\n' >"$conf" +run_migration "$conf" +[[ -f $conf ]] || fail "migration keeps a locally edited config" +pass "migration keeps a locally edited config" + +# Package-owned copies go away with their package; the migration must not touch +# them. +conf="$TMPDIR/owned.conf" +printf '[zram0]\ncompression-algorithm = zstd\n' >"$conf" +PATH="$stub_bin:$PATH" PACMAN_OWNS=1 OMARCHY_ZRAM_CONF="$conf" \ + bash -euo pipefail "$migration" >/dev/null || + fail "migration exits clean for a package-owned config" +[[ -f $conf ]] || fail "migration keeps a package-owned config" +pass "migration keeps a package-owned config" + +# Nothing to do, and running twice must stay clean. +conf="$TMPDIR/absent.conf" +run_migration "$conf" +run_migration "$conf" +pass "migration no-ops when the config is already gone"