#!/usr/bin/env bash set -euo pipefail APP_NAME="expose" BASE_URL="https://install.expose.gam-s.fr" log() { printf "%s\n" "$*"; } err() { printf "❌ Error: %s\n" "$*" >&2; } # 🖥️ Detect OS and architecture log "🖥️ Detecting OS and architecture..." os="$(uname -s)" arch="$(uname -m)" case "$os" in Linux) os_id="linux" ;; Darwin) os_id="mac" ;; *) err "Unsupported OS: $os"; exit 1 ;; esac case "$arch" in x86_64|amd64) arch_id="x64" ;; arm64|aarch64) arch_id="arm64" ;; *) err "Unsupported architecture: $arch"; exit 1 ;; esac asset="${APP_NAME}-${os_id}-${arch_id}" bin_url="${BASE_URL}/${asset}" sha_url="${BASE_URL}/${asset}.sha256" # 📂 Choose destination choose_dest() { for d in /usr/local/bin /usr/bin; do if [ -d "$d" ]; then echo "$d" return 0 fi done echo "${HOME}/.local/bin" } dest_dir="$(choose_dest)" dest="${dest_dir}/${APP_NAME}" # 🔧 Allow --dest override while [ "${1-}" != "" ]; do case "$1" in --dest) shift dest_dir="$1" dest="${dest_dir}/${APP_NAME}" ;; *) err "Unknown option: $1" exit 1 ;; esac shift || true done # 🔐 Check write perms need_sudo="0" if [ ! -d "$dest_dir" ]; then if mkdir -p "$dest_dir" 2>/dev/null; then :; else need_sudo="1"; fi elif [ ! -w "$dest_dir" ]; then need_sudo="1" fi # Resolve sudo command without printing anything sudo_cmd="" if [ "$need_sudo" = "1" ]; then if command -v sudo >/dev/null 2>&1; then sudo_cmd="sudo" else err "No write access to ${dest_dir} and sudo not found. Re-run with --dest \"${HOME}/.local/bin\"." exit 1 fi fi # 📥 Download binary + checksum tmp_bin="$(mktemp)" tmp_sha="$(mktemp)" cleanup() { rm -f "$tmp_bin" "$tmp_sha"; } trap cleanup EXIT log "📥 Downloading binary: ${bin_url}" curl -fSL --progress-bar "$bin_url" -o "$tmp_bin" log "📥 Downloading checksum: ${sha_url}" curl -fSL --progress-bar "$sha_url" -o "$tmp_sha" # 🔍 Verify checksum calc_sha256() { if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}' elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}' else err "No sha256 tool found (need sha256sum or shasum)." exit 1 fi } expected_hash="$(tr -d '\n\r\t ' < "$tmp_sha")" actual_hash="$(calc_sha256 "$tmp_bin")" if [ -z "$expected_hash" ] || [ ${#expected_hash} -ne 64 ]; then err "Invalid checksum file format at ${sha_url} (expected a 64-char hex string)." exit 1 fi if [ "$expected_hash" != "$actual_hash" ]; then err "Checksum mismatch for ${asset}. Expected: ${expected_hash} Actual: ${actual_hash}" exit 1 fi log "✅ Checksum verification passed." # 📦 Install log "📦 Installing to: ${dest}" if [ "$need_sudo" = "1" ]; then log "🔑 This action requires administrator rights. You may be asked for your sudo password..." $sudo_cmd mkdir -p "$dest_dir" $sudo_cmd install -m 0755 "$tmp_bin" "$dest" else mkdir -p "$dest_dir" install -m 0755 "$tmp_bin" "$dest" fi # 🔎 PATH check in_path="0" IFS=":" read -r -a path_entries <<< "${PATH}" for p in "${path_entries[@]}"; do if [ "$p" = "$dest_dir" ]; then in_path="1" break fi done log "" log "🎉 Installation complete: ${dest}" if [ "$in_path" = "0" ]; then log "" log "⚠️ ${dest_dir} is not in your PATH." if [ -n "${ZSH_VERSION-}" ] || [ -n "${BASH_VERSION-}" ]; then rc="${HOME}/.bashrc" [ -n "${ZSH_VERSION-}" ] && rc="${HOME}/.zshrc" log " Add this line to your shell config:" log " export PATH=\"${dest_dir}:\$PATH\"" log " echo 'export PATH=\"${dest_dir}:\$PATH\"' >> ${rc}" log " Then open a new terminal." else log " export PATH=\"${dest_dir}:\$PATH\"" fi log "" log "Skipping example run because ${dest_dir} is not in PATH." exit 0 fi # 💡 Show example usage instead of executing log "" log "💡 Try it now:" log " ${APP_NAME} 3000 as myapi"