#!/usr/bin/env bash # Gizmo installer — served by the activation server at https://gizmo.e404.eu/ # # curl -sSL https://gizmo.e404.eu | bash # # Installs the Gizmo CLI as an isolated pipx app, then prints next steps. The # wheel is pure-Python, so the same artifact serves every OS/arch; we still # detect the platform for clear messaging and to pick the install location. set -euo pipefail BASE_URL="https://gizmo.e404.eu" PACKAGE="gizmo" WHEEL_URL="${BASE_URL}/releases/latest" say() { printf '\033[1;36m%s\033[0m\n' "$*"; } warn() { printf '\033[1;33m%s\033[0m\n' "$*" >&2; } die() { printf '\033[1;31m%s\033[0m\n' "$*" >&2; exit 1; } # --- detect platform (informational) -------------------------------------- OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in Linux) PLATFORM="Linux" ;; Darwin) PLATFORM="macOS" ;; *) die "Unsupported OS: $OS (need Linux or macOS)" ;; esac case "$ARCH" in x86_64|amd64) ARCHLABEL="x86_64" ;; arm64|aarch64) ARCHLABEL="ARM64" ;; *) warn "Unrecognized arch '$ARCH' — continuing (wheel is arch-independent)."; ARCHLABEL="$ARCH" ;; esac say "Installing Gizmo for ${PLATFORM} ${ARCHLABEL}…" # --- ensure python3 ------------------------------------------------------- PYTHON="$(command -v python3 || true)" [ -n "$PYTHON" ] || die "python3 not found. Install Python 3.10+ and re-run." # --- ensure pipx ---------------------------------------------------------- PIPX="" if command -v pipx >/dev/null 2>&1; then PIPX="pipx" elif "$PYTHON" -m pipx --version >/dev/null 2>&1; then PIPX="$PYTHON -m pipx" fi if [ -z "$PIPX" ]; then say "pipx not found — trying to bootstrap it…" # Some distros (Debian/Ubuntu, incl. WSL) ship python3 without pip; try to # bootstrap pip via ensurepip first. (On Debian this is often disabled, in # which case pipx must come from the system package manager — handled below.) if ! "$PYTHON" -m pip --version >/dev/null 2>&1; then "$PYTHON" -m ensurepip --upgrade >/dev/null 2>&1 || true fi if "$PYTHON" -m pip --version >/dev/null 2>&1; then # pip available — install pipx into the user site (--break-system-packages # covers PEP 668 "externally-managed-environment" distros). "$PYTHON" -m pip install --user --quiet pipx 2>/dev/null \ || "$PYTHON" -m pip install --user --quiet --break-system-packages pipx 2>/dev/null \ || true "$PYTHON" -m pipx ensurepath >/dev/null 2>&1 || true export PATH="$("$PYTHON" -m site --user-base)/bin:$PATH" if command -v pipx >/dev/null 2>&1; then PIPX="pipx" elif "$PYTHON" -m pipx --version >/dev/null 2>&1; then PIPX="$PYTHON -m pipx" fi fi fi if [ -z "$PIPX" ]; then # Couldn't bootstrap without sudo — point the user at the one-liner for their # package manager (the apt/dnf pipx package also pulls in python3-venv, which # pipx needs to build the Gizmo venv). warn "" warn "Couldn't install pipx automatically. Install it with your package manager, then re-run:" if command -v apt-get >/dev/null 2>&1; then warn " sudo apt update && sudo apt install -y pipx" elif command -v dnf >/dev/null 2>&1; then warn " sudo dnf install -y pipx" elif command -v pacman >/dev/null 2>&1; then warn " sudo pacman -S --noconfirm python-pipx" elif command -v zypper >/dev/null 2>&1; then warn " sudo zypper install -y python3-pipx" elif command -v brew >/dev/null 2>&1; then warn " brew install pipx" else warn " (install the 'pipx' package via your OS package manager)" fi warn " curl -sSL ${BASE_URL} | bash" die "pipx is required." fi # --- download then install the wheel ------------------------------------- # We download to a temp file rather than `pipx install " @ "`: pip # names a direct-URL download from the URL basename, so a `/releases/latest` # URL is saved as "latest" and rejected as "not a Python project". Fetching the # file ourselves lets pip see a real `*.whl` name and recognize the wheel. say "Fetching the Gizmo wheel from ${WHEEL_URL}…" DL_DIR="$(mktemp -d)" trap 'rm -rf "$DL_DIR"' EXIT # /releases/latest 302-redirects to /releases/.whl. Resolve that real URL # first so curl -O names the saved file from a basename ending in .whl (curl -O # otherwise uses the command-line URL basename, "latest", which pip rejects). REAL_URL="$(curl -fsS -o /dev/null -w '%{redirect_url}' "$WHEEL_URL")" [ -n "$REAL_URL" ] || REAL_URL="$WHEEL_URL" ( cd "$DL_DIR" && curl -fSL -O "$REAL_URL" ) || die "Failed to download the wheel." WHEEL_FILE="$(ls "$DL_DIR"/*.whl 2>/dev/null | head -1)" [ -n "$WHEEL_FILE" ] || die "Downloaded file is not a .whl — check ${WHEEL_URL}." say "Installing ${WHEEL_FILE##*/}…" $PIPX install --force "$WHEEL_FILE" # Make sure pipx's bin dir is on PATH (idempotent; no-op if already added). $PIPX ensurepath >/dev/null 2>&1 || true echo say "Gizmo installed." echo "Next steps:" echo " 1. Ensure the 'gizmo' command is on your PATH — run this once, then open a new terminal:" echo echo " pipx ensurepath" echo echo " 2. Run: gizmo" echo " On first run you'll be guided through a one-time browser activation."