#!/bin/bash # Launched by SystemUpdate.qml (top bar, next to the clock) — opens a # terminal running whatever update command fits this distro, then notifies # once it's done. Ported from the old waybar custom/updater module # (.config/waybar/scripts/update-distro.sh); kept multi-distro even though # this machine is Arch, since these dotfiles aren't. # # The window it opens is floated + centered by a matching Hyprland rule # (system-update-terminal, in .config/hypr/layout/windowrules.lua), # same treatment as Bitwarden's window, rather than tiling into whatever # workspace you happened to be on. iDIR="$HOME/.config/swaync/images" # Printed inside the terminal before the actual update command runs, so it # reads as "updating" from the first frame rather than looking like an # empty/stuck window while pacman/apt/etc. take a moment to start printing. # # The terminal runs this in a fresh `bash -c`, which doesn't inherit shell # functions from this script's own environment (export -f only reaches bash # processes forked from *this* one, not whatever the terminal execs) — so # instead, the already-colored text is built once here with real escape # bytes ($'...'), then %q-quoted into a self-contained `echo '...'` that # reproduces those same bytes verbatim when the child bash parses it. msg=" Updating System — please wait " line=$(printf '=%.0s' $(seq 1 ${#msg})) banner_text=$'\033[1;36m'"$line"$'\033[0m\n\033[1;36m'"$msg"$'\033[0m\n\033[1;36m'"$line"$'\033[0m\n\n' BANNER="echo $(printf '%q' "$banner_text")" # GHOSTTY_INSTALL is how to install the terminal on this distro, if it's # packaged there at all — only Arch ships it in the official repos. if command -v paru &> /dev/null; then CMD="paru -Syu" LABEL="Arch-based system" GHOSTTY_INSTALL="pacman -S --needed --noconfirm ghostty" elif command -v yay &> /dev/null; then CMD="yay -Syu" LABEL="Arch-based system" GHOSTTY_INSTALL="pacman -S --needed --noconfirm ghostty" elif command -v dnf &> /dev/null; then CMD="sudo dnf update --refresh -y" LABEL="Fedora system" elif command -v apt &> /dev/null; then CMD="sudo apt update && sudo apt upgrade -y" LABEL="Debian/Ubuntu system" elif command -v zypper &> /dev/null; then CMD="sudo zypper dup -y" LABEL="openSUSE system" else notify-send -i "$iDIR/error.png" -u critical "Unsupported system" "This script does not support your distribution." exit 1 fi # --- Terminal: Ghostty, offering to install it if missing --- # This runs from the bar with no terminal of its own, so there's nowhere to # type a sudo password — the install goes through pkexec instead, which # pops up the polkit agent's graphical password prompt. Declining (or a # failed install) falls back to foot for this run, so updating never gets # blocked on the terminal choice. if ! command -v ghostty &> /dev/null; then if [ -n "$GHOSTTY_INSTALL" ]; then # -A waits for a click and prints the chosen action's name (nothing if # the notification is dismissed instead). choice=$(notify-send -i "$iDIR/error.png" -u critical \ -A install="Install Ghostty" -A foot="Use foot this time" \ "Ghostty not installed" "The system updater runs in Ghostty. Install it now?") if [ "$choice" = "install" ]; then if pkexec $GHOSTTY_INSTALL; then notify-send -i "$iDIR/profile-pic.jpg" -u low "Ghostty installed" "Starting the update..." else notify-send -i "$iDIR/error.png" "Ghostty install failed" "Using foot for this update." fi fi else notify-send -i "$iDIR/error.png" "Ghostty not installed" \ "Install Ghostty for the system updater — using foot for now." fi fi if command -v ghostty &> /dev/null; then # --gtk-single-instance=false: otherwise, with a Ghostty window already # open, this would just hand the window off to that running instance and # return immediately — SystemUpdates.qml relies on this script blocking # until the update window is closed (that's when it re-checks the count), # and the "has been updated" notification below would fire up front. TERMINAL=(ghostty --gtk-single-instance=false --title=update -e) elif command -v foot &> /dev/null; then TERMINAL=(foot -T update) else notify-send -i "$iDIR/error.png" "Need a terminal:" "Neither Ghostty nor foot is installed." exit 1 fi # Keeps the terminal open (whether the update succeeded or failed — read # always runs regardless, since it's ; not &&) until you press Enter, # instead of the terminal closing the instant the update command exits and # taking any output/errors with it. WAIT_PROMPT="echo; read -p 'Update finished — press Enter to close...'" # Pull + re-stow the dotfiles first, so config changes from the other machine # land alongside the package update. SYNC="$(printf '%q' "$(dirname "$0")/sync-dotfiles.sh")" "${TERMINAL[@]}" bash -c "$BANNER; $SYNC; $CMD; $WAIT_PROMPT" notify-send -i "$iDIR/profile-pic.jpg" -u low "$LABEL" 'has been updated.'