The protected entrypoints revoked the sudo timestamp before installing their cleanup traps, so a signal or failure during that first sudo -k exited without the cleanup path. Install the traps first. The shell restart probed the notification bus name with busctl's default 25 second timeout, so an unresponsive user bus could stall the restart by that much per probe. Bound each probe to one second. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
151 lines
5.0 KiB
Bash
Executable File
151 lines
5.0 KiB
Bash
Executable File
#!/bin/bash -p
|
|
|
|
# omarchy:summary=Set the Omarchy package channel.
|
|
# omarchy:args=<stable|rc|edge|dev>
|
|
# omarchy:requires-sudo=true
|
|
|
|
if [[ $- != *p* ]]; then
|
|
echo "Refusing an unsafe Bash startup for channel switching." >&2
|
|
exit 126
|
|
fi
|
|
security_entrypoint=$(/usr/bin/readlink -e -- "${BASH_SOURCE[0]}") || exit 126
|
|
source "${security_entrypoint%/*}/omarchy-security-functions" || exit 126
|
|
omarchy_security_require_privileged_bash_startup || exit 126
|
|
set -euo pipefail
|
|
omarchy_security_sanitize_bash_environment "$0" "$@"
|
|
omarchy_security_require_source_root "$0"
|
|
user_path=$PATH
|
|
# Traps first, so a signal or failure during the entry revocation still
|
|
# exits through the cleanup path.
|
|
omarchy_security_install_sudo_cleanup_traps
|
|
omarchy_security_revoke_sudo_timestamp || exit 1
|
|
omarchy_security_enable_no_update_sudo
|
|
|
|
usage() { echo "Usage: omarchy-channel-set [stable|rc|edge|dev]"; }
|
|
fail() { echo "Error: $*" >&2; exit 1; }
|
|
|
|
confirm_dev() {
|
|
cat <<'WARNING'
|
|
|
|
The dev channel links Omarchy directly to a checkout of the source in ~/omarchy.
|
|
It's exclusively intended for developers working on Omarchy itself.
|
|
|
|
WARNING
|
|
|
|
gum confirm --default=false "Switch to dev channel?"
|
|
}
|
|
|
|
validate_dev_checkout() {
|
|
local checkout="$1"
|
|
|
|
if [[ -e $checkout && ! -d $checkout/.git ]]; then
|
|
fail "$checkout already exists and is not a git checkout."
|
|
fi
|
|
|
|
if [[ -d $checkout/.git && ( ! -d $checkout/bin || ! -d $checkout/default || ! -d $checkout/shell ) ]]; then
|
|
fail "$checkout is a git checkout, but it does not look like Omarchy."
|
|
fi
|
|
}
|
|
|
|
link_dev_checkout() {
|
|
local checkout="$1" required
|
|
[[ -d $checkout/.git ]] || git clone https://github.com/omacom/omarchy.git "$checkout"
|
|
|
|
# Check the destination before changing /etc/omarchy.conf or sudo's path.
|
|
# An existing checkout is not pulled automatically and may predate this policy.
|
|
for required in bin/omarchy-security-functions bin/omarchy-update bin/omarchy-refresh-pacman default/omarchy/sudo-no-update/sudo; do
|
|
if [[ ! -f $checkout/$required || ! -r $checkout/$required ||
|
|
( $required != "bin/omarchy-security-functions" && ! -x $checkout/$required ) ]]; then
|
|
fail "Update the checkout before switching to dev; missing required update support in $required."
|
|
fi
|
|
done
|
|
|
|
omarchy-dev-link "$checkout" --no-reboot
|
|
}
|
|
|
|
# A packaged destination cannot be inspected before its package is installed,
|
|
# and a package transaction can replace the running tree with a release that
|
|
# predates the command-scoped wrapper. After that, a bare sudo would resolve to
|
|
# /usr/bin/sudo and publish a timestamp, and the destination's own updater
|
|
# authenticates the same way. Neither may run from a flow that has just run
|
|
# user hooks: stop at a consistent point and say how to finish from a fresh
|
|
# session.
|
|
stop_for_older_destination() {
|
|
cat >&2 <<EOF
|
|
The destination predates command-scoped sudo, so this switch stops before its update.
|
|
Packages are switched. Run 'omarchy update' from a new terminal to finish, then reboot if prompted.
|
|
EOF
|
|
exit 3
|
|
}
|
|
|
|
wrapper_present() {
|
|
[[ -f $OMARCHY_PATH/default/omarchy/sudo-no-update/sudo && -x $OMARCHY_PATH/default/omarchy/sudo-no-update/sudo ]]
|
|
}
|
|
|
|
(( $# > 0 )) || { usage; exit 1; }
|
|
|
|
dev_checkout=""
|
|
channel="$1"
|
|
leaving_dev=0
|
|
|
|
case "$channel" in
|
|
stable)
|
|
pacman_channel=stable
|
|
packages=(omarchy omarchy-settings)
|
|
;;
|
|
rc)
|
|
pacman_channel=rc
|
|
packages=(omarchy omarchy-settings)
|
|
;;
|
|
edge)
|
|
pacman_channel=edge
|
|
packages=(omarchy-dev omarchy-settings-dev)
|
|
;;
|
|
dev)
|
|
confirm_dev || { echo "Cancelled."; exit 0; }
|
|
dev_checkout="$HOME/omarchy"
|
|
validate_dev_checkout "$dev_checkout"
|
|
pacman_channel=edge
|
|
packages=(omarchy-dev omarchy-settings-dev)
|
|
;;
|
|
*)
|
|
echo "Unknown channel: $channel" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# A failure past this point leaves the channel switch half-applied, so say how
|
|
# to pick it back up rather than dying silently under set -e.
|
|
trap 'echo -e "\nThe channel switch did not complete. Review the error above, then rerun: omarchy-channel-set '"$channel"'" >&2' ERR
|
|
|
|
if [[ -z $dev_checkout && $OMARCHY_PATH != "/usr/share/omarchy" ]]; then
|
|
leaving_dev=1
|
|
fi
|
|
|
|
if [[ -n $dev_checkout ]]; then
|
|
link_dev_checkout "$dev_checkout"
|
|
export OMARCHY_PATH="$dev_checkout"
|
|
omarchy_security_enable_no_update_sudo
|
|
omarchy-state set reboot-required
|
|
fi
|
|
|
|
OMARCHY_UPDATE_USER_PATH="$user_path" omarchy-refresh-pacman "$pacman_channel"
|
|
# Each transaction can have replaced this tree; check before the next sudo.
|
|
wrapper_present || stop_for_older_destination
|
|
# --ask 4 accepts omarchy <-> omarchy-dev replacement prompts without file overwrites.
|
|
omarchy-update-pacman -S --needed --noconfirm --ask 4 "${packages[@]}"
|
|
wrapper_present || stop_for_older_destination
|
|
|
|
if [[ -z $dev_checkout ]]; then
|
|
omarchy-dev-unlink --no-reboot
|
|
export OMARCHY_PATH=/usr/share/omarchy
|
|
|
|
if (( leaving_dev )); then
|
|
omarchy-state set reboot-required
|
|
fi
|
|
omarchy_security_enable_no_update_sudo 2>/dev/null || stop_for_older_destination
|
|
fi
|
|
|
|
OMARCHY_UPDATE_USER_PATH="$user_path" "$OMARCHY_PATH/bin/omarchy-update" -y
|