#!/usr/bin/env bash # Install Node.js 20 user-local binary (no nvm/git) for mysql-mcp-server set -euo pipefail NODE_VERSION="v20.19.2" INSTALL_DIR="${HOME}/.local/node-${NODE_VERSION}" BIN_DIR="${INSTALL_DIR}/bin" if [ -x "${BIN_DIR}/node" ]; then echo "Already installed: $("${BIN_DIR}/node" --version)" exit 0 fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" install_from_tarball() { local tar_path="$1" local tmp tmp="$(mktemp -d)" trap 'rm -rf "${tmp}"' EXIT echo "Installing from cache: ${tar_path}" tar -xJf "${tar_path}" -C "${tmp}" rm -rf "${INSTALL_DIR}" mv "${tmp}/node-${NODE_VERSION}-linux-${NODE_ARCH}" "${INSTALL_DIR}" echo "Installed: $("${BIN_DIR}/node" --version) at ${BIN_DIR}/node" exit 0 } clear_bad_proxy() { local v for v in http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY no_proxy NO_PROXY; do if [ -n "${!v:-}" ]; then case "${!v}" in *export*|*EXPORT*) unset "$v" ;; esac fi done unset http_proxy https_proxy HTTP_PROXY HTTPS_PROXY all_proxy ALL_PROXY no_proxy NO_PROXY 2>/dev/null || true } download_node_tarball() { local dest="$1" local tarball="$2" local official="https://nodejs.org/dist/${NODE_VERSION}/${tarball}" local mirror="https://npmmirror.com/mirrors/node/${NODE_VERSION}/${tarball}" clear_bad_proxy echo "Trying official: ${official}" if curl --noproxy '*' -fsSL --connect-timeout 30 --max-time 600 "${official}" -o "${dest}"; then return 0 fi echo "Official failed, trying mirror: ${mirror}" if curl --noproxy '*' -fsSL --connect-timeout 30 --max-time 600 "${mirror}" -o "${dest}"; then return 0 fi return 1 } print_manual_steps() { local tarball="$1" cat </dev/null | grep -i proxy || echo " (no proxy vars)") Manual install: 1. Download: https://nodejs.org/dist/${NODE_VERSION}/${tarball} or https://npmmirror.com/mirrors/node/${NODE_VERSION}/${tarball} 2. Place tarball in .cache/ then: bash scripts/install_node20.sh 3. Verify: ~/.local/node-${NODE_VERSION}/bin/node --version EOF } mkdir -p "${HOME}/.local" TMP="$(mktemp -d)" trap 'rm -rf "${TMP}"' EXIT ARCH="$(uname -m)" case "${ARCH}" in x86_64) NODE_ARCH="x64" ;; aarch64) NODE_ARCH="arm64" ;; *) echo "Unsupported arch: ${ARCH}" >&2; exit 1 ;; esac TARBALL="node-${NODE_VERSION}-linux-${NODE_ARCH}.tar.xz" CACHED_TAR="${SCRIPT_DIR}/../.cache/${TARBALL}" if [ -f "${CACHED_TAR}" ]; then install_from_tarball "${CACHED_TAR}" fi if ! download_node_tarball "${TMP}/${TARBALL}" "${TARBALL}"; then print_manual_steps "${TARBALL}" exit 1 fi tar -xJf "${TMP}/${TARBALL}" -C "${TMP}" rm -rf "${INSTALL_DIR}" mv "${TMP}/node-${NODE_VERSION}-linux-${NODE_ARCH}" "${INSTALL_DIR}" echo "Installed: $("${BIN_DIR}/node" --version) at ${BIN_DIR}/node" echo "Add to PATH (optional): export PATH=\"${BIN_DIR}:\$PATH\""