#!/bin/sh set -e # Compute Portal CLI installer # Usage: curl -fsSL https://install.computeportal.io | sh BASE_URL="https://install.computeportal.io" BINARY_NAME="cpctl" INSTALL_DIR="${CP_INSTALL_DIR:-/usr/local/bin}" # ── Terminal colours ────────────────────────────────────────────────────────── if [ -t 1 ] && command -v tput >/dev/null 2>&1; then BOLD="$(tput bold 2>/dev/null || true)" GREEN="$(tput setaf 2 2>/dev/null || true)" YELLOW="$(tput setaf 3 2>/dev/null || true)" RED="$(tput setaf 1 2>/dev/null || true)" RESET="$(tput sgr0 2>/dev/null || true)" else BOLD="" GREEN="" YELLOW="" RED="" RESET="" fi log() { printf '%s==>%s %s\n' "${GREEN}${BOLD}" "${RESET}" "$*"; } warn() { printf '%s==>%s %sWARNING:%s %s\n' "${YELLOW}${BOLD}" "${RESET}" "${YELLOW}" "${RESET}" "$*"; } die() { printf '%s==>%s %sERROR:%s %s\n' "${RED}${BOLD}" "${RESET}" "${RED}" "${RESET}" "$*" >&2; exit 1; } # ── Detect OS ───────────────────────────────────────────────────────────────── OS="$(uname -s 2>/dev/null | tr '[:upper:]' '[:lower:]')" case "${OS}" in linux) OS="linux" ;; darwin) OS="darwin" ;; *) die "Unsupported OS: ${OS}. Supported: linux, darwin." ;; esac # ── Detect architecture ─────────────────────────────────────────────────────── ARCH="$(uname -m 2>/dev/null)" case "${ARCH}" in x86_64|amd64) ARCH="amd64" ;; aarch64|arm64|arm*) ARCH="arm64" ;; *) die "Unsupported architecture: ${ARCH}. Supported: amd64, arm64." ;; esac # ── Detect download tool ────────────────────────────────────────────────────── if command -v curl >/dev/null 2>&1; then DOWNLOAD="curl -fsSL" DOWNLOAD_TO="curl -fsSL -o" elif command -v wget >/dev/null 2>&1; then DOWNLOAD="wget -qO-" DOWNLOAD_TO="wget -qO" else die "curl or wget is required to install the Compute Portal CLI." fi # ── Resolve version ─────────────────────────────────────────────────────────── if [ -n "${CP_VERSION:-}" ]; then VERSION="${CP_VERSION}" else log "Fetching latest version..." VERSION="$(${DOWNLOAD} "${BASE_URL}/version" 2>/dev/null | tr -d '[:space:]')" [ -n "${VERSION}" ] || die "Could not fetch version from ${BASE_URL}/version" fi log "Installing Compute Portal CLI ${VERSION} (${OS}/${ARCH})..." # ── Build URLs ──────────────────────────────────────────────────────────────── BINARY_ASSET="cpctl-${OS}-${ARCH}" DOWNLOAD_URL="${BASE_URL}/releases/${VERSION}/${BINARY_ASSET}" CHECKSUM_URL="${BASE_URL}/releases/${VERSION}/${BINARY_ASSET}.sha256" # ── Check install dir ───────────────────────────────────────────────────────── BINARY_PATH="${INSTALL_DIR}/${BINARY_NAME}" NEED_SUDO=0 if [ ! -w "${INSTALL_DIR}" ]; then NEED_SUDO=1 command -v sudo >/dev/null 2>&1 || die "sudo is required to write to ${INSTALL_DIR}. Set CP_INSTALL_DIR to a writable directory." fi # ── Download binary ─────────────────────────────────────────────────────────── TMP_FILE="$(mktemp)" trap 'rm -f "${TMP_FILE}"' EXIT INT TERM log "Downloading ${DOWNLOAD_URL}..." ${DOWNLOAD_TO} "${TMP_FILE}" "${DOWNLOAD_URL}" || die "Download failed. Try: CP_VERSION= curl -fsSL ${BASE_URL} | sh" # ── Verify checksum ─────────────────────────────────────────────────────────── EXPECTED="$(${DOWNLOAD} "${CHECKSUM_URL}" 2>/dev/null | awk '{print $1}' || true)" if [ -n "${EXPECTED}" ]; then log "Verifying checksum..." if command -v sha256sum >/dev/null 2>&1; then ACTUAL="$(sha256sum "${TMP_FILE}" | awk '{print $1}')" elif command -v shasum >/dev/null 2>&1; then ACTUAL="$(shasum -a 256 "${TMP_FILE}" | awk '{print $1}')" else warn "sha256sum/shasum not found — skipping checksum verification." ACTUAL="${EXPECTED}" fi [ "${ACTUAL}" = "${EXPECTED}" ] || die "Checksum mismatch. The download may be corrupt." else warn "Checksum not available — skipping verification." fi # ── Install ─────────────────────────────────────────────────────────────────── chmod +x "${TMP_FILE}" if [ "${NEED_SUDO}" -eq 1 ]; then log "Installing to ${BINARY_PATH} (requires sudo)..." sudo mv "${TMP_FILE}" "${BINARY_PATH}" sudo chown root:root "${BINARY_PATH}" 2>/dev/null || true else log "Installing to ${BINARY_PATH}..." mv "${TMP_FILE}" "${BINARY_PATH}" fi # ── Verify ──────────────────────────────────────────────────────────────────── if ! command -v "${BINARY_NAME}" >/dev/null 2>&1; then warn "${INSTALL_DIR} may not be in your PATH." warn "Add this to your shell profile: export PATH=\"${INSTALL_DIR}:\$PATH\"" fi INSTALLED_VERSION="$("${BINARY_PATH}" version 2>/dev/null || echo "unknown")" printf '\n' printf '%s✓%s Compute Portal CLI installed successfully!\n' "${GREEN}${BOLD}" "${RESET}" printf ' Version : %s\n' "${INSTALLED_VERSION}" printf ' Binary : %s\n' "${BINARY_PATH}" printf '\n' printf 'Get started:\n' printf ' %scpctl login --token %s\n' "${BOLD}" "${RESET}" printf ' %scpctl deploy --image nginx:latest%s\n' "${BOLD}" "${RESET}" printf '\n' printf 'Get your API token at: %shttps://computeportal.io/user/orders%s\n' "${BOLD}" "${RESET}" printf 'Documentation: %shttps://docs.computeportal.io%s\n' "${BOLD}" "${RESET}"