#!/bin/bash # omarchy:summary=Upgrade a legacy Omarchy install to the package-backed Omarchy 4 layout. # omarchy:args=[--yes] [--channel stable|rc|edge] [--user USER] # omarchy:examples=omarchy upgrade to 4 # omarchy:requires-sudo=true set -euo pipefail usage() { cat <<'USAGE' Usage: omarchy-upgrade-to-4 [--yes] [--channel stable|rc|edge] [--user USER] Upgrade any pre-4 Omarchy install to the package-backed Omarchy 4 layout. This script is intentionally self-contained so it can be shipped as a command in Omarchy 3.8.x or run directly with curl | bash on older systems. Options: -y, --yes Do not prompt before upgrading --channel stable|rc|edge Override detected Omarchy package channel --user USER User account to refresh after package install -h, --help Show this help USAGE } log() { printf '\033[32m==>\033[0m %s\n' "$*" } warn() { printf '\033[33mWarning:\033[0m %s\n' "$*" >&2 } fail() { printf '\033[31mError:\033[0m %s\n' "$*" >&2 exit 1 } normalize_channel() { case "${1:-}" in stable|master|main) echo stable ;; rc) echo rc ;; edge|dev) echo edge ;; *) return 1 ;; esac } valid_channel() { normalize_channel "$1" >/dev/null 2>&1 } channel_override="${OMARCHY_UPGRADE_CHANNEL:-${OMARCHY_CHANNEL:-${OMARCHY_MIRROR:-}}}" target_user="${OMARCHY_INSTALL_USER:-}" yes=0 while (($#)); do case "$1" in -y|--yes) yes=1 shift ;; --channel) channel_override="${2:-}" shift 2 ;; --user) target_user="${2:-}" shift 2 ;; -h|--help) usage exit 0 ;; *) fail "Unknown option: $1" ;; esac done if ! command -v pacman >/dev/null 2>&1; then fail "This upgrade is only supported on Arch/Omarchy systems with pacman." fi if ! command -v sudo >/dev/null 2>&1 && (( EUID != 0 )); then fail "sudo is required when not running as root." fi if [[ -z $target_user ]]; then if (( EUID == 0 )); then target_user="${SUDO_USER:-}" else target_user="${USER:-$(id -un)}" fi fi if [[ -z $target_user || $target_user == root ]]; then fail "Could not determine the non-root Omarchy user. Re-run with --user USER." fi if ! getent passwd "$target_user" >/dev/null; then fail "User '$target_user' does not exist." fi target_home=$(getent passwd "$target_user" | cut -d: -f6) [[ -n $target_home && -d $target_home ]] || fail "Home directory for '$target_user' was not found." as_root() { if (( EUID == 0 )); then "$@" else sudo "$@" fi } run_as_user() { if (( EUID == 0 )); then if command -v sudo >/dev/null 2>&1; then sudo -u "$target_user" -H "$@" else runuser -u "$target_user" -- "$@" fi else "$@" fi } detect_channel() { local candidate="${channel_override:-}" if [[ -n $candidate ]] && valid_channel "$candidate"; then normalize_channel "$candidate" return 0 fi if command -v omarchy-version-channel >/dev/null 2>&1; then candidate=$(omarchy-version-channel 2>/dev/null | awk '{ print $1 }' || true) if [[ -n $candidate ]] && valid_channel "$candidate"; then normalize_channel "$candidate" return 0 fi fi if [[ -f /etc/pacman.conf ]]; then if grep -q 'https://pkgs\.omarchy\.org/rc/' /etc/pacman.conf; then echo rc return 0 elif grep -q 'https://pkgs\.omarchy\.org/edge/' /etc/pacman.conf; then echo edge return 0 elif grep -q 'https://pkgs\.omarchy\.org/stable/' /etc/pacman.conf; then echo stable return 0 fi fi if [[ -f /etc/pacman.d/mirrorlist ]]; then if grep -q 'https://rc-mirror\.omarchy\.org/' /etc/pacman.d/mirrorlist; then echo rc return 0 elif grep -q 'https://mirror\.omarchy\.org/' /etc/pacman.d/mirrorlist; then echo edge return 0 elif grep -q 'https://stable-mirror\.omarchy\.org/' /etc/pacman.d/mirrorlist; then echo stable return 0 fi fi if [[ -d $target_home/.local/share/omarchy/.git ]]; then if (( EUID == 0 )); then candidate=$(run_as_user git -C "$target_home/.local/share/omarchy" branch --show-current 2>/dev/null || true) else candidate=$(git -C "$target_home/.local/share/omarchy" branch --show-current 2>/dev/null || true) fi if [[ -n $candidate ]] && valid_channel "$candidate"; then normalize_channel "$candidate" return 0 fi fi echo stable } channel=$(detect_channel) if ! valid_channel "$channel"; then fail "Invalid channel '$channel'. Use stable, rc, or edge." fi case "$channel" in stable) mirror_server='https://stable-mirror.omarchy.org/$repo/os/$arch' package_server='https://pkgs.omarchy.org/stable/$arch' ;; rc) mirror_server='https://rc-mirror.omarchy.org/$repo/os/$arch' package_server='https://pkgs.omarchy.org/rc/$arch' ;; edge) mirror_server='https://mirror.omarchy.org/$repo/os/$arch' package_server='https://pkgs.omarchy.org/edge/$arch' ;; esac if (( ! yes )); then cat </dev/tty read -r answer /dev/null & sudo_keepalive_pid=$! trap 'kill "$sudo_keepalive_pid" 2>/dev/null || true' EXIT fi backup_suffix=$(date +%Y%m%d%H%M%S) configure_pacman_channel() { log "Configuring Omarchy pacman repositories ($channel)" as_root install -d -m 0755 /etc/pacman.d if [[ -f /etc/pacman.d/mirrorlist ]]; then as_root cp -f /etc/pacman.d/mirrorlist "/etc/pacman.d/mirrorlist.omarchy-upgrade-to-4.$backup_suffix.bak" fi printf 'Server = %s\n' "$mirror_server" | as_root tee /etc/pacman.d/mirrorlist >/dev/null if [[ ! -f /etc/pacman.conf ]]; then fail "/etc/pacman.conf does not exist." fi as_root cp -f /etc/pacman.conf "/etc/pacman.conf.omarchy-upgrade-to-4.$backup_suffix.bak" tmp=$(mktemp) awk -v server="$package_server" ' BEGIN { in_omarchy = 0; wrote = 0 } /^\[omarchy\]$/ { if (!wrote) { print "[omarchy]" print "SigLevel = Optional TrustAll" print "Server = " server wrote = 1 } in_omarchy = 1 next } /^\[/ && in_omarchy { in_omarchy = 0 } !in_omarchy { print } END { if (!wrote) { print "" print "[omarchy]" print "SigLevel = Optional TrustAll" print "Server = " server } } ' /etc/pacman.conf >"$tmp" as_root install -m 0644 "$tmp" /etc/pacman.conf rm -f "$tmp" } install_keyrings() { log "Refreshing package databases and keyrings" as_root pacman -Sy --noconfirm archlinux-keyring omarchy-keyring || { warn "Keyring package install failed; attempting to trust the Omarchy packaging key directly." as_root pacman-key --recv-keys 40DFB630FF42BCFFB047046CF0134EE680CAC571 --keyserver keys.openpgp.org || true as_root pacman-key --lsign-key 40DFB630FF42BCFFB047046CF0134EE680CAC571 || true as_root pacman -Sy --noconfirm archlinux-keyring omarchy-keyring } } remove_legacy_installer_package() { if pacman -Q omarchy-installer >/dev/null 2>&1; then log "Removing legacy omarchy-installer package" # The pre-4 omarchy meta package may depend on omarchy-installer. Ignore # that edge temporarily; the next transaction installs the Omarchy 4 meta. as_root pacman -Rdd --noconfirm omarchy-installer 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 # after NetworkManager and the rest of the new stack are installed. local conflicting_packages=( asdcontrol-git lazydocker-bin localsend-bin omarchy-chromium omarchy-lazyvim openai-codex-bin ttf-jetbrains-mono ttf-jetbrains-mono-nerd wayfreeze wayfreeze-git ) local pkg for pkg in "${conflicting_packages[@]}"; do if pacman -Q "$pkg" >/dev/null 2>&1; 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 # example ttf-jetbrains-mono-nerd -> ttf-jetbrains-mono-nerd-basic) and # --noconfirm answers "no". as_root pacman -Rdd --noconfirm "$pkg" || warn "Could not remove conflicting legacy package '$pkg'; continuing." fi done } install_omarchy_4_packages() { local core_packages=( omarchy-keyring omarchy-settings omarchy-limine omarchy-nvim omarchy ) 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[@]}" 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[@]}" fi else warn "/usr/share/omarchy/install/omarchy-base.packages was not found; skipping default package set install." fi # Archinstall installs the audio application during fresh ISO installs, so # legacy upgrades need to ensure the same PipeWire stack is present without # depending on Archinstall or Omarchy setup helpers. local audio_packages=( pipewire pipewire-alsa pipewire-jack pipewire-pulse gst-plugin-pipewire libpulse wireplumber ) as_root pacman -S --needed --noconfirm --ask 4 --overwrite='*' "${audio_packages[@]}" } remove_retired_default_packages() { local retired_packages=( 1password-beta 1password-cli alacritty asdcontrol-git blueberry bluetui chaotic-keyring chaotic-mirrorlist claude-code elephant elephant-all elephant-bluetooth elephant-calc elephant-clipboard elephant-desktopapplications elephant-files elephant-menus elephant-providerlist elephant-runner elephant-symbols elephant-todo elephant-unicode elephant-websearch fcitx5-configtool gcc14 github-cli hypridle hyprlock impala iwd lazydocker-bin lmstudio lmstudio-bin localsend-bin makima-bin mako omarchy-chromium omarchy-lazyvim omarchy-walker openai-codex openai-codex-bin opencode pavucontrol playerctl polkit-gnome qt5-remoteobjects signal-desktop spotify swaybg swayosd ttf-jetbrains-mono ttf-jetbrains-mono-nerd vlc waybar wayfreeze wayfreeze-git wf-recorder wiremix wl-screenrec yay-bin-debug zoom ) log "Removing packages retired from the Omarchy 4 default install" local pkg for pkg in "${retired_packages[@]}"; do if pacman -Q "$pkg" >/dev/null 2>&1; then as_root pacman -Rns --noconfirm "$pkg" || warn "Could not remove retired package '$pkg'; leaving it installed." fi done } cleanup_legacy_user_paths() { log "Cleaning legacy user command shims" run_as_user env TARGET_HOME="$target_home" bash <<'USER_CLEANUP' set -euo pipefail local_bin="$TARGET_HOME/.local/bin" legacy_root="$TARGET_HOME/.local/share/omarchy/bin/" [[ -d $local_bin ]] || exit 0 shopt -s nullglob for link in "$local_bin"/omarchy*; do [[ -L $link ]] || continue target=$(readlink "$link" || true) case "$target" in "$legacy_root"*|../share/omarchy/bin/*|*.local/share/omarchy/bin/*) rm -f "$link" ;; esac done USER_CLEANUP } cleanup_retired_services() { log "Disabling services retired by Omarchy 4" # Do not stop iwd mid-upgrade; disabling is enough and avoids dropping a # running Wi-Fi connection before the user can reboot into NetworkManager. as_root systemctl disable iwd.service >/dev/null 2>&1 || true run_as_user systemctl --user disable \ hyprpolkitagent.service \ mako.service \ omarchy-battery-monitor.service \ omarchy-battery-monitor.timer \ omarchy-shell.service \ swayosd-server.service \ elephant.service \ app-walker@autostart.service \ >/dev/null 2>&1 || true run_as_user systemctl --user daemon-reload >/dev/null 2>&1 || true } enable_system_service() { local unit="$1" as_root systemctl enable "$unit" >/dev/null 2>&1 || warn "Could not enable $unit; it may not be installed on this system." } apply_firewall_defaults() { if ! command -v ufw >/dev/null 2>&1; then warn "ufw is not installed; skipping firewall defaults." return 0 fi log "Applying Omarchy firewall defaults" as_root ufw default deny incoming >/dev/null || true as_root ufw default allow outgoing >/dev/null || true as_root ufw allow 53317/udp >/dev/null || true as_root ufw allow 53317/tcp >/dev/null || true as_root ufw allow in proto udp from 172.16.0.0/12 to 172.17.0.1 port 53 comment 'allow-docker-dns' >/dev/null || true as_root ufw allow in proto udp from 192.168.0.0/16 to 172.17.0.1 port 53 comment 'allow-docker-dns' >/dev/null || true as_root sed -i 's/^ENABLED=.*/ENABLED=yes/' /etc/ufw/ufw.conf 2>/dev/null || true enable_system_service ufw.service } apply_system_transition() { log "Applying Omarchy 4 system transition" [[ -d /usr/share/omarchy ]] || fail "/usr/share/omarchy was not installed." as_root install -d -m 0755 /usr/share/icons/Yaru/scalable/actions as_root ln -snf /usr/share/icons/Adwaita/symbolic/actions/go-previous-symbolic.svg \ /usr/share/icons/Yaru/scalable/actions/go-previous-symbolic.svg as_root ln -snf /usr/share/icons/Adwaita/symbolic/actions/go-next-symbolic.svg \ /usr/share/icons/Yaru/scalable/actions/go-next-symbolic.svg as_root gtk-update-icon-cache /usr/share/icons/Yaru >/dev/null 2>&1 || true as_root install -d -m 0777 /etc/chromium/policies/managed as_root install -d -m 0755 /usr/lib/chromium printf '%s\n' '{"browser":{"theme":{"color_scheme":0,"color_scheme2":0}}}' | \ as_root tee /usr/lib/chromium/initial_preferences >/dev/null if getent group docker >/dev/null; then as_root usermod -aG docker "$target_user" fi if [[ -f /usr/bin/powerprofilesctl ]]; then as_root sed -i '/env python3/ c\#!/bin/python3' /usr/bin/powerprofilesctl || true fi as_root install -d -m 0755 /etc/systemd/resolved.conf.d /etc/docker cat <<'EOF' | as_root tee /etc/systemd/resolved.conf.d/10-disable-multicast.conf >/dev/null [Resolve] LLMNR=no MulticastDNS=no EOF cat <<'EOF' | as_root tee /etc/systemd/resolved.conf.d/20-docker-dns.conf >/dev/null [Resolve] DNSStubListenerExtra=172.17.0.1 EOF cat <<'EOF' | as_root tee /etc/docker/daemon.json >/dev/null { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "5" }, "dns": ["172.17.0.1"], "bip": "172.17.0.1/16" } EOF enable_system_service cups.service enable_system_service cups-browsed.service enable_system_service avahi-daemon.service enable_system_service linux-modules-cleanup.service enable_system_service docker.socket enable_system_service systemd-resolved.service enable_system_service NetworkManager.service enable_system_service power-profiles-daemon.service enable_system_service sddm.service apply_firewall_defaults log "Normalizing SDDM login configuration" as_root install -d -m 0755 /etc/sddm.conf.d printf '[Theme]\nCurrent=omarchy\n' | as_root tee /etc/sddm.conf.d/10-theme.conf >/dev/null cat <<'EOF' | as_root tee /etc/sddm.conf.d/10-wayland.conf >/dev/null [General] DisplayServer=wayland [Wayland] CompositorCommand=start-hyprland -- --config /usr/share/sddm/hyprland.lua EOF cat <<'EOF' | as_root tee /etc/sddm.conf.d/99-omarchy-login.conf >/dev/null [Theme] Current=omarchy [Users] 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" cat </dev/null [Autologin] User=$autologin_user Session=omarchy.desktop EOF 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 cat </dev/null [Last] Session=omarchy.desktop User=$target_user EOF as_root chown sddm:sddm /var/lib/sddm /var/lib/sddm/state.conf 2>/dev/null || true as_root rm -f /etc/systemd/system/getty@tty1.service.d/autologin.conf as_root rm -f /etc/systemd/system/plymouth-quit.service.d/wait-for-graphical.conf as_root rm -f /etc/systemd/system/omarchy-seamless-login.service as_root rm -f /usr/local/bin/seamless-login as_root systemctl disable omarchy-seamless-login.service >/dev/null 2>&1 || true as_root systemctl disable makima.service >/dev/null 2>&1 || true as_root rm -rf /etc/systemd/system/makima.service.d as_root rm -f /etc/udev/rules.d/99-uinput.rules as_root systemctl disable dell-xps-haptic-touchpad.service >/dev/null 2>&1 || true as_root rm -f /etc/systemd/system/dell-xps-haptic-touchpad.service as_root rm -f /etc/systemd/system/multi-user.target.wants/dell-xps-haptic-touchpad.service as_root rm -rf /etc/systemd/system/dell-xps-haptic-touchpad.service.d as_root rm -f /etc/udev/rules.d/99-dell-xps-haptic-touchpad.rules as_root rm -f /etc/omarchy-dell-haptic-touchpad.env as_root rm -f /etc/pacman.d/hooks/walker-restart.hook as_root systemctl daemon-reload >/dev/null 2>&1 || true if [[ -f /etc/pam.d/sddm ]]; then as_root sed -i '/-auth.*pam_gnome_keyring\.so/d' /etc/pam.d/sddm as_root sed -i '/-password.*pam_gnome_keyring\.so/d' /etc/pam.d/sddm fi if [[ -f /etc/pam.d/system-auth ]]; then as_root sed -i 's|^\(auth\s\+required\s\+pam_faillock.so\)\s\+preauth.*$|\1 preauth silent deny=10 unlock_time=120|' /etc/pam.d/system-auth as_root sed -i 's|^\(auth\s\+\[default=die\]\s\+pam_faillock.so\)\s\+authfail.*$|\1 authfail deny=10 unlock_time=120|' /etc/pam.d/system-auth fi if [[ -f /etc/pam.d/sddm-autologin ]]; then as_root sed -i '/pam_faillock\.so preauth/d' /etc/pam.d/sddm-autologin as_root sed -i '/pam_faillock\.so authsucc/d' /etc/pam.d/sddm-autologin as_root sed -i '/auth.*pam_permit\.so/a auth required pam_faillock.so authsucc' /etc/pam.d/sddm-autologin fi } apply_user_transition() { log "Applying Omarchy 4 user transition" [[ -d /usr/share/omarchy ]] || fail "/usr/share/omarchy was not installed." run_as_user env \ TARGET_HOME="$target_home" \ BACKUP_SUFFIX="$backup_suffix" \ OMARCHY_USER_NAME="${OMARCHY_USER_NAME:-}" \ OMARCHY_USER_EMAIL="${OMARCHY_USER_EMAIL:-}" \ bash <<'USER_SETUP' set -euo pipefail root=/usr/share/omarchy state_dir="$HOME/.local/state/omarchy" mkdir -p "$state_dir" "$HOME/.config" if [[ -d $root/config ]]; then cp -R "$root/config/." "$HOME/.config/" fi if [[ -f $root/default/bashrc ]]; then cp "$root/default/bashrc" "$HOME/.bashrc" echo '[[ -f ~/.bashrc ]] && . ~/.bashrc' >"$HOME/.bash_profile" fi mkdir -p "$HOME/.agents/skills" "$HOME/.claude/skills" "$HOME/.codex/skills" "$HOME/.pi/agent/skills" if [[ -d $root/default/omarchy-skill ]]; then ln -sfn "$root/default/omarchy-skill" "$HOME/.agents/skills/omarchy" ln -sfn "$root/default/omarchy-skill" "$HOME/.claude/skills/omarchy" ln -sfn "$root/default/omarchy-skill" "$HOME/.codex/skills/omarchy" ln -sfn "$root/default/omarchy-skill" "$HOME/.pi/agent/skills/omarchy" fi 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 mkdir -p "$HOME/.local/share/nautilus-python/extensions" for extension in localsend.py transcode.py; do if [[ -f $root/default/nautilus-python/extensions/$extension ]]; then cp "$root/default/nautilus-python/extensions/$extension" "$HOME/.local/share/nautilus-python/extensions/" fi done mkdir -p "$HOME/.config/omarchy/branding" [[ -f $root/icon.txt ]] && cp "$root/icon.txt" "$HOME/.config/omarchy/branding/about.txt" [[ -f $root/logo.txt ]] && cp "$root/logo.txt" "$HOME/.config/omarchy/branding/screensaver.txt" mkdir -p "$HOME/Downloads" "$HOME/Pictures" "$HOME/Videos" "$HOME/Projects" "$HOME/.config/gtk-3.0" if command -v xdg-user-dirs-update >/dev/null 2>&1; then xdg-user-dirs-update --set TEMPLATES "$HOME" || true xdg-user-dirs-update --set PUBLICSHARE "$HOME" || true xdg-user-dirs-update --set DESKTOP "$HOME" || true fi rmdir "$HOME/Templates" "$HOME/Public" "$HOME/Desktop" 2>/dev/null || true touch "$HOME/.config/gtk-3.0/bookmarks" for dir in Downloads Projects Pictures Videos; do bookmark="file://$HOME/$dir $dir" grep -qxF "$bookmark" "$HOME/.config/gtk-3.0/bookmarks" || echo "$bookmark" >>"$HOME/.config/gtk-3.0/bookmarks" done conf=/etc/vconsole.conf hyprlua="$HOME/.config/hypr/input.lua" if [[ -f $conf && -f $hyprlua ]]; then sed -i '/^[[:space:]]*kb_layout[[:space:]]*=/d' "$hyprlua" sed -i '/^[[:space:]]*kb_variant[[:space:]]*=/d' "$hyprlua" if grep -q '^XKBLAYOUT=' "$conf"; then layout=$(grep '^XKBLAYOUT=' "$conf" | cut -d= -f2 | tr -d '"') sed -i "/^[[:space:]]*kb_options *=/i\ kb_layout = \"$layout\"," "$hyprlua" fi if grep -q '^XKBVARIANT=' "$conf"; then variant=$(grep '^XKBVARIANT=' "$conf" | cut -d= -f2 | tr -d '"') sed -i "/^[[:space:]]*kb_options *=/i\ kb_variant = \"$variant\"," "$hyprlua" fi fi if [[ -n ${OMARCHY_USER_NAME//[[:space:]]/} ]]; then git config --global user.name "$OMARCHY_USER_NAME" || true fi if [[ -n ${OMARCHY_USER_EMAIL//[[:space:]]/} ]]; then git config --global user.email "$OMARCHY_USER_EMAIL" || true fi if [[ ! -f $HOME/.XCompose ]]; then cat >"$HOME/.XCompose" < : "$OMARCHY_USER_NAME" : "$OMARCHY_USER_EMAIL" EOF fi mkdir -p "$HOME/.config/omarchy/themes" "$HOME/.config/btop/themes" ln -snf "$HOME/.config/omarchy/current/theme/btop.theme" "$HOME/.config/btop/themes/current.theme" if [[ ! -e $HOME/.config/omarchy/current/background && -d $HOME/.config/omarchy/current/theme/backgrounds ]]; then background=$(find "$HOME/.config/omarchy/current/theme/backgrounds" -maxdepth 1 -type f \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' \) | sort | head -n1) [[ -n ${background:-} ]] && ln -snf "$background" "$HOME/.config/omarchy/current/background" fi mkdir -p "$HOME/.config/wireplumber/wireplumber.conf.d" if [[ -f $root/default/wireplumber/wireplumber.conf.d/bluetooth-a2dp-autoconnect.conf ]]; then cp "$root/default/wireplumber/wireplumber.conf.d/bluetooth-a2dp-autoconnect.conf" "$HOME/.config/wireplumber/wireplumber.conf.d/" fi enable_user_unit() { local unit="$1" unit_path="$HOME/.config/systemd/user/$1" target local -a targets=() [[ -f $unit_path ]] || return 0 mapfile -t targets < <(awk -F= ' /^\[Install\]/ { in_install=1; next } /^\[/ { in_install=0 } in_install && $1 == "WantedBy" { n=split($2, values, /[[:space:]]+/) for (i = 1; i <= n; i++) if (values[i] != "") print values[i] } ' "$unit_path") ((${#targets[@]})) || targets=(default.target) for target in "${targets[@]}"; do mkdir -p "$HOME/.config/systemd/user/$target.wants" ln -sfn "../$unit" "$HOME/.config/systemd/user/$target.wants/$unit" done } enable_user_unit bt-agent.service enable_user_unit omarchy-sleep-lock.service mkdir -p "$HOME/.config/systemd/user/default.target.wants" for unit in pipewire-pulse.service pipewire-pulse.socket; do if [[ -e /usr/lib/systemd/user/$unit ]]; then ln -sfn "/usr/lib/systemd/user/$unit" "$HOME/.config/systemd/user/default.target.wants/$unit" fi done keyring_dir="$HOME/.local/share/keyrings" keyring_file="$keyring_dir/Default_keyring.keyring" default_file="$keyring_dir/default" mkdir -p "$keyring_dir" if [[ ! -f $keyring_file ]]; then cat >"$keyring_file" <"$default_file" fi chmod 700 "$keyring_dir" chmod 600 "$keyring_file" chmod 644 "$default_file" mkdir -p "$HOME/.local/share/applications" rm -f "$HOME/.config/autostart/walker.desktop" rm -rf "$HOME/.config/elephant" "$HOME/.config/makima" "$HOME/.config/wiremix" rm -rf "$HOME/.config/systemd/user/app-walker@autostart.service.d" rm -f \ "$HOME/.config/systemd/user/omarchy-battery-monitor.service" \ "$HOME/.config/systemd/user/omarchy-battery-monitor.timer" \ "$HOME/.config/systemd/user/omarchy-shell.service" \ "$HOME/.config/systemd/user/swayosd-server.service" \ "$HOME/.config/systemd/user/elephant.service" rm -f \ "$HOME/.local/state/omarchy/toggles/mako.ini" \ "$HOME/.local/state/omarchy/toggles/waybar-off" \ "$HOME/.local/state/omarchy/toggles/hyprlock.conf" \ "$HOME/.local/state/omarchy/toggles/lock.conf" \ "$HOME/.local/state/omarchy/toggles/hypr/rounded-corners.lua" for desktop in \ About.desktop \ Activity.desktop \ Alacritty.desktop \ Cliamp.desktop \ blueberry.desktop \ nvim.desktop \ omarchy.desktop \ org.pulseaudio.pavucontrol.desktop \ vlc.desktop \ wiremix.desktop; do rm -f "$HOME/.local/share/applications/$desktop" done legacy_icons_dir="$HOME/.local/share/applications/icons" legacy_icons_backup="$HOME/.local/share/applications/icons.omarchy-upgrade-to-4.$BACKUP_SUFFIX.bak" if [[ -d $legacy_icons_dir ]]; then mkdir -p "$legacy_icons_backup" for icon in \ Basecamp.png \ Battle.net.png \ ChatGPT.png \ Cliamp.png \ Discord.png \ "Disk Usage.png" \ Docker.png \ Figma.png \ Fizzy.png \ GitHub.png \ "Google Contacts.png" \ "Google Maps.png" \ "Google Messages.png" \ "Google Photos.png" \ HEY.png \ imv.png \ "Retro Gaming.png" \ WhatsApp.png \ windows.png \ X.png \ YouTube.png \ Zoom.png; do if [[ -e $legacy_icons_dir/$icon ]]; then mv -f "$legacy_icons_dir/$icon" "$legacy_icons_backup/" fi done rmdir "$legacy_icons_dir" 2>/dev/null || true rmdir "$legacy_icons_backup" 2>/dev/null || true fi if [[ -d $root/applications ]]; then find "$root/applications" -maxdepth 1 -type f -name '*.desktop' -exec cp -f {} "$HOME/.local/share/applications/" \; fi if [[ -f $root/default/alacritty/Alacritty.desktop && ! -f $HOME/.local/share/applications/Alacritty.desktop ]]; then cp "$root/default/alacritty/Alacritty.desktop" "$HOME/.local/share/applications/" fi if command -v update-desktop-database >/dev/null 2>&1; then update-desktop-database "$HOME/.local/share/applications" >/dev/null 2>&1 || true fi if command -v xdg-settings >/dev/null 2>&1; then xdg-settings set default-web-browser chromium.desktop || true fi if command -v xdg-mime >/dev/null 2>&1; then xdg-mime default HEY.desktop x-scheme-handler/mailto || true fi touch "$state_dir/setup-user.done" USER_SETUP } configure_pacman_channel install_keyrings remove_legacy_installer_package remove_conflicting_legacy_packages install_omarchy_4_packages cleanup_legacy_user_paths apply_system_transition apply_user_transition cleanup_retired_services remove_retired_default_packages cat <