Add Omarchy 4 upgrade bridge
Introduce a self-contained omarchy-upgrade-to-4 command for legacy installs and remove the 4.0 package-layout transition from the normal migration runner.
This commit is contained in:
@@ -184,6 +184,6 @@ New migration format:
|
|||||||
- Use `$OMARCHY_PATH` to reference the omarchy directory
|
- Use `$OMARCHY_PATH` to reference the omarchy directory
|
||||||
- Prefer helper commands such as `omarchy-cmd-present`, `omarchy-cmd-missing`, `omarchy-pkg-present`, and `omarchy-pkg-missing`
|
- Prefer helper commands such as `omarchy-cmd-present`, `omarchy-cmd-missing`, `omarchy-pkg-present`, and `omarchy-pkg-missing`
|
||||||
|
|
||||||
Omarchy 4.0 intentionally collapses historical migrations into a single package-layout migration. Do not add compatibility migrations for old installer layouts.
|
Omarchy 4.0 is upgraded through `bin/omarchy-upgrade-to-4`, not through the normal migration runner. Do not add compatibility migrations for old installer layouts; put pre-4 package-layout transition work in the upgrade command instead.
|
||||||
|
|
||||||
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for one-off repair work.
|
Migrations may use raw `pacman`, `command -v`, or direct config edits when needed for one-off repair work.
|
||||||
|
|||||||
Executable
+410
@@ -0,0 +1,410 @@
|
|||||||
|
#!/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."
|
||||||
|
|
||||||
|
run_as_user() {
|
||||||
|
if (( EUID == 0 )); then
|
||||||
|
sudo -u "$target_user" -H "$@"
|
||||||
|
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=$(sudo -u "$target_user" -H 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 <<EOF
|
||||||
|
|
||||||
|
This will upgrade Omarchy for user '$target_user' to Omarchy 4 using the '$channel' channel.
|
||||||
|
|
||||||
|
It will install the package-backed Omarchy 4 stack, overwrite files previously
|
||||||
|
written by the legacy installer, remove retired default packages, and refresh
|
||||||
|
system/user setup. A reboot is strongly recommended afterward.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [[ -r /dev/tty ]]; then
|
||||||
|
printf '\nContinue? [y/N] ' >/dev/tty
|
||||||
|
read -r answer </dev/tty
|
||||||
|
[[ $answer =~ ^[Yy]$ ]] || exit 0
|
||||||
|
else
|
||||||
|
fail "No TTY available for confirmation. Re-run with --yes to proceed non-interactively."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( EUID != 0 )); then
|
||||||
|
sudo -v
|
||||||
|
while true; do sudo -n true; sleep 60; done 2>/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)"
|
||||||
|
|
||||||
|
sudo install -d -m 0755 /etc/pacman.d
|
||||||
|
if [[ -f /etc/pacman.d/mirrorlist ]]; then
|
||||||
|
sudo cp -f /etc/pacman.d/mirrorlist "/etc/pacman.d/mirrorlist.omarchy-upgrade-to-4.$backup_suffix.bak"
|
||||||
|
fi
|
||||||
|
printf 'Server = %s\n' "$mirror_server" | sudo tee /etc/pacman.d/mirrorlist >/dev/null
|
||||||
|
|
||||||
|
if [[ ! -f /etc/pacman.conf ]]; then
|
||||||
|
fail "/etc/pacman.conf does not exist."
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo 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"
|
||||||
|
sudo install -m 0644 "$tmp" /etc/pacman.conf
|
||||||
|
rm -f "$tmp"
|
||||||
|
}
|
||||||
|
|
||||||
|
install_keyrings() {
|
||||||
|
log "Refreshing package databases and keyrings"
|
||||||
|
sudo pacman -Sy --noconfirm archlinux-keyring omarchy-keyring || {
|
||||||
|
warn "Keyring package install failed; attempting to trust the Omarchy packaging key directly."
|
||||||
|
sudo pacman-key --recv-keys 40DFB630FF42BCFFB047046CF0134EE680CAC571 --keyserver keys.openpgp.org || true
|
||||||
|
sudo pacman-key --lsign-key 40DFB630FF42BCFFB047046CF0134EE680CAC571 || true
|
||||||
|
sudo 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.
|
||||||
|
sudo pacman -Rdd --noconfirm omarchy-installer
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_omarchy_4_packages() {
|
||||||
|
local core_packages=(
|
||||||
|
omarchy-keyring
|
||||||
|
omarchy-settings
|
||||||
|
omarchy-limine
|
||||||
|
omarchy-nvim
|
||||||
|
omarchy
|
||||||
|
)
|
||||||
|
|
||||||
|
log "Installing Omarchy 4 packages"
|
||||||
|
sudo pacman -Syu --needed --noconfirm --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
|
||||||
|
sudo pacman -S --needed --noconfirm --overwrite='*' "${base_packages[@]}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "/usr/share/omarchy/install/omarchy-base.packages was not found; skipping default package set install."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_retired_default_packages() {
|
||||||
|
local retired_packages=(
|
||||||
|
1password-beta
|
||||||
|
1password-cli
|
||||||
|
alacritty
|
||||||
|
bluetui
|
||||||
|
claude-code
|
||||||
|
github-cli
|
||||||
|
hypridle
|
||||||
|
hyprlock
|
||||||
|
impala
|
||||||
|
iwd
|
||||||
|
mako
|
||||||
|
omarchy-walker
|
||||||
|
playerctl
|
||||||
|
polkit-gnome
|
||||||
|
signal-desktop
|
||||||
|
spotify
|
||||||
|
swaybg
|
||||||
|
swayosd
|
||||||
|
waybar
|
||||||
|
wiremix
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
sudo 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.
|
||||||
|
sudo systemctl disable iwd.service >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
run_as_user systemctl --user disable \
|
||||||
|
omarchy-battery-monitor.timer \
|
||||||
|
swayosd-server.service \
|
||||||
|
elephant.service \
|
||||||
|
app-walker@autostart.service \
|
||||||
|
>/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
run_omarchy_4_setup() {
|
||||||
|
log "Running Omarchy 4 system setup"
|
||||||
|
[[ -x /usr/bin/omarchy-setup-system ]] || fail "/usr/bin/omarchy-setup-system was not installed."
|
||||||
|
sudo env \
|
||||||
|
OMARCHY_PATH=/usr/share/omarchy \
|
||||||
|
OMARCHY_INSTALL=/usr/share/omarchy/install \
|
||||||
|
OMARCHY_INSTALL_USER="$target_user" \
|
||||||
|
OMARCHY_MIRROR="$channel" \
|
||||||
|
/usr/bin/omarchy-setup-system --install-user "$target_user" --upgrade
|
||||||
|
|
||||||
|
log "Running Omarchy 4 user setup"
|
||||||
|
[[ -x /usr/bin/omarchy-setup-user ]] || fail "/usr/bin/omarchy-setup-user was not installed."
|
||||||
|
run_as_user env \
|
||||||
|
OMARCHY_PATH=/usr/share/omarchy \
|
||||||
|
OMARCHY_INSTALL=/usr/share/omarchy/install \
|
||||||
|
OMARCHY_SETUP_CONTEXT=runtime \
|
||||||
|
/usr/bin/omarchy-setup-user --force
|
||||||
|
|
||||||
|
if [[ -x /usr/bin/omarchy-refresh-applications ]]; then
|
||||||
|
run_as_user env OMARCHY_PATH=/usr/share/omarchy /usr/bin/omarchy-refresh-applications
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_pacman_channel
|
||||||
|
install_keyrings
|
||||||
|
remove_legacy_installer_package
|
||||||
|
install_omarchy_4_packages
|
||||||
|
cleanup_legacy_user_paths
|
||||||
|
run_omarchy_4_setup
|
||||||
|
cleanup_retired_services
|
||||||
|
remove_retired_default_packages
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
Omarchy 4 upgrade complete.
|
||||||
|
|
||||||
|
Please reboot to finish switching to the package-backed Omarchy 4 session.
|
||||||
|
EOF
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
echo "Migrate to Omarchy 4.0 package layout"
|
|
||||||
|
|
||||||
# Omarchy 4.0 collapses the old git/online-installer layout into the packaged
|
|
||||||
# runtime layout. Packages own most static system files; these commands refresh
|
|
||||||
# the machine-specific and user-specific pieces in place.
|
|
||||||
channel=$(omarchy-version-channel 2>/dev/null | awk '{print $1}')
|
|
||||||
case "$channel" in
|
|
||||||
stable|rc|edge) ;;
|
|
||||||
*) channel=stable ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Fold post-4.0 pre-release migration work into the single 4.0 migration.
|
|
||||||
rm -f "$HOME/.local/bin/playwright-cli"
|
|
||||||
omarchy-pkg-drop claude-code github-cli
|
|
||||||
|
|
||||||
sudo env \
|
|
||||||
OMARCHY_PATH="${OMARCHY_PATH:-/usr/share/omarchy}" \
|
|
||||||
OMARCHY_INSTALL="${OMARCHY_INSTALL:-${OMARCHY_PATH:-/usr/share/omarchy}/install}" \
|
|
||||||
OMARCHY_INSTALL_USER="$USER" \
|
|
||||||
OMARCHY_MIRROR="${OMARCHY_MIRROR:-$channel}" \
|
|
||||||
/usr/bin/omarchy-setup-system --install-user "$USER" --upgrade
|
|
||||||
|
|
||||||
OMARCHY_SETUP_CONTEXT=runtime omarchy-setup-user --force
|
|
||||||
omarchy-refresh-applications
|
|
||||||
@@ -88,5 +88,5 @@ PY
|
|||||||
pass "default bar widget ids resolve to manifests and entry points"
|
pass "default bar widget ids resolve to manifests and entry points"
|
||||||
|
|
||||||
mapfile -t migrations < <(find "$ROOT/migrations" -maxdepth 1 -type f -name '*.sh' -printf '%f\n' | sort)
|
mapfile -t migrations < <(find "$ROOT/migrations" -maxdepth 1 -type f -name '*.sh' -printf '%f\n' | sort)
|
||||||
[[ ${#migrations[@]} -eq 1 && ${migrations[0]} == "1780000000_4_0.sh" ]] || fail "historical migrations are collapsed"
|
[[ ${#migrations[@]} -eq 0 ]] || fail "4.0 upgrade is not modeled as a migration"
|
||||||
pass "historical migrations are collapsed into the 4.0 migration"
|
pass "4.0 upgrade is handled outside the migration runner"
|
||||||
|
|||||||
Reference in New Issue
Block a user