#!/usr/bin/env bash # ============================================================================== # install.sh — HanaToolbox installer # Downloads the latest native AOT binary from Gitea and installs it. # Optionally runs the onboarding wizard for first-time setup. # # Usage: # curl -fsSL https://git.technopunk.space/tomi/HanaToolbox/raw/branch/main/install.sh | bash # # or with onboard: # curl -fsSL .../install.sh | bash -s -- --onboard # ============================================================================== set -euo pipefail # ── Config ──────────────────────────────────────────────────────────────────── REPO_API="https://git.technopunk.space/api/v1/repos/tomi/HanaToolbox/releases/latest" BINARY_NAME="hanatoolbox" INSTALL_DIR="/usr/local/bin" INSTALL_PATH="${INSTALL_DIR}/${BINARY_NAME}" # ── Colours ─────────────────────────────────────────────────────────────────── RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' CYAN='\033[0;36m'; RESET='\033[0m' info() { echo -e "${CYAN}ℹ $*${RESET}"; } success() { echo -e "${GREEN}✅ $*${RESET}"; } warn() { echo -e "${YELLOW}⚠ $*${RESET}"; } error() { echo -e "${RED}❌ $*${RESET}" >&2; exit 1; } # ── Arg parsing ─────────────────────────────────────────────────────────────── RUN_ONBOARD=false for arg in "$@"; do [[ "$arg" == "--onboard" ]] && RUN_ONBOARD=true done # ── Root check ──────────────────────────────────────────────────────────────── if [[ $EUID -ne 0 ]]; then error "This installer must be run as root (sudo or root shell)." fi # ── Dependency check ────────────────────────────────────────────────────────── for tool in curl jq; do if ! command -v "$tool" &>/dev/null; then error "Required tool '${tool}' is not installed. Install it and re-run." fi done # ── Fetch latest release info ───────────────────────────────────────────────── info "Fetching latest release from Gitea..." RELEASE_JSON=$(curl -fsSL "$REPO_API") \ || error "Failed to fetch release info from ${REPO_API}" TAG=$(echo "$RELEASE_JSON" | jq -r '.tag_name') \ || error "Could not parse tag_name from release JSON." if [[ -z "$TAG" || "$TAG" == "null" ]]; then error "No release found in the repository yet. Publish a release first." fi info "Latest release: ${TAG}" # ── Find the binary asset ───────────────────────────────────────────────────── DOWNLOAD_URL=$(echo "$RELEASE_JSON" \ | jq -r --arg name "$BINARY_NAME" \ '.assets[] | select(.name == $name) | .browser_download_url') if [[ -z "$DOWNLOAD_URL" || "$DOWNLOAD_URL" == "null" ]]; then error "No asset named '${BINARY_NAME}' found in release ${TAG}." fi info "Download URL: ${DOWNLOAD_URL}" # ── Download ────────────────────────────────────────────────────────────────── TMP_FILE=$(mktemp) trap 'rm -f "$TMP_FILE"' EXIT info "Downloading ${BINARY_NAME} ${TAG}..." curl -fsSL --progress-bar -o "$TMP_FILE" "$DOWNLOAD_URL" \ || error "Download failed." # ── Install ─────────────────────────────────────────────────────────────────── # Backup current binary if it exists if [[ -f "$INSTALL_PATH" ]]; then cp "$INSTALL_PATH" "${INSTALL_PATH}.bak" warn "Previous binary backed up to ${INSTALL_PATH}.bak" fi install -m 0755 "$TMP_FILE" "$INSTALL_PATH" success "${BINARY_NAME} ${TAG} installed to ${INSTALL_PATH}" # ── Verify ──────────────────────────────────────────────────────────────────── if ! "$INSTALL_PATH" --help &>/dev/null; then warn "Binary installed but failed self-test. Check architecture compatibility." else success "Self-test passed." fi # ── Cron entry hint ─────────────────────────────────────────────────────────── CRON_FILE="/etc/cron.d/hanatoolbox" if [[ ! -f "$CRON_FILE" ]]; then echo -e "\n${CYAN}To enable scheduled tasks, add this cron entry:${RESET}" echo -e " ${YELLOW}* * * * * root ${INSTALL_PATH} cron${RESET}" echo -e " e.g.: echo '* * * * * root ${INSTALL_PATH} cron' > ${CRON_FILE}" echo "" fi # ── Onboard ─────────────────────────────────────────────────────────────────── if [[ "$RUN_ONBOARD" == true ]]; then echo "" info "Starting onboarding wizard..." exec "$INSTALL_PATH" onboard fi echo "" success "Installation complete! Run '${BINARY_NAME} onboard' to configure."