#!/bin/bash set -e # ── Configuration ──────────────────────────────────────────────────────────── BINARY="ostiary" REPO_API="${OSTIARY_API:-https://git.vainend.com/api/v1/repos/admin/ostiary}" INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}" # ── Colors ─────────────────────────────────────────────────────────────────── RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' CYAN='\033[0;36m'; NC='\033[0m' info() { echo -e "${CYAN}[ostiary]${NC} $*"; } ok() { echo -e "${GREEN}[ostiary]${NC} $*"; } warn() { echo -e "${YELLOW}[ostiary]${NC} $*"; } die() { echo -e "${RED}[ostiary]${NC} $*" >&2; exit 1; } # ── Detect OS ──────────────────────────────────────────────────────────────── case "$(uname -s)" in Linux) OS="linux" ;; Darwin) OS="macos" ;; *) die "Unsupported OS: $(uname -s)" ;; esac # ── Detect architecture ────────────────────────────────────────────────────── case "$(uname -m)" in x86_64) ARCH="x86_64" ;; aarch64|arm64) ARCH="aarch64" ;; *) die "Unsupported architecture: $(uname -m)" ;; esac ASSET="${BINARY}-${OS}-${ARCH}" info "Platform: ${OS}-${ARCH}" # ── HTTP helper ────────────────────────────────────────────────────────────── if command -v curl &>/dev/null; then fetch() { curl -fsSL "$1"; } fetch_file() { curl -fsSL -o "$2" "$1"; } http_code() { curl -o /dev/null -sLw "%{http_code}" "$1"; } elif command -v wget &>/dev/null; then fetch() { wget -qO- "$1"; } fetch_file() { wget -qO "$2" "$1"; } http_code() { wget -q --server-response -O /dev/null "$1" 2>&1 \ | awk '/^ HTTP/{code=$2} END{print code}'; } else die "curl or wget is required" fi # ── Fetch latest release tag ───────────────────────────────────────────────── # Uses /releases/latest which returns the newest non-prerelease, non-draft release. info "Fetching latest release info..." LATEST_JSON=$(fetch "${REPO_API}/releases/latest") \ || die "Failed to reach Gitea API: ${REPO_API}" VERSION=$(printf '%s' "$LATEST_JSON" \ | grep -o '"tag_name":"[^"]*"' \ | head -1 \ | cut -d'"' -f4) [ -z "$VERSION" ] && die "Could not parse version from API response" ok "Latest version: ${VERSION}" # ── Build download URL ─────────────────────────────────────────────────────── # Strip /api/v1/repos from the API base to get the Gitea web URL: # https://git.vainend.com/api/v1/repos/admin/ostiary # → https://git.vainend.com/admin/ostiary BASE_URL=$(printf '%s' "$REPO_API" | sed 's|/api/v1/repos||') DOWNLOAD_URL="${BASE_URL}/releases/download/${VERSION}/${ASSET}" info "Downloading ${DOWNLOAD_URL}..." # Quick existence check before downloading the full binary CODE=$(http_code "$DOWNLOAD_URL") [ "$CODE" = "200" ] || die "Asset not found (HTTP ${CODE}): ${ASSET}\nCheck that the release contains a file named '${ASSET}'" # ── Download to temp file ──────────────────────────────────────────────────── TMP=$(mktemp) trap 'rm -f "$TMP"' EXIT fetch_file "$DOWNLOAD_URL" "$TMP" || die "Download failed" chmod +x "$TMP" # ── Install ────────────────────────────────────────────────────────────────── do_install() { local dest="$1/$BINARY" if [ -w "$1" ]; then mv "$TMP" "$dest" ok "Installed → $dest" return 0 elif command -v sudo &>/dev/null; then warn "Writing to $1 requires sudo..." sudo mv "$TMP" "$dest" ok "Installed → $dest" return 0 fi return 1 } if ! do_install "$INSTALL_DIR"; then FALLBACK="$HOME/.local/bin" warn "${INSTALL_DIR} is not writable and sudo is unavailable" warn "Installing to ${FALLBACK} instead" mkdir -p "$FALLBACK" mv "$TMP" "$FALLBACK/$BINARY" ok "Installed → $FALLBACK/$BINARY" if [[ ":$PATH:" != *":$FALLBACK:"* ]]; then warn "Add to your shell profile:" warn " export PATH=\"\$HOME/.local/bin:\$PATH\"" fi fi echo "" ok "Done! Run: $BINARY"