#!/usr/bin/env bash # server-config-cli installer # # Usage (always latest, no version needed): # curl -fsSL https://gitea1.deeppolicy.cn:3002/hanruo/server-config-cli/raw/branch/main/scripts/install.sh | bash # # Environment overrides: # VERSION release tag to install (default: latest) # NODE_VERSION portable Node version (default: v20.18.1) # NODE_MIRROR Node download base URL # REPO_BASE Gitea repo URL # SERVER_CONFIG_HOME install root (default: $HOME/.server-config) # SERVER_CONFIG_BIN launcher dir (default: $HOME/.local/bin) set -euo pipefail REPO_BASE="${REPO_BASE:-https://gitea1.deeppolicy.cn:3002/hanruo/server-config-cli}" VERSION="${VERSION:-latest}" NODE_VERSION="${NODE_VERSION:-v20.18.1}" NODE_MIRROR="${NODE_MIRROR:-https://registry.npmmirror.com/-/binary/node}" INSTALL_DIR="${SERVER_CONFIG_HOME:-$HOME/.server-config}" BIN_DIR="${SERVER_CONFIG_BIN:-$HOME/.local/bin}" log() { printf '\033[1;34m==>\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m!!\033[0m %s\n' "$*" >&2; } die() { printf '\033[1;31mxx\033[0m %s\n' "$*" >&2; exit 1; } command -v curl >/dev/null 2>&1 || die "curl is required" command -v tar >/dev/null 2>&1 || die "tar is required" OS=$(uname -s | tr '[:upper:]' '[:lower:]') case "$OS" in linux) NODE_OS=linux ;; darwin) NODE_OS=darwin ;; *) die "unsupported OS: $OS" ;; esac ARCH=$(uname -m) case "$ARCH" in x86_64|amd64) NODE_ARCH=x64 ;; aarch64|arm64) NODE_ARCH=arm64 ;; *) die "unsupported arch: $ARCH" ;; esac NODE_PKG="node-${NODE_VERSION}-${NODE_OS}-${NODE_ARCH}.tar.gz" NODE_URL="${NODE_MIRROR}/${NODE_VERSION}/${NODE_PKG}" NODE_DIR="${INSTALL_DIR}/node-${NODE_VERSION}-${NODE_OS}-${NODE_ARCH}" if [ "$VERSION" = "latest" ]; then # Resolve the newest release tag via the API (works on all Gitea versions, # unlike the GitHub-style /releases/latest/download shortcut). proto="${REPO_BASE%%://*}" rest="${REPO_BASE#*://}" host="${rest%%/*}" repo_path="${rest#*/}" API_BASE="${proto}://${host}/api/v1/repos/${repo_path}" log "Resolving latest release tag" TAG=$(curl -fsSL "${API_BASE}/releases/latest" \ | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' \ | head -1 \ | sed -E 's/.*"tag_name"[[:space:]]*:[[:space:]]*"([^"]*)".*/\1/') [ -n "$TAG" ] || die "could not resolve latest release tag from ${API_BASE}/releases/latest" log "Latest release is ${TAG}" BUNDLE_URL="${REPO_BASE}/releases/download/${TAG}/app.mjs" else BUNDLE_URL="${REPO_BASE}/releases/download/${VERSION}/app.mjs" fi mkdir -p "$INSTALL_DIR" "$BIN_DIR" if [ ! -x "${NODE_DIR}/bin/node" ]; then log "Downloading Node ${NODE_VERSION} (${NODE_OS}-${NODE_ARCH})" TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT curl -fL --progress-bar "$NODE_URL" -o "${TMP}/node.tar.gz" \ || die "failed to download $NODE_URL" tar -xzf "${TMP}/node.tar.gz" -C "$INSTALL_DIR" [ -x "${NODE_DIR}/bin/node" ] || die "Node extraction did not produce ${NODE_DIR}/bin/node" else log "Reusing existing Node at ${NODE_DIR}" fi log "Downloading server-config bundle (${VERSION})" mkdir -p "${INSTALL_DIR}/app" curl -fL --progress-bar "$BUNDLE_URL" -o "${INSTALL_DIR}/app/app.mjs" \ || die "failed to download $BUNDLE_URL" log "Writing launcher to ${BIN_DIR}/server-config" cat > "${BIN_DIR}/server-config" < server-config" case ":$PATH:" in *":${BIN_DIR}:"*) ;; *) echo warn "${BIN_DIR} is not in your PATH." echo " Add this to ~/.zshrc or ~/.bashrc:" echo " export PATH=\"${BIN_DIR}:\$PATH\"" ;; esac echo echo "Run: server-config"