#!/usr/bin/env bash set -euo pipefail repository_root=$(cd "$(dirname "$0")/.." && pwd) install_directory="${THT_INSTALL_DIRECTORY:-/usr/local/bin}" staging_root=$(mktemp -d) trap 'rm -rf "$staging_root"' EXIT HUP INT TERM fail() { echo "install-tht.sh: $*" >&2 exit 1 } 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 fail "SHA-256 verification requires sha256sum or shasum" fi } platform_artifact_name() { local system architecture system=$(uname -s) architecture=$(uname -m) case "$system" in Darwin) system=darwin ;; Linux) system=linux ;; *) fail "unsupported operating system: $system (supported: macOS and Linux)" ;; esac case "$architecture" in x86_64|amd64) architecture=amd64 ;; arm64|aarch64) architecture=arm64 ;; *) fail "unsupported processor architecture: $architecture (supported: amd64 and arm64)" ;; esac printf 'tht-%s-%s\n' "$system" "$architecture" } validate_packaged_artifact() { local artifact=$1 expected actual expected=${THT_BUILD_ARTIFACT_SHA256:-} [[ "$expected" =~ ^[[:xdigit:]]{64}$ ]] || fail "THT_BUILD_ARTIFACT_SHA256 must be a 64-character SHA-256 digest" actual=$(sha256 "$artifact") actual=$(printf '%s' "$actual" | tr '[:upper:]' '[:lower:]') expected=$(printf '%s' "$expected" | tr '[:upper:]' '[:lower:]') [[ "$actual" == "$expected" ]] || fail "packaged tht artifact checksum does not match" } build_artifact() { local build_output="$staging_root/build" mkdir -p "$build_output" THT_THT_OUTPUT_DIRECTORY="$build_output" bash "$repository_root/scripts/build-tht.sh" --all >&2 printf '%s/%s\n' "$build_output" "$(platform_artifact_name)" } install_atomically() { local destination_directory=$1 source_file=$2 local temporary_destination if mkdir -p "$destination_directory" 2>/dev/null && [[ -w "$destination_directory" ]]; then temporary_destination=$(mktemp "$destination_directory/.tht.XXXXXX") cp "$source_file" "$temporary_destination" chmod 0755 "$temporary_destination" mv -f "$temporary_destination" "$destination_directory/tht" return fi command -v sudo >/dev/null 2>&1 || fail "cannot write to $destination_directory and sudo is unavailable" sudo sh -c ' set -eu destination_directory=$1 source_file=$2 mkdir -p "$destination_directory" temporary_destination=$(mktemp "$destination_directory/.tht.XXXXXX") trap "rm -f \"$temporary_destination\"" EXIT HUP INT TERM cp "$source_file" "$temporary_destination" chmod 0755 "$temporary_destination" mv -f "$temporary_destination" "$destination_directory/tht" ' sh "$destination_directory" "$source_file" } [[ "$install_directory" == /* ]] || fail "THT_INSTALL_DIRECTORY must be an absolute path" artifact_name=$(platform_artifact_name) if [[ -n "${THT_BUILD_ARTIFACT:-}" ]]; then source_artifact=$THT_BUILD_ARTIFACT [[ -f "$source_artifact" ]] || fail "THT_BUILD_ARTIFACT is not a regular file" validate_packaged_artifact "$source_artifact" else source_artifact=$(build_artifact) fi [[ -s "$source_artifact" ]] || fail "native artifact is missing: $artifact_name" staged_binary="$staging_root/tht" cp "$source_artifact" "$staged_binary" chmod 0755 "$staged_binary" "$staged_binary" --help >/dev/null || fail "native artifact did not pass its help check" install_atomically "$install_directory" "$staged_binary" resolved_command=$(command -v tht || true) [[ "$resolved_command" == "$install_directory/tht" ]] || fail "installed tht is not resolvable at $install_directory/tht; add $install_directory to PATH and open a new terminal" "$install_directory/tht" --help >/dev/null || fail "installed tht did not pass its help check" printf 'Installed tht at %s/tht\n' "$install_directory"