mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-06 12:39:35 +02:00
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
|
||||
- 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.
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
pass "historical migrations are collapsed into the 4.0 migration"
|
||||
[[ ${#migrations[@]} -eq 0 ]] || fail "4.0 upgrade is not modeled as a migration"
|
||||
pass "4.0 upgrade is handled outside the migration runner"
|
||||
|
||||
Reference in New Issue
Block a user