diff --git a/bin/omarchy-refresh-fastfetch b/bin/omarchy-refresh-fastfetch deleted file mode 100755 index c7988b71..00000000 --- a/bin/omarchy-refresh-fastfetch +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -# omarchy:summary=Overwrite the user config for fastfetch with the Omarchy default. - -omarchy-refresh-config fastfetch/config.jsonc diff --git a/bin/omarchy-upgrade-to-4 b/bin/omarchy-upgrade-to-4 index 11c7f745..9044db86 100755 --- a/bin/omarchy-upgrade-to-4 +++ b/bin/omarchy-upgrade-to-4 @@ -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 _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" <&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 </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 diff --git a/bin/omarchy-version b/bin/omarchy-version index da8b4974..eaa203a6 100755 --- a/bin/omarchy-version +++ b/bin/omarchy-version @@ -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" diff --git a/bin/omarchy-version-branch b/bin/omarchy-version-branch new file mode 100755 index 00000000..efec57d0 --- /dev/null +++ b/bin/omarchy-version-branch @@ -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" diff --git a/default/omarchy-skill/SKILL.md b/default/omarchy-skill/SKILL.md index 193c205c..474d4449 100644 --- a/default/omarchy-skill/SKILL.md +++ b/default/omarchy-skill/SKILL.md @@ -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` | diff --git a/docs/file-layout.md b/docs/file-layout.md index c989a208..e925a245 100644 --- a/docs/file-layout.md +++ b/docs/file-layout.md @@ -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? diff --git a/docs/migrations.md b/docs/migrations.md index e8db4a68..7e0e58fb 100644 --- a/docs/migrations.md +++ b/docs/migrations.md @@ -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: diff --git a/config/fastfetch/config.jsonc b/etc/fastfetch/config.jsonc similarity index 95% rename from config/fastfetch/config.jsonc rename to etc/fastfetch/config.jsonc index 86b05d01..0bacc465 100644 --- a/config/fastfetch/config.jsonc +++ b/etc/fastfetch/config.jsonc @@ -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", diff --git a/test/shell.d/config-test.sh b/test/shell.d/config-test.sh index c4873a6f..8caf2e0e 100755 --- a/test/shell.d/config-test.sh +++ b/test/shell.d/config-test.sh @@ -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"),