#!/usr/bin/env bash set -euo pipefail ######################################## # Seby's Calagopus Wings Updater # curl | bash safe ######################################## ######################################## # Styling ######################################## TTY="/dev/tty" BOLD="\033[1m" GREEN="\033[32m" YELLOW="\033[33m" RED="\033[31m" BLUE="\033[34m" RESET="\033[0m" section() { printf "\n${BLUE}${BOLD}==> %s${RESET}\n" "$*"; } say() { printf "${GREEN}✔ %s${RESET}\n" "$*"; } warn() { printf "${YELLOW}⚠ %s${RESET}\n" "$*"; } err() { printf "${RED}✖ %s${RESET}\n" "$*"; } have() { command -v "$1" >/dev/null 2>&1; } require_root_or_sudo() { if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then if have sudo; then SUDO="sudo" else err "Root or sudo required." exit 1 fi else SUDO="" fi } ######################################## # Spinner (writes to /dev/tty so curl|bash stays safe) ######################################## run_with_spinner() { local label="$1"; shift ("$@") & local pid=$! local spin='|/-\' local i=0 printf "\033[?25l" >"$TTY" || true while kill -0 "$pid" 2>/dev/null; do i=$(( (i + 1) % 4 )) printf "\r${BLUE}${BOLD}..${RESET} %s %s" "${spin:$i:1}" "$label" >"$TTY" sleep 0.12 done wait "$pid" local rc=$? printf "\r\033[K" >"$TTY" printf "\033[?25h" >"$TTY" || true return "$rc" } ######################################## # Header ######################################## clear cat << "EOF" ____ _ / ___|__ _| | __ _ __ _ ___ _ __ _ _ ___ | | / _` | |/ _` |/ _` |/ _ \| '_ \| | | / __| | |__| (_| | | (_| | (_| | (_) | |_) | |_| \__ \ \____\__,_|_|\__,_|\__, |\___/| .__/ \__,_|___/ |___/ |_| Calagopus Wings Updater | v1.0 EOF require_root_or_sudo if ! have systemctl; then err "systemctl not found — is this a systemd host?" exit 1 fi if ! have curl; then err "curl not found. Install it and re-run." exit 1 fi ######################################## # Setup ######################################## WINGS_BIN="/usr/local/bin/wings" ARCH="$(uname -m)" case "$ARCH" in x86_64|amd64) WINGS_ARCH="x86_64" ;; aarch64|arm64) WINGS_ARCH="aarch64" ;; *) err "Unsupported architecture: $ARCH" exit 1 ;; esac WINGS_URL="https://github.com/calagopus/wings/releases/latest/download/wings-rs-${WINGS_ARCH}-linux" TMP_FILE="$(mktemp /tmp/wings-XXXXXX)" cleanup() { rm -f "$TMP_FILE"; } trap cleanup EXIT ######################################## # Download ######################################## section "Downloading Wings" if run_with_spinner "Fetching latest wings-rs build for ${WINGS_ARCH}..." \ curl -fL --retry 3 --retry-delay 2 -o "$TMP_FILE" "$WINGS_URL"; then say "Download complete" else err "Download failed — check your connection or verify a build exists for arch '${WINGS_ARCH}' at:" err " ${WINGS_URL}" exit 1 fi if [[ ! -s "$TMP_FILE" ]]; then err "Downloaded file is empty — aborting to avoid a broken install" exit 1 fi chmod +x "$TMP_FILE" if file "$TMP_FILE" | grep -qi "ASCII text\|HTML"; then err "Downloaded file doesn't look like a binary — GitHub may have returned an error page" exit 1 fi say "Binary verified" ######################################## # Backup ######################################## if [[ -f "$WINGS_BIN" ]]; then BACKUP_PATH="${WINGS_BIN}.bak-$(date +%Y%m%d%H%M%S)" $SUDO cp -a "$WINGS_BIN" "$BACKUP_PATH" say "Backed up existing binary to ${BACKUP_PATH}" fi ######################################## # Stop, swap, start ######################################## section "Restarting Service" if $SUDO systemctl is-active --quiet wings 2>/dev/null; then $SUDO systemctl stop wings say "Stopped wings" else warn "wings was not running (continuing)" fi $SUDO mv "$TMP_FILE" "$WINGS_BIN" $SUDO chmod +x "$WINGS_BIN" say "Installed new binary to ${WINGS_BIN}" $SUDO systemctl start wings say "Started wings" ######################################## # Verify ######################################## sleep 2 section "Done" if $SUDO systemctl is-active --quiet wings; then say "Wings updated and running successfully" "$WINGS_BIN" version || true else err "wings failed to start after update — check: journalctl -u wings -n 50 --no-pager" exit 1 fi