#!/bin/bash set -euo pipefail source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" upgrade_to_quattro="$ROOT/bin/omarchy-upgrade-to-quattro" snapshot_line=$(grep -n '^create_pre_upgrade_snapshot$' "$upgrade_to_quattro" | cut -d: -f1) pacman_line=$(grep -n '^configure_pacman_channel$' "$upgrade_to_quattro" | cut -d: -f1) [[ -n $snapshot_line && -n $pacman_line ]] || fail "upgrade snapshot and first mutation calls exist" (( snapshot_line < pacman_line )) || fail "upgrade snapshot runs before pacman configuration" grep -F 'omarchy-snapshot create || (($? == 127))' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade snapshots the system before mutation" # The mirrors are repointed immediately before the keyrings go in, so only a # forced refresh replaces the legacy database and its stale checksums. grep -F 'pacman -Syy --noconfirm archlinux-keyring omarchy-keyring' "$upgrade_to_quattro" >/dev/null if grep -F 'pacman -Sy --noconfirm archlinux-keyring omarchy-keyring' "$upgrade_to_quattro" >/dev/null; then fail "Omarchy 4 upgrade forces a database refresh before installing keyrings" fi pass "Omarchy 4 upgrade forces a database refresh before installing keyrings" grep -F 'pacman -Syu --needed' "$upgrade_to_quattro" >/dev/null grep -F 'omarchy-update-aur-pkgs' "$upgrade_to_quattro" >/dev/null grep -F 'omarchy-update-available' "$upgrade_to_quattro" >/dev/null grep -F 'omarchy-update-mise' "$upgrade_to_quattro" >/dev/null grep -F 'run_final_system_package_upgrade' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade completes package update checks" grep -F 'run_post_upgrade_migrations' "$upgrade_to_quattro" >/dev/null grep -F 'omarchy-migrate' "$upgrade_to_quattro" >/dev/null grep -F 'dust' "$upgrade_to_quattro" >/dev/null grep -F 'satty' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade applies packaged migrations" if grep -F 'skip-first-run-update-notification' "$upgrade_to_quattro" >/dev/null; then fail "Omarchy 4 upgrade does not use notification-specific first-run state" fi pass "Omarchy 4 upgrade completes first-run as one lifecycle" grep -F 'touch "$done_dir/first-run-user" "$done_dir/finalize-user"' "$upgrade_to_quattro" >/dev/null grep -F 'rm -f "$state_dir/first-run-user.done" "$state_dir/finalize-user.done"' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade completes first-run and migrates legacy completion markers" # The script runs from the branch against whatever packaged tree the channel # serves, so a packaged command missing from an older build must never be able # to abort the upgrade partway through. if grep -F '"$root/bin/omarchy-done"' "$upgrade_to_quattro" >/dev/null; then fail "Omarchy 4 upgrade writes completion markers without the packaged omarchy-done" fi pass "Omarchy 4 upgrade writes completion markers without the packaged omarchy-done" for guarded_step in omarchy-refresh-applications 'omarchy-bar defaults'; do grep -F "run_as_user_omarchy $guarded_step ||" "$upgrade_to_quattro" >/dev/null || fail "Omarchy 4 upgrade survives a packaged tree without $guarded_step" done pass "Omarchy 4 upgrade survives a packaged tree missing top-level commands" grep -F 'configure_snapper_policy' "$upgrade_to_quattro" >/dev/null grep -F '/usr/share/omarchy/install/config/snapper.sh' "$upgrade_to_quattro" >/dev/null grep -F 'bash -euo pipefail "$snapper_config_script"' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade normalizes Snapper retention" grep -F 'configure_lock_authentication' "$upgrade_to_quattro" >/dev/null grep -F 'OMARCHY_INSTALL_USER="$target_user"' "$upgrade_to_quattro" >/dev/null grep -F '"$apply_lock"' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade configures lock screen authentication for the target user" grep -F 'OMARCHY_UPGRADE_TO_QUATTRO_LIVE=1' "$upgrade_to_quattro" >/dev/null grep -F 'systemd-networkd.service' "$upgrade_to_quattro" >/dev/null grep -F 'systemd-networkd.socket' "$upgrade_to_quattro" >/dev/null grep -F 'systemd-networkd-resolve-hook.socket' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade retires systemd-networkd for NetworkManager" # Booting with both managers enabled leaves them fighting over the Wi-Fi # adapter, so enabling NetworkManager and disabling iwd cannot be separated by # any step that might abort in between. function_body() { awk -v name="$1" '$0 == name "() {" { inside = 1; next } inside && $0 == "}" { exit } inside' "$upgrade_to_quattro" } if function_body cleanup_retired_services | grep -F 'systemctl disable iwd' >/dev/null; then fail "Omarchy 4 upgrade does not retire iwd in a step separate from the NetworkManager enable" fi grep -A1 -F ' enable_system_service NetworkManager.service' "$upgrade_to_quattro" | grep -F 'as_root systemctl disable iwd.service' >/dev/null || fail "Omarchy 4 upgrade retires iwd in the step that enables NetworkManager" pass "Omarchy 4 upgrade switches from iwd to NetworkManager atomically" # set -e aborts silently, so only an explicit banner distinguishes a # half-upgraded system from a finished one. grep -Fx 'trap cleanup_on_exit EXIT' "$upgrade_to_quattro" >/dev/null || fail "Omarchy 4 upgrade reports an aborted run instead of exiting silently" cleanup_body=$(function_body cleanup_on_exit) grep -F 'upgrade_started && ! upgrade_completed' <<<"$cleanup_body" >/dev/null || fail "Omarchy 4 upgrade reports an aborted run instead of exiting silently" grep -F 'Upgrade incomplete - do NOT reboot.' <<<"$cleanup_body" >/dev/null || fail "Omarchy 4 upgrade reports an aborted run instead of exiting silently" grep -F 'exit "$exit_status"' <<<"$cleanup_body" >/dev/null || fail "Omarchy 4 upgrade preserves the failing exit status" grep -F '>&2' <<<"$cleanup_body" >/dev/null || fail "Omarchy 4 upgrade reports an aborted run on stderr" started_line=$(grep -n '^upgrade_started=1$' "$upgrade_to_quattro" | cut -d: -f1) completed_line=$(grep -n '^upgrade_completed=1$' "$upgrade_to_quattro" | cut -d: -f1) suppress_line=$(grep -n '^suppress_hyprland_config_reload$' "$upgrade_to_quattro" | cut -d: -f1) # The reboot is the cutover, so the last mutating step hands the live session # back rather than swapping the shell out underneath it. last_step_line=$(grep -n '^restore_hyprland_config_reload$' "$upgrade_to_quattro" | cut -d: -f1) [[ -n $started_line && -n $completed_line && -n $suppress_line && -n $last_step_line ]] || fail "upgrade progress markers and the mutating step range exist" (( started_line < suppress_line )) || fail "the upgrade is marked started before the first mutation" (( completed_line > last_step_line )) || fail "the upgrade is marked complete only after the last step" pass "Omarchy 4 upgrade reports an aborted run instead of exiting silently" # Ordering alone would still pass if either retired entry point came back, so # name them: the reboot is the cutover, and nothing may swap the shell out from # under the session being replaced. ! grep -q 'start_omarchy_shell_session' "$upgrade_to_quattro" || fail "Omarchy 4 upgrade does not start the shell in the session it is replacing" ! grep -q 'stop_retired_session_processes' "$upgrade_to_quattro" || fail "Omarchy 4 upgrade leaves the retired session processes running until reboot" pass "Omarchy 4 upgrade leaves the Omarchy 3 session alone until the reboot" grep -F 'omarchy-bar defaults' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade restores service-aware bar defaults" grep -F 'install_hardware_transition_packages' "$upgrade_to_quattro" >/dev/null grep -F 'sof-firmware' "$upgrade_to_quattro" >/dev/null grep -F 'vulkan-intel' "$upgrade_to_quattro" >/dev/null grep -F 'apply_user_hardware_transition' "$upgrade_to_quattro" >/dev/null grep -F 'DX13260' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade backfills hardware support from the legacy release" grep -F 'omarchy-refresh-applications' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade refreshes application launchers" grep -F '/etc/systemd/system.conf.d/99-omarchy-nofile.conf' "$upgrade_to_quattro" >/dev/null grep -F '/etc/systemd/user.conf.d/99-omarchy-nofile.conf' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade removes stale nofile drop-ins" cmdline_line=$(grep -n '^preserve_kernel_cmdline_root$' "$upgrade_to_quattro" | cut -d: -f1) packages_line=$(grep -n '^install_omarchy_quattro_packages$' "$upgrade_to_quattro" | cut -d: -f1) [[ -n $cmdline_line && -n $packages_line ]] || fail "kernel cmdline preservation and package install calls exist" (( packages_line < cmdline_line )) || fail "kernel cmdline preservation runs once limine-mkinitcpio is installed" grep -F '/etc/default/limine' "$upgrade_to_quattro" >/dev/null grep -F 'KERNEL_CMDLINE[default]+=" ${boot_params[*]}"' "$upgrade_to_quattro" >/dev/null grep -F 'cat /proc/cmdline' "$upgrade_to_quattro" >/dev/null grep -F 'findmnt -no UUID /' "$upgrade_to_quattro" >/dev/null grep -F 'rootflags=subvol=' "$upgrade_to_quattro" >/dev/null grep -F 'cryptdevice' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade preserves the kernel cmdline root parameters" # The += drop-ins make limine-entry-tool ignore /etc/kernel/cmdline and # /proc/cmdline, so only the tool's own merge can say whether root= survives. # Queried for the default key, so a kernel-specific pin cannot cover for the # entries this repairs. grep -F 'limine-entry-tool --get-cmdline default' "$upgrade_to_quattro" >/dev/null grep -F "grep -qE '(^|[[:space:]])root='" "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade asks limine-entry-tool whether root= survives" # The crypt layer hides in the parents on LVM-on-LUKS, and a partial cmdline # for an encrypted root must not be written at all. grep -F 'findmnt -no SOURCE --nofsroot /' "$upgrade_to_quattro" >/dev/null grep -F 'lsblk -nso TYPE "$root_source"' "$upgrade_to_quattro" >/dev/null grep -F 'grep -qx crypt' "$upgrade_to_quattro" >/dev/null grep -F '((have_mount_mode)) || boot_params+=(rw)' "$upgrade_to_quattro" >/dev/null pass "Omarchy 4 upgrade repair path refuses a partial dm-crypt cmdline" # The cmdline that boots is the one embedded in the UKIs, and an unverified # root= must block the reboot rather than just warn. grep -F -- '--only-section=.cmdline' "$upgrade_to_quattro" >/dev/null grep -F "as_root find /boot/EFI/Linux -maxdepth 1 -name 'omarchy_linux*.efi'" "$upgrade_to_quattro" >/dev/null grep -F 'boot_cmdline_unsafe=1' "$upgrade_to_quattro" >/dev/null unsafe_line=$(grep -n 'if (( boot_cmdline_unsafe )); then' "$upgrade_to_quattro" | cut -d: -f1) reboot_line=$(grep -n 'Rebooting because --reboot was passed' "$upgrade_to_quattro" | cut -d: -f1) [[ -n $unsafe_line && -n $reboot_line ]] || fail "reboot gate and reboot branch exist" (( unsafe_line < reboot_line )) || fail "an unverified kernel cmdline blocks the reboot" pass "Omarchy 4 upgrade verifies the UKIs and refuses to reboot unverified"