Finish v4 upgrade cleanup

This commit is contained in:
Ryan Hughes
2026-06-04 18:38:25 -04:00
parent 0804962619
commit d0cac7346a
9 changed files with 455 additions and 61 deletions
-5
View File
@@ -1,5 +0,0 @@
#!/bin/bash
# omarchy:summary=Overwrite the user config for fastfetch with the Omarchy default.
omarchy-refresh-config fastfetch/config.jsonc
+400 -44
View File
@@ -146,6 +146,30 @@ run_as_user_session() {
"$@"
}
package_installed_exact() {
local pkg="$1"
pacman -Qq "$pkg" 2>/dev/null | grep -Fxq "$pkg"
}
mark_packages_explicit() {
local pkg installed_pkg
local installed_packages=()
for pkg in "$@"; do
# pacman -Qq resolves installed providers too (for example nvim -> neovim),
# while package_installed_exact intentionally does not.
installed_pkg=$(pacman -Qq "$pkg" 2>/dev/null | head -n1 || true)
[[ -n $installed_pkg ]] && installed_packages+=("$installed_pkg")
done
((${#installed_packages[@]})) || return 0
mapfile -t installed_packages < <(printf '%s\n' "${installed_packages[@]}" | sort -u)
if ! as_root pacman -D --asexplicit "${installed_packages[@]}" >/dev/null; then
warn "Could not mark installed default packages as explicit; retired-package cleanup may leave extra dependencies installed."
fi
}
target_hyprland_pid() {
pgrep -u "$target_uid" -x Hyprland 2>/dev/null | head -n1 || true
}
@@ -416,6 +440,59 @@ remove_legacy_installer_package() {
fi
}
remove_legacy_limine_configs() {
# Mirrors the old 1762446739 migration: old Limine installs sometimes left
# alternate limine.conf files in paths Limine searches before /boot/limine.conf.
# If any are still present, Limine may ignore the package-managed default config.
local canonical_limine_config=/boot/limine.conf
local legacy_limine_configs=(
/boot/EFI/arch-limine/limine.conf
/boot/EFI/limine/limine.conf
/boot/EFI/BOOT/limine.conf
/boot/limine/limine.conf
)
local legacy_limine_config
local found_legacy_limine_configs=()
for legacy_limine_config in "${legacy_limine_configs[@]}"; do
if as_root test -f "$legacy_limine_config"; then
found_legacy_limine_configs+=("$legacy_limine_config")
fi
done
((${#found_legacy_limine_configs[@]})) || return 0
if ! as_root test -f "$canonical_limine_config"; then
fail "Legacy Limine configs exist (${found_legacy_limine_configs[*]}) but $canonical_limine_config does not. Do not reboot until the bootloader config is repaired."
fi
log "Removing legacy alternate Limine configs"
as_root rm -f "${found_legacy_limine_configs[@]}"
}
normalize_limine_config() {
local machine_id legacy_uki
as_root test -f /boot/limine.conf || return 0
log "Normalizing Limine config"
# Mirrors old 1777570652: normalize British/American spelling, the old color
# index, and help colors that pre-4 installs may never have migrated.
as_root sed -i -E 's/^interface_branding_colou?r: 2$/interface_branding_color: 9ece6a/' /boot/limine.conf
as_root sed -i 's/^interface_branding_colour: /interface_branding_color: /' /boot/limine.conf
as_root sed -i -E '/^interface_help_colou?r(_bright)?:/d' /boot/limine.conf
as_root sed -i '/^interface_branding_color:/a interface_help_color_bright: 9ece6a' /boot/limine.conf
as_root sed -i '/^interface_branding_color:/a interface_help_color: 9ece6a' /boot/limine.conf
# Pre-4 custom-UKI installs used <machine-id>_linux.efi. Omarchy 4 uses the
# stable omarchy_linux.efi path generated by limine-entry-tool.
machine_id=$(as_root cat /etc/machine-id 2>/dev/null || true)
legacy_uki="/boot/EFI/Linux/${machine_id}_linux.efi"
if [[ -n $machine_id ]] && as_root test -f /boot/EFI/Linux/omarchy_linux.efi && as_root test -f "$legacy_uki"; then
as_root rm -f "$legacy_uki"
fi
}
remove_conflicting_legacy_packages() {
# Remove legacy packages that are known to conflict with Omarchy 4 defaults
# before the main package transaction. Broader retired-package cleanup runs
@@ -435,7 +512,7 @@ remove_conflicting_legacy_packages() {
local pkg
for pkg in "${conflicting_packages[@]}"; do
if pacman -Q "$pkg" >/dev/null 2>&1; then
if package_installed_exact "$pkg"; then
# Some pre-4 meta packages depend on these retired/default packages. We
# intentionally break those old dependency edges before installing the
# Omarchy 4 meta, otherwise pacman prompts to remove conflicts (for
@@ -446,6 +523,17 @@ remove_conflicting_legacy_packages() {
done
}
migrate_1password_beta_package() {
if ! package_installed_exact 1password-beta && ! package_installed_exact 1password-beta-bin; then
return 0
fi
log "Replacing 1Password Beta with stable 1Password"
if ! as_root pacman -S --noconfirm --ask 4 1password; then
warn "Could not replace 1Password Beta with stable 1Password; leaving the existing 1Password package installed."
fi
}
install_omarchy_4_packages() {
# omarchy-limine and omarchy-dev-tools are no longer separate packages:
# omarchy-limine's content (bootloader + snapper configs) folded into
@@ -457,19 +545,25 @@ install_omarchy_4_packages() {
omarchy-settings
omarchy-nvim
omarchy
# checkupdates support for update tooling
fakeroot
pacman-contrib
)
local base_packages=()
log "Installing Omarchy 4 packages"
# --noconfirm answers "no" to conflict-removal prompts. --ask 4 preselects
# removing the conflicting package, which is required for legacy packages like
# ttf-jetbrains-mono-nerd -> ttf-jetbrains-mono-nerd-basic.
as_root pacman -Syu --needed --noconfirm --ask 4 --overwrite='*' "${core_packages[@]}"
as_root env OMARCHY_UPDATE_PACMAN=1 pacman -Syu --needed --noconfirm --ask 4 --overwrite='*' "${core_packages[@]}"
mark_packages_explicit "${core_packages[@]}"
if [[ -f /usr/share/omarchy/install/omarchy-base.packages ]]; then
log "Installing Omarchy 4 default package set"
mapfile -t base_packages < <(sed -e 's/[[:space:]]*#.*$//' -e '/^[[:space:]]*$/d' /usr/share/omarchy/install/omarchy-base.packages)
if (( ${#base_packages[@]} )); then
as_root pacman -S --needed --noconfirm --ask 4 --overwrite='*' "${base_packages[@]}"
mark_packages_explicit "${base_packages[@]}"
fi
else
warn "/usr/share/omarchy/install/omarchy-base.packages was not found; skipping default package set install."
@@ -488,13 +582,11 @@ install_omarchy_4_packages() {
wireplumber
)
as_root pacman -S --needed --noconfirm --ask 4 --overwrite='*' "${audio_packages[@]}"
mark_packages_explicit "${audio_packages[@]}"
}
remove_retired_default_packages() {
local retired_packages=(
1password-beta
1password-cli
alacritty
asdcontrol-git
blueberry
bluetui
@@ -517,7 +609,6 @@ remove_retired_default_packages() {
elephant-websearch
fcitx5-configtool
gcc14
github-cli
hypridle
hyprlock
impala
@@ -538,10 +629,9 @@ remove_retired_default_packages() {
playerctl
polkit-gnome
qt5-remoteobjects
signal-desktop
spotify
swaybg
swayosd
walker-bin
ttf-jetbrains-mono
ttf-jetbrains-mono-nerd
vlc
@@ -559,7 +649,7 @@ remove_retired_default_packages() {
local pkg
local installed_retired=()
for pkg in "${retired_packages[@]}"; do
if pacman -Q "$pkg" >/dev/null 2>&1; then
if package_installed_exact "$pkg"; then
installed_retired+=("$pkg")
fi
done
@@ -594,7 +684,7 @@ remove_retired_default_packages() {
read -r -a group_packages <<<"$group"
installed_group=()
for group_pkg in "${group_packages[@]}"; do
if pacman -Q "$group_pkg" >/dev/null 2>&1; then
if package_installed_exact "$group_pkg"; then
installed_group+=("$group_pkg")
fi
done
@@ -608,7 +698,7 @@ remove_retired_default_packages() {
done
for pkg in "${installed_retired[@]}"; do
pacman -Q "$pkg" >/dev/null 2>&1 || continue
package_installed_exact "$pkg" || continue
if pacman -Rs --print "$pkg" >/dev/null 2>&1; then
as_root pacman -Rns --noconfirm --ask 4 "$pkg" || warn "Could not remove retired package '$pkg'; leaving it installed."
@@ -643,18 +733,118 @@ if [[ -d $local_bin ]]; then
done
fi
legacy_hypr_config_active() {
local hyprland_conf="$TARGET_HOME/.config/hypr/hyprland.conf"
[[ -f $hyprland_conf ]] || return 1
grep -q '\.local/share/omarchy/default/hypr' "$hyprland_conf"
}
populate_legacy_hypr_defaults() {
local shim_hypr_dir="$1" backup="$2" tmp_dir clone_dir archive_dir
rm -rf "$shim_hypr_dir"
mkdir -p "$shim_hypr_dir"
tmp_dir=$(mktemp -d)
clone_dir="$tmp_dir/omarchy"
archive_dir="$tmp_dir/archive"
if command -v git >/dev/null 2>&1; then
if git clone --depth 1 --branch master --single-branch --filter=blob:none --sparse https://github.com/basecamp/omarchy.git "$clone_dir" >/dev/null 2>&1 && \
git -C "$clone_dir" sparse-checkout set default/hypr >/dev/null 2>&1 && \
[[ -d $clone_dir/default/hypr ]]; then
cp -a "$clone_dir/default/hypr/." "$shim_hypr_dir/"
fi
fi
if ! find "$shim_hypr_dir" -type f -name '*.conf' -print -quit | grep -q .; then
if command -v curl >/dev/null 2>&1 && command -v tar >/dev/null 2>&1; then
mkdir -p "$archive_dir"
if curl -fsSL https://github.com/basecamp/omarchy/archive/refs/heads/master.tar.gz | tar -xz -C "$archive_dir"; then
if [[ -d $archive_dir/omarchy-master/default/hypr ]]; then
cp -a "$archive_dir/omarchy-master/default/hypr/." "$shim_hypr_dir/"
fi
fi
fi
fi
if ! find "$shim_hypr_dir" -type f -name '*.conf' -print -quit | grep -q .; then
if [[ -n $backup && -d $backup/default/hypr ]]; then
cp -a "$backup/default/hypr/." "$shim_hypr_dir/"
fi
fi
rm -rf "$tmp_dir"
find "$shim_hypr_dir" -type f -name '*.conf' -print -quit | grep -q .
}
create_live_omarchy_overlay() {
local backup="$1" compat_root shim_hypr_dir entry base cleanup_hook
compat_root="$TARGET_HOME/.local/state/omarchy/upgrade-to-4-live-omarchy"
shim_hypr_dir="$TARGET_HOME/.local/state/omarchy/upgrade-to-4-hypr-defaults"
populate_legacy_hypr_defaults "$shim_hypr_dir" "$backup" || return 1
rm -rf "$compat_root"
mkdir -p "$compat_root/default"
shopt -s dotglob nullglob
for entry in /usr/share/omarchy/* /usr/share/omarchy/.[!.]* /usr/share/omarchy/..?*; do
[[ -e $entry ]] || continue
base=$(basename "$entry")
[[ $base == default ]] && continue
ln -s "$entry" "$compat_root/$base"
done
for entry in /usr/share/omarchy/default/* /usr/share/omarchy/default/.[!.]* /usr/share/omarchy/default/..?*; do
[[ -e $entry ]] || continue
base=$(basename "$entry")
[[ $base == hypr ]] && continue
ln -s "$entry" "$compat_root/default/$base"
done
ln -s "$shim_hypr_dir" "$compat_root/default/hypr"
cleanup_hook="$TARGET_HOME/.config/omarchy/hooks/post-boot.d/cleanup-upgrade-to-4-live-shim"
mkdir -p "$(dirname "$cleanup_hook")"
cat >"$cleanup_hook" <<CLEANUP_HOOK
#!/bin/bash
set -euo pipefail
legacy_root="\$HOME/.local/share/omarchy"
compat_root="$compat_root"
shim_hypr_dir="$shim_hypr_dir"
if [[ -L \$legacy_root && \$(readlink "\$legacy_root") == "\$compat_root" ]]; then
ln -sfn /usr/share/omarchy "\$legacy_root"
fi
rm -rf "\$compat_root" "\$shim_hypr_dir"
rm -f "\$0"
CLEANUP_HOOK
chmod +x "$cleanup_hook"
printf '%s\n' "$compat_root"
}
# Existing terminals still have OMARCHY_PATH=$HOME/.local/share/omarchy and
# often have $OMARCHY_PATH/bin early in PATH. Make that stale path resolve to
# the package-backed tree for the rest of the live session, while backing up
# the old git checkout for inspection/rollback.
# the old git checkout for inspection/rollback. If the live Hyprland session is
# still using legacy ~/.config/hypr/*.conf files, keep those user files in place
# and provide a temporary default/hypr/*.conf shim so reloads do not explode.
if [[ -e /usr/share/omarchy ]]; then
mkdir -p "$TARGET_HOME/.local/share"
backup=""
if [[ -L $legacy_root ]]; then
ln -sfn /usr/share/omarchy "$legacy_root"
rm -f "$legacy_root"
elif [[ -e $legacy_root ]]; then
backup="$legacy_root.omarchy-upgrade-to-4.$BACKUP_SUFFIX.bak"
mv "$legacy_root" "$backup"
ln -sfn /usr/share/omarchy "$legacy_root"
fi
if legacy_hypr_config_active; then
if compat_root=$(create_live_omarchy_overlay "$backup"); then
ln -sfn "$compat_root" "$legacy_root"
else
echo "Warning: Could not prepare legacy Hyprland conf shim; linking ~/.local/share/omarchy directly to /usr/share/omarchy." >&2
ln -sfn /usr/share/omarchy "$legacy_root"
fi
else
ln -sfn /usr/share/omarchy "$legacy_root"
fi
@@ -873,20 +1063,6 @@ restore_hyprland_config_reload() {
hyprland_config_reload_suppressed=0
}
reload_hyprland_config_after_upgrade() {
log "Reloading Hyprland config with a full reset"
if run_hyprctl_session reload full-reset >/dev/null 2>&1; then
restore_hyprland_config_reload
return 0
fi
warn "hyprctl reload full-reset failed; trying a regular Hyprland reload. If this session is still running an older Hyprland, reboot will complete the cutover."
if ! run_hyprctl_session reload >/dev/null 2>&1; then
warn "Could not reload the live Hyprland session; the new config will load after reboot."
fi
restore_hyprland_config_reload
}
enable_system_service() {
local unit="$1"
@@ -910,6 +1086,26 @@ apply_firewall_defaults() {
enable_system_service ufw.service
}
root_filesystem_encrypted() {
local root_source root_type
root_source=$(findmnt -n -o SOURCE / 2>/dev/null || true)
[[ $root_source == /dev/mapper/* ]] && return 0
if [[ -n $root_source ]]; then
root_type=$(lsblk -no TYPE "$root_source" 2>/dev/null | head -n1 || true)
[[ $root_type == crypt ]] && return 0
fi
as_root bash -c '[[ -s /etc/crypttab ]] && grep -qvE "^[[:space:]]*(#|$)" /etc/crypttab' >/dev/null 2>&1
}
should_enable_sddm_autologin() {
as_root test -f /etc/sddm.conf.d/autologin.conf && return 0
as_root systemctl is-enabled omarchy-seamless-login.service >/dev/null 2>&1 && return 0
root_filesystem_encrypted
}
apply_system_transition() {
log "Applying Omarchy 4 system transition"
[[ -d /usr/share/omarchy ]] || fail "/usr/share/omarchy was not installed."
@@ -952,6 +1148,11 @@ EOF
"bip": "172.17.0.1/16"
}
EOF
as_root ln -sfn ../run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
# Fresh Omarchy socket-activates Docker. Disable the old always-on service if
# an upgraded install had enabled it, but do not stop running containers mid-upgrade.
as_root systemctl disable docker.service >/dev/null 2>&1 || true
enable_system_service cups.service
enable_system_service cups-browsed.service
@@ -960,6 +1161,7 @@ EOF
enable_system_service docker.socket
enable_system_service systemd-resolved.service
enable_system_service NetworkManager.service
enable_system_service bluetooth.service
enable_system_service power-profiles-daemon.service
enable_system_service sddm.service
@@ -984,15 +1186,19 @@ RememberLastUser=true
RememberLastSession=true
EOF
if as_root test -f /etc/sddm.conf.d/autologin.conf; then
local autologin_user
autologin_user=$(as_root awk -F= '/^User=/ { print $2; exit }' /etc/sddm.conf.d/autologin.conf 2>/dev/null || true)
[[ -n $autologin_user ]] || autologin_user="$target_user"
local autologin_user
if should_enable_sddm_autologin; then
if as_root test -f /etc/sddm.conf.d/autologin.conf; then
autologin_user=$(as_root awk -F= '/^User=/ { print $2; exit }' /etc/sddm.conf.d/autologin.conf 2>/dev/null || true)
fi
[[ -n ${autologin_user:-} ]] || autologin_user="$target_user"
cat <<EOF | as_root tee /etc/sddm.conf.d/autologin.conf >/dev/null
[Autologin]
User=$autologin_user
Session=omarchy.desktop
EOF
else
as_root rm -f /etc/sddm.conf.d/autologin.conf
fi
as_root install -d -m 0755 -o sddm -g sddm /var/lib/sddm 2>/dev/null || as_root install -d -m 0755 /var/lib/sddm
@@ -1077,17 +1283,7 @@ refresh chromium-flags.conf 3d52925a48ac3704f9427ecec70310d9c89be5442c41ece18312
refresh chromium-flags.conf 4bc8710615d2151464e9bd6d1123fbfbb8f56dea4cf0568320bc7b50d24ad205
refresh chromium-flags.conf 1df1a5282f9525bfbb97a697c8169c08c1adb2b5a4de5ae94d84df7b4a78f2fc
refresh chromium-flags.conf 0408c524892830f5cf43e94c389b897cbc093ede312f49a4627bfabf692653c2
refresh fastfetch/config.jsonc 6adebf87d93902fb4bc68824a8e7c71e482846af23fea199e489c5496f791590
refresh fastfetch/config.jsonc fe61d9f7cfac800adb7bd21f75f1bfcca266c609b6efa02a6e25303ac192e86e
refresh fastfetch/config.jsonc 62fa26fa5fb8e11d31c5ec9f3a53b9b6b1124b29134b19329a092878ff624581
refresh fastfetch/config.jsonc 22565532d139ab8c2ddb21dcfe56460dc9f2f8a712b8d29f125c1c8b29beca37
refresh fastfetch/config.jsonc b65cb9ca36eed45929bfc35443762b14957d3847f6bed361a338224a87450e3a
refresh fastfetch/config.jsonc 3d153225131d3031b99b2e1a07e84d22cd0e51fcae1e701b08f6b6a558bc7a9c
refresh fastfetch/config.jsonc 404d0273c380cfdad4a037fa87202fc1d96be178c867e8a9d27b0a772f6e2fa1
refresh fastfetch/config.jsonc 4a98ff77ed46109d08ef7301249ea6823d1abba6c39c0871680feebf96620bf2
refresh fastfetch/config.jsonc c827c3a24f64c418d309244a8a967def0c522d824addf65d8ee0741afbc970bd
refresh fastfetch/config.jsonc c909b43ba000887cd418d9eaf98c1c9c5ba938aa27f9246cf8fa5662946c4e87
refresh fastfetch/config.jsonc b2e5757851f0703edb8bcfc4b51a00bf5e303c1df26b8c63e6b7df6be4ead4ed
refresh fcitx5/conf/clipboard.conf 2d53b40811ee7ceb71c7db0422a3ed733647f389379a57dbf2915d522dff4193
refresh fcitx5/conf/xcb.conf f5cf059182c4361fa7b16d5149f20a09eb1e0915f4463ba60dae626b86df7d9c
refresh foot/foot.ini 52e30647172522459b2179af714c19b62a35fe11bc23c49839fda5dca3253e84
@@ -1147,6 +1343,7 @@ refresh xournalpp/settings.xml 1c1a9efbf1b6dc7813bf3440fd5bf8409fc283e8d0192ca29
# (hash mismatch) are kept active as backups.
# Legacy ~/.config path -> package-owned destination (where the file now lives):
# environment.d/fcitx.conf -> /usr/lib/environment.d/10-omarchy-fcitx.conf
# fastfetch/config.jsonc -> /etc/fastfetch/config.jsonc
# fontconfig/fonts.conf -> /usr/share/fontconfig/conf.avail/30-omarchy.conf
# mimeapps.list -> /usr/share/applications/mimeapps.list
# omarchy.ttf -> /usr/share/fonts/omarchy/omarchy.ttf
@@ -1158,6 +1355,24 @@ refresh xournalpp/settings.xml 1c1a9efbf1b6dc7813bf3440fd5bf8409fc283e8d0192ca29
# xdg-terminals.list -> /usr/share/xdg-terminal-exec/hyprland-xdg-terminals.list
retire environment.d/fcitx.conf faacbd703a8f797013968b235fec6289a9c921d3ec7b7f8b4e1cd24392f68b9c
retire environment.d/fcitx.conf 8b077b6ea2594dc1d4b57592a3bc62703df4959e86b93ea0fc488b6686309095
retire fastfetch/config.jsonc 6adebf87d93902fb4bc68824a8e7c71e482846af23fea199e489c5496f791590
retire fastfetch/config.jsonc fe61d9f7cfac800adb7bd21f75f1bfcca266c609b6efa02a6e25303ac192e86e
retire fastfetch/config.jsonc 62fa26fa5fb8e11d31c5ec9f3a53b9b6b1124b29134b19329a092878ff624581
retire fastfetch/config.jsonc abb336459df8dea8f84df1dd54a2f223adec558df3de39cce84ca83f88acc02f
retire fastfetch/config.jsonc f1c9a999a4f31a215b10474eeac8894ce6da220d680c30d2aab7b3c1b7a539a6
retire fastfetch/config.jsonc 97aefdea2103d6c73e063bf0d11ad26da8fe60630305ac4eb2970cfc50cb0d91
retire fastfetch/config.jsonc 22565532d139ab8c2ddb21dcfe56460dc9f2f8a712b8d29f125c1c8b29beca37
retire fastfetch/config.jsonc b65cb9ca36eed45929bfc35443762b14957d3847f6bed361a338224a87450e3a
retire fastfetch/config.jsonc 3d153225131d3031b99b2e1a07e84d22cd0e51fcae1e701b08f6b6a558bc7a9c
retire fastfetch/config.jsonc 404d0273c380cfdad4a037fa87202fc1d96be178c867e8a9d27b0a772f6e2fa1
retire fastfetch/config.jsonc 4a98ff77ed46109d08ef7301249ea6823d1abba6c39c0871680feebf96620bf2
retire fastfetch/config.jsonc 2cc59c562e51ed3a58a784a17414ad40699253d0a9522eb7ce01faf6d7cff7c2
retire fastfetch/config.jsonc 07027778c12914c7077022cc835de4ac6c38af90aed539a871b13c7c89603e87
retire fastfetch/config.jsonc 0bc8cb0a24ec07e786cccbad446fd80b72520e7effd9bff8cfa27b7361211f4b
retire fastfetch/config.jsonc c827c3a24f64c418d309244a8a967def0c522d824addf65d8ee0741afbc970bd
retire fastfetch/config.jsonc c909b43ba000887cd418d9eaf98c1c9c5ba938aa27f9246cf8fa5662946c4e87
retire fastfetch/config.jsonc b2e5757851f0703edb8bcfc4b51a00bf5e303c1df26b8c63e6b7df6be4ead4ed
retire fastfetch/config.jsonc 1a0a085e7a80036f415148da21f772e99898de7e70768ec7b7613f8cc620700c
retire fontconfig/fonts.conf 7db33b0f8673f71f42604255cad222194294cd401315fecde6b83151eecebe91
retire fontconfig/fonts.conf f35b5b4bd0d8d3926f5d9a49ca791fc66b00793786420508d4a4c41ae9ccbefc
retire fontconfig/fonts.conf 6dec98b539388b95ecfdb3c7ab951001c712820eb0581002832cb7bfdde1a654
@@ -1453,6 +1668,46 @@ copy_missing_config_defaults "$root/config" "$HOME/.config"
copy_always_config_defaults
repair_chromium_copy_url_extension_flags
# Carry over user-added backgrounds from the legacy git checkout backup, then
# remove old symlinks that pointed ~/.config/omarchy/themes/* back into the
# pre-4 checkout. Omarchy 4 reads stock themes from /usr/share/omarchy/themes.
legacy_omarchy_backup="$HOME/.local/share/omarchy.omarchy-upgrade-to-4.$BACKUP_SUFFIX.bak"
if [[ -d $legacy_omarchy_backup/themes && -d $legacy_omarchy_backup/.git ]]; then
(
cd "$legacy_omarchy_backup"
mapfile -t tracked_backgrounds < <(git ls-files --cached 'themes/*/backgrounds/*' 2>/dev/null)
for theme_dir in themes/*/; do
[[ -d $theme_dir/backgrounds ]] || continue
theme_name=$(basename "$theme_dir")
for bg_file in "$theme_dir"/backgrounds/*; do
[[ -f $bg_file ]] || continue
is_tracked=0
for tracked in "${tracked_backgrounds[@]}"; do
[[ $tracked == "$bg_file" ]] && { is_tracked=1; break; }
done
if (( ! is_tracked )); then
mkdir -p "$HOME/.config/omarchy/backgrounds/$theme_name"
mv "$bg_file" "$HOME/.config/omarchy/backgrounds/$theme_name/"
fi
done
done
)
fi
if [[ -d $HOME/.config/omarchy/themes ]]; then
find "$HOME/.config/omarchy/themes" -mindepth 1 -maxdepth 1 -type l -delete
fi
# Retire legacy UI configs replaced by omarchy-shell. Hyprland .conf files are
# intentionally left in place for users to reference/port after the upgrade.
for rel in waybar swayosd mako walker; do
file="$HOME/.config/$rel"
if [[ -e $file || -L $file ]]; then
backup="$file.omarchy-upgrade-to-4.$BACKUP_SUFFIX.bak"
rm -rf "$backup"
mv "$file" "$backup"
fi
done
for rel in "${retired_config_files[@]}"; do
file="$HOME/.config/$rel"
backup="$file.omarchy-upgrade-to-4.$BACKUP_SUFFIX.bak"
@@ -1490,6 +1745,11 @@ mkdir -p "$HOME/.local/state/omarchy/toggles/hypr"
if [[ -f $root/default/hypr/toggles/flags.lua ]]; then
cp "$root/default/hypr/toggles/flags.lua" "$HOME/.local/state/omarchy/toggles/hypr/"
fi
# Legacy Hyprland .conf entry points source ~/.local/state/omarchy/toggles/hypr/*.conf.
# Keep an empty match around for the live pre-reboot session; v4 Lua ignores it.
if [[ -f $HOME/.config/hypr/hyprland.conf ]]; then
: >"$HOME/.local/state/omarchy/toggles/hypr/flags.conf"
fi
mkdir -p "$HOME/.local/share/nautilus-python/extensions"
for extension in localsend.py transcode.py; do
@@ -1709,18 +1969,114 @@ touch "$state_dir/finalize-user.done"
USER_SETUP
}
write_legacy_theme_hyprland_conf() {
run_as_user env HOME="$target_home" bash <<'THEME_COMPAT'
set -euo pipefail
hyprland_conf="$HOME/.config/hypr/hyprland.conf"
[[ -f $hyprland_conf ]] || exit 0
grep -q 'current/theme/hyprland.conf' "$hyprland_conf" || exit 0
theme_dir="$HOME/.config/omarchy/current/theme"
colors="$theme_dir/colors.toml"
target="$theme_dir/hyprland.conf"
mkdir -p "$theme_dir"
accent="7aa2f7"
if [[ -f $colors ]]; then
parsed=$(awk -F= '/^[[:space:]]*accent[[:space:]]*=/ { gsub(/[[:space:]"#]/, "", $2); print $2; exit }' "$colors")
[[ -n ${parsed:-} ]] && accent="$parsed"
fi
{
printf '$activeBorderColor = rgb(%s)\n\n' "$accent"
cat <<'EOF'
general {
col.active_border = $activeBorderColor
}
group {
col.border_active = $activeBorderColor
}
EOF
} >"$target"
THEME_COMPAT
}
refresh_current_theme_after_upgrade() {
local theme_name runtime_dir
theme_name=$(run_as_user env HOME="$target_home" bash -c '
set -euo pipefail
theme_name_path="$HOME/.config/omarchy/current/theme.name"
current_theme_path="$HOME/.config/omarchy/current/theme"
if [[ -f $theme_name_path ]]; then
read -r theme_name <"$theme_name_path" || true
printf "%s" "${theme_name:-}"
elif [[ -L $current_theme_path ]]; then
basename -- "$(readlink "$current_theme_path")"
else
printf ""
fi
')
theme_name=${theme_name//$'\r'/}
theme_name=${theme_name//$'\n'/}
[[ -n $theme_name ]] || theme_name="Tokyo Night"
log "Refreshing current theme with Omarchy 4 templates ($theme_name)"
runtime_dir="$target_runtime_dir"
[[ -d $runtime_dir ]] || runtime_dir=/tmp
if ! run_as_user env \
HOME="$target_home" \
USER="$target_user" \
LOGNAME="$target_user" \
XDG_RUNTIME_DIR="$runtime_dir" \
DBUS_SESSION_BUS_ADDRESS="unix:path=$runtime_dir/bus" \
XDG_CURRENT_DESKTOP=Hyprland \
XDG_SESSION_DESKTOP=Hyprland \
XDG_SESSION_TYPE=wayland \
DESKTOP_SESSION=hyprland \
OMARCHY_PATH=/usr/share/omarchy \
OMARCHY_THEME_HEADLESS=1 \
PATH="$package_path" \
omarchy-theme-set "$theme_name"; then
warn "Could not refresh current theme '$theme_name'. Run 'omarchy theme set \"$theme_name\"' after reboot if theme-dependent app config looks stale."
fi
write_legacy_theme_hyprland_conf
# Headless theme refresh intentionally skips omarchy-theme-set's live post
# hooks because one of them runs `hyprctl reload`. Still poke terminal
# emulators so the active upgrade terminal picks up generated theme files.
run_as_user env \
HOME="$target_home" \
USER="$target_user" \
LOGNAME="$target_user" \
OMARCHY_PATH=/usr/share/omarchy \
PATH="$package_path" \
omarchy-restart-terminal >/dev/null 2>&1 || true
}
configure_pacman_channel
install_keyrings
remove_legacy_installer_package
remove_legacy_limine_configs
remove_conflicting_legacy_packages
install_omarchy_4_packages
normalize_limine_config
migrate_1password_beta_package
cleanup_legacy_user_paths
apply_system_transition
suppress_hyprland_config_reload
apply_user_transition
cleanup_retired_services
remove_retired_default_packages
reload_hyprland_config_after_upgrade
refresh_current_theme_after_upgrade
# Do not force-reload Hyprland in the live upgraded session. The legacy
# default/hypr and theme hyprland.conf shims above exist specifically so the
# pre-reboot session can keep running safely; the reboot performs the real
# Omarchy 4 Lua-config cutover.
restore_hyprland_config_reload
if start_omarchy_shell_session; then
stop_retired_session_processes
else
+19 -1
View File
@@ -2,4 +2,22 @@
# omarchy:summary=Print the installed Omarchy version
cat $OMARCHY_PATH/version
omarchy_path=${OMARCHY_PATH:-/usr/share/omarchy}
omarchy_path=${omarchy_path%/}
if [[ $omarchy_path != "/usr/share/omarchy" ]]; then
hash=$(git -C "$omarchy_path" rev-parse --short HEAD 2>/dev/null || true)
if [[ -n $hash ]]; then
echo "dev ($hash)"
else
echo "dev"
fi
exit 0
fi
version=$(pacman -Q omarchy 2>/dev/null | awk '{ print $2 }')
[[ -n $version ]] || exit 1
echo "$version"
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
# omarchy:summary=Print the active Omarchy dev-link git branch
# omarchy:hidden=true
omarchy_path=${OMARCHY_PATH:-/usr/share/omarchy}
omarchy_path=${omarchy_path%/}
[[ $omarchy_path != "/usr/share/omarchy" ]] || exit 1
branch=$(git -C "$omarchy_path" branch --show-current 2>/dev/null || true)
if [[ -z $branch ]]; then
hash=$(git -C "$omarchy_path" rev-parse --short HEAD 2>/dev/null || true)
[[ -n $hash ]] || exit 1
branch="detached@$hash"
fi
echo "$branch"
+1 -1
View File
@@ -178,7 +178,7 @@ changes. For more invasive changes (new plugin, packaged update):
| App | Location |
|-----|----------|
| btop | `~/.config/btop/btop.conf` |
| fastfetch | `~/.config/fastfetch/config.jsonc` |
| fastfetch | `/etc/fastfetch/config.jsonc` default; `~/.config/fastfetch/config.jsonc` user override |
| lazygit | `~/.config/lazygit/config.yml` |
| starship | `~/.config/starship.toml` |
| git | `~/.config/git/config` |
+5 -2
View File
@@ -67,6 +67,7 @@ version ──► omarchy /usr/share/omarchy
config/** ──► omarchy-settings /etc/skel/.config/** (seeds new users)
/usr/share/omarchy/config/** (resync source)
etc/fastfetch/config.jsonc ──► omarchy-settings /etc/fastfetch/config.jsonc
applications/*.desktop ──► omarchy-settings /etc/skel/.local/share/applications/
/usr/share/omarchy/applications/
@@ -267,8 +268,10 @@ brand-new user, so this one copy resyncs `.bashrc`, `.config/**`,
branding files, and the shipped migration markers in a single pass.
Then it runs `omarchy-refresh-limine`, `omarchy-refresh-plymouth`, and the
nvim refresh. Destructive: existing user files at these paths are clobbered
without backup.
nvim refresh. Destructive: existing user files copied from `/etc/skel` are
clobbered without backup. Fastfetch is package-owned at
`/etc/fastfetch/config.jsonc`; delete `~/.config/fastfetch/config.jsonc` to
return to the packaged default.
## Quick reference: where does X live?
+4 -7
View File
@@ -4,13 +4,6 @@ Omarchy migrations are one-time repair scripts for existing installs. They are
used when a package update needs to change state that pacman cannot safely own by
itself.
They are for both humans and agents:
- Users should know when migrations run, where state is stored, and how to retry
or inspect pending work.
- Agents should know which migration scope to use, how to write safe migration
scripts, and what should **not** be a migration.
## The two migration scopes
Omarchy migrations are split by execution context:
@@ -32,6 +25,8 @@ Use system migrations for machine-wide state, for example:
- hardware quirks
- package-owned layout transitions
Note that it's not necessary to write a migration for any file that will be package-owned.
State lives in:
```text
@@ -177,6 +172,8 @@ Migrations are plain shell files:
- no shebang
- start with an `echo` describing the migration
- use `$OMARCHY_PATH` for Omarchy-owned files
- should be idempotent
- should be as simple as possible to accomplish the task
Example system migration:
@@ -66,7 +66,13 @@
"type": "command",
"key": "\ue900 OS",
"keyColor": "blue",
"text": "version=$(omarchy-version); echo \"Omarchy $version\""
"text": "version=$(omarchy-version) && echo \"Omarchy $version\""
},
{
"type": "command",
"key": "│ ├󰘬",
"keyColor": "blue",
"text": "omarchy-version-branch"
},
{
"type": "command",
+1
View File
@@ -103,6 +103,7 @@ package_defaults = [
("default/fontconfig/conf.avail/30-omarchy.conf", "/usr/share/fontconfig/conf.avail/30-omarchy.conf", "fontconfig/fonts.conf"),
("default/xdg-terminal-exec/hyprland-xdg-terminals.list", "/usr/share/xdg-terminal-exec/hyprland-xdg-terminals.list", "xdg-terminals.list"),
("default/applications/mimeapps.list", "/usr/share/applications/mimeapps.list", "mimeapps.list"),
("etc/fastfetch/config.jsonc", "/etc/fastfetch/config.jsonc", "fastfetch/config.jsonc"),
("default/systemd/user/bt-agent.service", "/usr/lib/systemd/user/bt-agent.service", "systemd/user/bt-agent.service"),
("default/systemd/user/omarchy-sleep-lock.service", "/usr/lib/systemd/user/omarchy-sleep-lock.service", "systemd/user/omarchy-sleep-lock.service"),
("default/systemd/user/omarchy-recover-internal-monitor.service", "/usr/lib/systemd/user/omarchy-recover-internal-monitor.service", "systemd/user/omarchy-recover-internal-monitor.service"),