#!/usr/bin/env sh # MACHHUB one-liner installer # Usage: # curl -sSf https://install.machhub.dev | sh # curl -sSf https://install.machhub.dev | sh -s -- -v v1.0.0 # curl -sSf https://install.machhub.dev | sh -s -- --defaults # curl -sSf https://install.machhub.dev | sh -s -- --historian timescaledb set -e VERSION="latest" REPO="machhub-dev/releases" UPDATE_COMPONENT="" echo "" echo "oooo oooo o oooooooo8 ooooo ooooo ooooo ooooo ooooo oooo oooooooooo " echo " 8888o 888 888 o888 88 888 888 888 888 888 88 888 888 " echo " 88 888o8 88 8 88 888 888ooo888 888ooo888 888 88 888oooo88 " echo " 88 888 88 8oooo88 888o oo 888 888 888 888 888 88 888 888 " echo "o88o 8 o88o o88o o888o 888oooo88 o888o o888o o888o o888o 888oo88 o888ooo888 " echo "" # Allow flags when called as: sh -s -- -v v1.0.0 -u machhub # -v|--version : install a specific version (default: latest) # -u|--update : non-interactive update target: all | machhub | surreal | nodered # # Anything else is passed through to the release's own install.sh, which is what # owns the install options (--defaults, --historian, --surreal-version, # --db-password, ...). Passing them through rather than duplicating them here # means this bootstrap does not need updating whenever one is added — run # `./install.sh --help` from an unpacked release for the current list. # # The rotation below is how a POSIX shell keeps unrecognised arguments as # separate words: each one is pushed back onto the end of "$@" while the # original count is walked down, so a value containing spaces survives intact. remaining=$# while [ "$remaining" -gt 0 ]; do arg="$1"; shift; remaining=$((remaining - 1)) case $arg in -v|--version) VERSION="$1"; shift; remaining=$((remaining - 1)) ;; -u|--update) UPDATE_COMPONENT="$1"; shift; remaining=$((remaining - 1)) ;; *) set -- "$@" "$arg" ;; esac done # Detect architecture ARCH=$(uname -m) case $ARCH in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; *) echo "Unsupported architecture: $ARCH" exit 1 ;; esac # Resolve 'latest' to a real tag if [ "$VERSION" = "latest" ]; then VERSION=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \ | grep '"tag_name"' | cut -d '"' -f4) fi if [ -z "$VERSION" ]; then echo "Error: could not determine latest release version." exit 1 fi FILE="machhub-linux-${ARCH}-${VERSION}.tar.gz" URL="https://github.com/${REPO}/releases/download/${VERSION}/${FILE}" echo "Downloading MACHHUB ${VERSION} for linux/${ARCH}..." echo " -> ${URL}" # Create temp dir TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT echo "Using temporary directory: ${TMP}" curl -fSL --progress-bar "$URL" -o "${TMP}/machhub.tar.gz" echo "Extracting..." tar -xzf "${TMP}/machhub.tar.gz" -C "$TMP" cd "${TMP}/build" # If machhub is already installed, prompt what to update; otherwise run the installer if command -v machhub > /dev/null 2>&1; then INSTALLED_VERSION=$(cat /etc/machhub/VERSION 2>/dev/null || echo "unknown") echo "MACHHUB is already installed (current version: ${INSTALLED_VERSION})." echo "" if [ -n "$UPDATE_COMPONENT" ]; then # Non-interactive mode: component supplied via --update flag case $UPDATE_COMPONENT in all) UPDATE_FLAG="-a" ;; machhub) UPDATE_FLAG="-m" ;; surreal) UPDATE_FLAG="-s" ;; nodered) UPDATE_FLAG="-n" ;; *) echo "Invalid --update component '${UPDATE_COMPONENT}'. Valid values: all, machhub, surreal, nodered" exit 1 ;; esac echo "Non-interactive update: updating '${UPDATE_COMPONENT}'..." else echo "Select what you want to update:" echo " 1) All (MACHHUB, SurrealDB, Node-RED)" echo " 2) MACHHUB only" echo " 3) SurrealDB only" echo " 4) Node-RED only" echo "" printf "Enter your choice [1-4]: " read UPDATE_CHOICE < /dev/tty case $UPDATE_CHOICE in 1) UPDATE_FLAG="-a" ;; 2) UPDATE_FLAG="-m" ;; 3) UPDATE_FLAG="-s" ;; 4) UPDATE_FLAG="-n" ;; *) echo "Invalid choice. Aborting." exit 1 ;; esac fi chmod +x ./update.sh ./update.sh $UPDATE_FLAG -y else echo "Running installer..." chmod +x ./install.sh ./install.sh "$@" fi