#!/bin/bash # shellcheck disable=SC2312 # # Honeymux install script # # Intended invocation: curl -fsSL https://get.hmx.dev | bash set -u read -r -d '' _MSG_COMMAND_FAILED <<'EOF' Command failed: $1 Check the output above for more details. EOF read -r -d '' _MSG_COMMAND_RETRY_FAILED <<'EOF' Command failed after $1 attempts: $2 Check the output above for more details. EOF read -r -d '' _MSG_INTERACTIVE_MODE_CONFLICT <<'EOF' Both `$INTERACTIVE` and `$NONINTERACTIVE` are set. Please unset at least one variable and try again. EOF read -r -d '' _MSG_FORCE_INTERACTIVE_IN_CI <<'EOF' Cannot run force-interactive mode in CI. Unset `INTERACTIVE` or run this installer from a terminal session instead. EOF read -r -d '' _MSG_POSIX_MODE <<'EOF' Bash must not run in POSIX mode. Please unset POSIXLY_CORRECT and try again. EOF read -r -d '' _MSG_BASE64_DECODE_UNSUPPORTED <<'EOF' Failed to find a supported way to decode embedded installer assets. Install a `base64` implementation that supports either `-d` or `-D`, then try again. EOF read -r -d '' _MSG_LOGO_LOAD_FAILED <<'EOF' Failed to load the embedded Honeymux logo. This installer copy may be corrupted. Re-download it and try again. EOF read -r -d '' _MSG_LOGO_PREPARE_FAILED <<'EOF' Failed to prepare the embedded Honeymux logo for display. This installer copy may be corrupted. Re-download it and try again. EOF read -r -d '' _MSG_INTERACTIVE_TTY_REQUIRED <<'EOF' Interactive mode requires a usable /dev/tty. Re-run from a terminal session, or set `NONINTERACTIVE=1`. EOF read -r -d '' _MSG_NO_SHA256_TOOL <<'EOF' No supported SHA-256 tool was found. Install `sha256sum`, `shasum`, or `openssl` and try again. EOF read -r -d '' _MSG_HOME_NOT_SET <<'EOF' `$HOME` is not set. Set `HMX_INSTALL_DIR` explicitly and try again. EOF read -r -d '' _MSG_ROOT_INSTALL <<'EOF' Do not run this installer as root when using the default install location. Re-run as a normal user, or set `HMX_INSTALL_DIR` explicitly. EOF read -r -d '' _MSG_UNSUPPORTED_OS <<'EOF' Unsupported operating system: $1 Honeymux installer releases currently support macOS and Linux. EOF read -r -d '' _MSG_UNSUPPORTED_ARCH <<'EOF' Unsupported architecture: $1 Honeymux installer releases currently support x64 and arm64. EOF read -r -d '' _MSG_UNSUPPORTED_LIBC <<'EOF' Unsupported Linux libc: musl. Honeymux releases currently target glibc-based Linux. EOF read -r -d '' _MSG_INSTALL_PATH_IS_DIRECTORY <<'EOF' Install target is a directory: $1 Remove it or choose a different `HMX_INSTALL_DIR`, then try again. EOF read -r -d '' _MSG_RELEASE_METADATA_UNAVAILABLE <<'EOF' Failed to resolve release metadata for $1. Check network access to the release host, or set `HMX_VERSION` explicitly and try again. EOF read -r -d '' _MSG_TEMP_DIR_CREATE_FAILED <<'EOF' Failed to create a temporary directory under $1. Check that the directory exists and is writable, then try again. EOF read -r -d '' _MSG_TEMP_DIR_INIT_FAILED <<'EOF' Failed to initialize temporary directory: $1 Check that the directory is writable, then try again. EOF read -r -d '' _MSG_CHECKSUM_ENTRY_MISSING <<'EOF' The SHA256SUMS file did not contain an entry for $1. EOF read -r -d '' _MSG_CHECKSUM_MISMATCH <<'EOF' Checksum verification failed for $1. Expected: $2 Actual: $3 EOF read -r -d '' _MSG_INSTALL_DIR_NOT_WRITABLE <<'EOF' Need permission to write to $1. Choose a writable `HMX_INSTALL_DIR` or re-run where sudo access is available. EOF read -r -d '' _MSG_UNKNOWN_ARGUMENT <<'EOF' Unknown argument: $1 Run `bash install.sh --help` for usage. EOF HMX_MIN_TMUX_VERSION="3.3" BASE64_DECODE_FLAG="" SUMMARY_ERROR="" SUMMARY_WARNING="" TMUX_VERSION_LABEL="not installed" TMUX_VERSION_OK=0 ASSET_SIZE_BYTES="" HMX_COLOR_ENABLED=0 HMX_LOGO_WIDTH=0 HMX_LOGO_LINES=() HMX_LOGO_PLAIN_LINES=() EXISTING_INSTALL_VERSION="" TMP_PARENT_DIR="" TMP_MARKER_FILE="" _word_wrap() { local text="$1" local width="$2" if ! command -v sed >/dev/null 2>&1 || ! command -v awk >/dev/null 2>&1 || ! command -v fold >/dev/null 2>&1; then printf "%s\n" "${text}" return fi printf "%s\n" "${text}" | sed 's/^[[:space:]]*//' | awk ' BEGIN { para="" } /^$/ { if (para != "") { print para; para="" }; print "" } /[^[:space:]]/ { if (para == "") para=$0; else para=para " " $0 } END { if (para != "") print para } ' | fold -s -w "${width}" } current_terminal_width() { local terminal_width terminal_width="$(env TERM="${TERM:-dumb}" tput cols 2>/dev/null || echo "80")" [[ "${terminal_width}" =~ ^[0-9]+$ && "${terminal_width}" -ge 20 ]] || terminal_width=80 printf "%s" "${terminal_width}" } _print() { local tag="$1" local template="$2" local terminal_width local formatted="${template}" local i=1 shift 2 terminal_width="$(current_terminal_width)" while [[ "$#" -gt 0 ]]; do formatted="${formatted//\$${i}/$1}" i=$((i + 1)) shift done { printf "%s\n\n" "${tag}" _word_wrap "${formatted}" "$((terminal_width - 1))" } >&2 } _fatal() { _print "Fatal:" "$@" exit 1 } if [ -z "${BASH_VERSION:-}" ]; then _fatal "Bash is required to interpret this script." fi if [[ -n "${CI-}" && -n "${INTERACTIVE-}" ]]; then _fatal "${_MSG_FORCE_INTERACTIVE_IN_CI}" fi if [[ -n "${INTERACTIVE-}" && -n "${NONINTERACTIVE-}" ]]; then _fatal "${_MSG_INTERACTIVE_MODE_CONFLICT}" fi if [[ -n "${POSIXLY_CORRECT+1}" ]]; then _fatal "${_MSG_POSIX_MODE}" fi if [[ -t 1 ]]; then tty_escape() { printf "\033[%sm" "$1"; } else tty_escape() { :; } fi tty_mkbold() { tty_escape "1;$1"; } tty_blue="$(tty_mkbold 34)" tty_bold="$(tty_mkbold 39)" tty_red="$(tty_mkbold 31)" tty_reset="$(tty_escape 0)" shell_join() { local arg printf "%s" "$1" shift for arg in "$@"; do printf " %s" "${arg// /\\ }" done } chomp() { printf "%s" "${1/"$'\n'"/}" } ohai() { printf "${tty_blue}==>${tty_bold} %s${tty_reset}\n" "$(shell_join "$@")" } warn() { printf "${tty_red}Warning${tty_reset}: %s\n" "$(chomp "$1")" >&2 } append_summary_warning() { if [[ -z "${SUMMARY_WARNING}" ]]; then SUMMARY_WARNING="$1" else SUMMARY_WARNING="${SUMMARY_WARNING}; $1" fi } append_summary_error() { if [[ -z "${SUMMARY_ERROR}" ]]; then SUMMARY_ERROR="$1" else SUMMARY_ERROR="${SUMMARY_ERROR}; $1" fi } normalize_version_for_display() { printf "%s" "${1#v}" } extract_version_from_text() { local text="$1" if [[ "${text}" =~ v?([0-9]+\.[0-9]+\.[0-9]+([-.+][0-9A-Za-z.-]+)*) ]]; then printf "%s" "${BASH_REMATCH[1]}" fi } strip_ansi_stream() { awk '{ gsub(/\033\[[0-9;]*m/, ""); print }' } detect_base64_decode_flag() { if printf 'QQ==' | base64 -d >/dev/null 2>&1; then BASE64_DECODE_FLAG="-d" return fi if printf 'QQ==' | base64 -D >/dev/null 2>&1; then BASE64_DECODE_FLAG="-D" return fi _fatal "${_MSG_BASE64_DECODE_UNSUPPORTED}" } hmx_logo_color_art_gz_base64() { cat <<'EOF' H4sIAFPO4GkAA+1bMY7bMBDs/QU3eUAQyLIkS3ETIMU194PrD0jB7v6PKMUhMGfudry3lGhb7cKk yOXM7uyS3r8cx3N/Pgzp2/6lOTdN2m+WRS2n9N201Lbm+7fsalvQ7VgAvv2UztlvmjYdMlPXp+fM NI6psU1kIE5P1rDRbKPHVZYfl5b2mH5eWoYBUN1MAM6+TU+I6hFNv+xfzXMJDHFP3w2wVNzQ0OS7 Rs+g91Y/zY0kV4K7SX9yLBzTKwbjMHDzWP8bY/2btVLczRf2ly8glHDoPlyEsr+bItwiRMndwWQK AKD1A4CcNjERgAsAgDxDAMDkjV1pnMg8ITPPKzxbu4gOKJq/SUB5NZHBfFCecLv/n8ePKQAnOvzN 9sjykgKgIep306JkAoQqfl2ZxzeKEE7YF47Cry8vT70ZXDxtRPy7Zffhj0ial+EtmIj3eH2q7NgT eMEyz6yEdIUVhRCPfHN/y8c3JS2acYTLh8joqpmyuQjeB4EmbO3jpGRUwgAylzfI+cI5HPmEp4B5 qTsicQ+EuLYYd+msCunlGCWFMSGwEa8Sda51DAmQSUNSpUk+ThOeSBOSnoWy3I0Jm3/HE9IW9ELb wkY00z/G5STsUP/PjFOkYEhCW1LmlWMl0TyILJEoAOVPQVqCJ1gv+Hji8zeO8mWufsxHTT3kZc43 SFSkIMbcNaLOIHNhOnNXTLVZHDShmmfjSZjDtd6SrSgIajVBx3kiUIcwk9VZZtcAazFqUeYxZ75r nvCMtiBNAuVxnjxQ8bBKBNWTKrtoZsinnxGfy64RMNcqWMHdcGY6+eudi6xLK/IfTH8RE6m7XMW7 r+SVCxUN5dlAlGUo3aL2hr+ZOowPEzh7XjXckpCLE68Jv0i0qsAVX7vyg6pe6CzHJRdsmfGmuLtt V64p7msRQyCnTeN1e1ghajLwxrPKCzgBa6TxJLaITaxhL1S+44VOEMnrsde+zjsZx03ckncpRenl uHP80kvPsBtmFl9Jq5G9GlUu/t8tn3Ilqs42r53cnIs8hKLvdL1B3IdxM4gThxeGOHn2KUGcvqvI 9W65CBLIFJ8lpEWiXfSWpVzb9+xX9tMDigDTCdW+/VSCOC4+CuJRyNSSiutVwrobi1I+DH+Ecljg c0hGZrnl4W2+dq4N3lGoVLWXozLzNXCWdCses3jwpqUs3fiDZrv4ehxYu4uva3oSBZ7Y2zQL6pNK FuicKoRBNTRbFqPZBmgDLRrGbuC/J6UI5pKEM6A9VNHopBDMtDw4oOv441bFxFiRYEr0dRLMS4xa JUdtgN6IcUcEU97c33uErs2yEaNCgq2jqjfLBTH+Ano6j4RmSwAA EOF } emit_logo_color_art() { hmx_logo_color_art_gz_base64 | base64 "${BASE64_DECODE_FLAG}" | gzip -dc } logo_supports_color() { local colors local term="${TERM:-}" [[ -t 1 ]] || return 1 [[ -n "${term}" && "${term}" != "dumb" ]] || return 1 if have_cmd tput; then colors="$(tput colors 2>/dev/null || true)" if [[ "${colors}" =~ ^[0-9]+$ && "${colors}" -ge 256 ]]; then return 0 fi fi case "${term}" in *256color* | *direct* | alacritty* | foot* | kitty | wezterm | xterm-kitty) return 0 ;; esac return 1 } load_logo_lines() { local line local logo_text local plain_text HMX_LOGO_LINES=() HMX_LOGO_PLAIN_LINES=() HMX_COLOR_ENABLED=0 HMX_LOGO_WIDTH=0 logo_text="$(emit_logo_color_art)" || _fatal "${_MSG_LOGO_LOAD_FAILED}" plain_text="$(printf '%s' "${logo_text}" | strip_ansi_stream)" || _fatal "${_MSG_LOGO_PREPARE_FAILED}" while IFS= read -r line; do HMX_LOGO_PLAIN_LINES[${#HMX_LOGO_PLAIN_LINES[@]}]="${line}" if [[ "${#line}" -gt "${HMX_LOGO_WIDTH}" ]]; then HMX_LOGO_WIDTH="${#line}" fi done <<< "${plain_text}" if [[ "${#HMX_LOGO_PLAIN_LINES[@]}" -eq 0 ]]; then _fatal "${_MSG_LOGO_PREPARE_FAILED}" fi if logo_supports_color; then HMX_COLOR_ENABLED=1 while IFS= read -r line; do HMX_LOGO_LINES[${#HMX_LOGO_LINES[@]}]="${line}" done <<< "${logo_text}" else HMX_LOGO_LINES=("${HMX_LOGO_PLAIN_LINES[@]}") fi } usage() { cat </dev/null 2>&1 } require_cmd() { have_cmd "$1" || _fatal 'A required command was not found: $1' "$1" } execute() { if ! "$@"; then _fatal "${_MSG_COMMAND_FAILED}" "$(shell_join "$@")" fi } retry() { local tries="$1" local remaining="$1" local pause=2 shift until "$@"; do ((remaining--)) if [[ "${remaining}" -le 0 ]]; then _fatal "${_MSG_COMMAND_RETRY_FAILED}" "${tries}" "$(shell_join "$@")" fi warn "Trying again in ${pause} seconds: $(shell_join "$@")" sleep "${pause}" pause=$((pause * 2)) done } have_sudo_access() { if [[ "${EUID:-${UID}}" == "0" ]]; then return 0 fi if [[ ! -x "/usr/bin/sudo" ]]; then return 1 fi if [[ -n "${NONINTERACTIVE-}" || ! -r "/dev/tty" ]]; then /usr/bin/sudo -n -v && /usr/bin/sudo -n true return $? fi ohai 'Checking for `sudo` access (which may request your password)...' /usr/bin/sudo -v && /usr/bin/sudo true } execute_sudo() { if [[ "${EUID:-${UID}}" == "0" ]]; then ohai "$@" execute "$@" return fi ohai /usr/bin/sudo "$@" execute /usr/bin/sudo "$@" } getc() { local char local target_var="$1" if [[ ! -r "/dev/tty" || ! -w "/dev/tty" ]]; then _fatal "${_MSG_INTERACTIVE_TTY_REQUIRED}" fi char="" if ! IFS='' read -r -s -n 1 char /dev/null )"; then headers="$(printf '%s\n' "${result}" | awk 'index($0, "CURL_EFFECTIVE_URL:") != 1 { print }')" length="$(printf '%s\n' "${headers}" | awk 'tolower($1) == "content-length:" { gsub("\r", "", $2); size=$2 } END { print size }')" if [[ -z "${HMX_VERSION-}" ]]; then resolved_tag="$(printf '%s\n' "${result}" | awk ' tolower($1) == "location:" || index($0, "CURL_EFFECTIVE_URL:") == 1 { gsub("\r", "") marker = "/download/v" start = index($0, marker) if (start > 0) { suffix = substr($0, start + length(marker)) slash = index(suffix, "/") if (slash > 1) { tag = "v" substr(suffix, 1, slash - 1) } } } END { print tag } ')" if [[ -n "${resolved_tag}" ]]; then VERSION_LABEL="$(normalize_version_for_display "${resolved_tag}")" fi fi if [[ "${length}" =~ ^[0-9]+$ ]]; then ASSET_SIZE_BYTES="${length}" fi if [[ -n "${ASSET_SIZE_BYTES}" && "${VERSION_LABEL}" != "latest" ]]; then return fi fi attempt=$((attempt + 1)) done if [[ -z "${HMX_VERSION-}" && "${VERSION_LABEL}" == "latest" ]]; then _fatal "${_MSG_RELEASE_METADATA_UNAVAILABLE}" "${ASSET_URL}" fi } detect_existing_install_version() { local version_output="" EXISTING_INSTALL_VERSION="" if [[ ! -x "${INSTALL_PATH}" ]]; then return fi version_output="$("${INSTALL_PATH}" -V 2>/dev/null || true)" EXISTING_INSTALL_VERSION="$(extract_version_from_text "${version_output}")" } check_existing_install() { if [[ -d "${INSTALL_PATH}" ]]; then _fatal "${_MSG_INSTALL_PATH_IS_DIRECTORY}" "${INSTALL_PATH}" fi if [[ -e "${INSTALL_PATH}" ]]; then detect_existing_install_version if [[ -n "${EXISTING_INSTALL_VERSION}" ]]; then append_summary_warning "Existing installation (${EXISTING_INSTALL_VERSION}) will be replaced" else append_summary_warning "Existing installation will be replaced" fi fi } asset_summary_content() { if [[ -n "${ASSET_SIZE_BYTES}" ]]; then printf "%s (%s; %s bytes)" "${ASSET}" "${VERSION_LABEL}" "${ASSET_SIZE_BYTES}" else printf "%s (%s; size unavailable)" "${ASSET}" "${VERSION_LABEL}" fi } banner_wrapped_line() { local width="$1" local target_line="$2" local text="$3" local current_line=1 local line while IFS= read -r line; do if [[ "${current_line}" -eq "${target_line}" ]]; then printf "%s" "${line}" return fi current_line=$((current_line + 1)) done <<< "$(_word_wrap "${text}" "${width}")" } banner_status_label() { if [[ -n "${SUMMARY_ERROR}" ]]; then if [[ "${HMX_COLOR_ENABLED}" -eq 1 ]]; then printf "%sError%s:" "${tty_red}" "${tty_reset}" else printf "Error:" fi elif [[ -n "${SUMMARY_WARNING}" ]]; then if [[ "${HMX_COLOR_ENABLED}" -eq 1 ]]; then printf "%sWarning%s:" "${tty_red}" "${tty_reset}" else printf "Warning:" fi fi } banner_status_content() { if [[ -n "${SUMMARY_ERROR}" ]]; then printf "%s" "${SUMMARY_ERROR}" elif [[ -n "${SUMMARY_WARNING}" ]]; then printf "%s" "${SUMMARY_WARNING}" fi } banner_note_for_line() { local line_index="$1" local note_width="$2" case "${line_index}" in 3) printf "Honeymux installer" ;; 5) printf "Operating system: %s" "${OS_NAME}" ;; 6) printf "Architecture: %s" "${ARCH}" ;; 7) printf "Home folder: %s" "${HOME_DIR_LABEL}" ;; 9) printf "tmux version: %s" "${TMUX_VERSION_LABEL}" ;; 11) printf "This script will install:" ;; 12) printf "%s" "${INSTALL_PATH}" ;; 14) printf "Asset:" ;; 15) banner_wrapped_line "${note_width}" 1 "$(asset_summary_content)" ;; 16) banner_wrapped_line "${note_width}" 2 "$(asset_summary_content)" ;; 18) banner_status_label ;; 19) banner_wrapped_line "${note_width}" 1 "$(banner_status_content)" ;; 20) banner_wrapped_line "${note_width}" 2 "$(banner_status_content)" ;; esac } print_install_banner() { local index=0 local line local note local plain_line local padding local note_width local terminal_width load_logo_lines terminal_width="$(current_terminal_width)" note_width=$((terminal_width - HMX_LOGO_WIDTH - 4)) if [[ "${note_width}" -lt 20 ]]; then note_width=20 fi echo while [[ "${index}" -lt "${#HMX_LOGO_LINES[@]}" ]]; do line="${HMX_LOGO_LINES[${index}]}" plain_line="${HMX_LOGO_PLAIN_LINES[${index}]}" note="$(banner_note_for_line "${index}" "${note_width}")" printf "%s" "${line}" if [[ -n "${note}" ]]; then padding=$((HMX_LOGO_WIDTH - ${#plain_line} + 4)) printf "%*s%s" "${padding}" "" "${note}" fi printf "\n" index=$((index + 1)) done } ensure_tmux_ready() { if [[ "${TMUX_VERSION_OK}" -eq 1 ]]; then return fi echo printf "Please install or upgrade tmux before installing Honeymux\n" exit 1 } setup_temp_dir() { local old_umask TMP_PARENT_DIR="${TMPDIR:-/tmp}" if [[ "${TMP_PARENT_DIR}" != "/" ]]; then TMP_PARENT_DIR="${TMP_PARENT_DIR%/}" fi old_umask="$(umask)" umask 077 TMP_DIR="$(mktemp -d "${TMP_PARENT_DIR}/hmx-install.XXXXXX")" umask "${old_umask}" [[ -n "${TMP_DIR}" ]] || _fatal "${_MSG_TEMP_DIR_CREATE_FAILED}" "${TMP_PARENT_DIR}" chmod 700 "${TMP_DIR}" 2>/dev/null || true TMP_MARKER_FILE="${TMP_DIR}/.honeymux-install-tempdir" : > "${TMP_MARKER_FILE}" || _fatal "${_MSG_TEMP_DIR_INIT_FAILED}" "${TMP_DIR}" trap cleanup EXIT } cleanup() { [[ -n "${TMP_DIR-}" ]] || return [[ -n "${TMP_PARENT_DIR-}" ]] || return [[ -n "${TMP_MARKER_FILE-}" && -f "${TMP_MARKER_FILE}" ]] || return [[ "${TMP_DIR}" == "${TMP_PARENT_DIR}/hmx-install."* ]] || return [[ -d "${TMP_DIR}" ]] || return rm -rf "${TMP_DIR}" } download_file() { local url="$1" local destination="$2" retry 3 curl \ --connect-timeout 15 \ --fail \ --location \ --output "${destination}" \ --silent \ --show-error \ "${url}" } download_release() { BINARY_PATH="${TMP_DIR}/${ASSET}" CHECKSUMS_PATH="${TMP_DIR}/SHA256SUMS" ohai "Downloading ${ASSET}" download_file "${ASSET_URL}" "${BINARY_PATH}" ohai "Downloading SHA256SUMS" download_file "${CHECKSUM_URL}" "${CHECKSUMS_PATH}" } verify_checksum() { local checksum_line local expected local actual checksum_line="$(awk -v file="${ASSET}" '$2 == file { print; exit }' "${CHECKSUMS_PATH}")" [[ -n "${checksum_line}" ]] || _fatal "${_MSG_CHECKSUM_ENTRY_MISSING}" "${ASSET}" ohai "Verifying checksum" if have_cmd sha256sum; then actual="$(sha256sum "${BINARY_PATH}" | awk '{ print $1 }')" elif have_cmd shasum; then actual="$(shasum -a 256 "${BINARY_PATH}" | awk '{ print $1 }')" else actual="$(openssl dgst -sha256 "${BINARY_PATH}" | awk '{ print $NF }')" fi expected="${checksum_line%% *}" [[ "${actual}" == "${expected}" ]] || _fatal "${_MSG_CHECKSUM_MISMATCH}" "${ASSET}" "${expected}" "${actual}" } install_binary() { if mkdir -p "${INSTALL_DIR}" 2>/dev/null && install -m 0755 "${BINARY_PATH}" "${INSTALL_PATH}" 2>/dev/null; then return fi if ! have_sudo_access; then _fatal "${_MSG_INSTALL_DIR_NOT_WRITABLE}" "${INSTALL_DIR}" fi execute_sudo mkdir -p "${INSTALL_DIR}" execute_sudo install -m 0755 "${BINARY_PATH}" "${INSTALL_PATH}" } path_contains_install_dir() { case ":${PATH:-}:" in *":${INSTALL_DIR}:"*) return 0 ;; *) return 1 ;; esac } print_success() { local resolved_hmx ohai "Installation successful!" echo printf "%sHoneymux installed successfully.%s\n" "${tty_bold}" "${tty_reset}" printf "Installed to: %s\n" "${INSTALL_PATH}" if ! path_contains_install_dir; then warn "${INSTALL_DIR} is not in your PATH." echo echo "Next steps:" printf " export PATH=\"%s:\$PATH\"\n" "${INSTALL_DIR}" fi resolved_hmx="$(type -P hmx || true)" if [[ -n "${resolved_hmx}" && "${resolved_hmx}" != "${INSTALL_PATH}" ]]; then warn "hmx currently resolves to ${resolved_hmx}. Ensure ${INSTALL_DIR} comes first in PATH if you want to use the new install." fi echo printf "Run '%s' to get started.\n" "${INSTALL_PATH}" } main() { while [[ $# -gt 0 ]]; do case "$1" in --help | -h) usage exit 0 ;; *) _fatal "${_MSG_UNKNOWN_ARGUMENT}" "$1" ;; esac done check_not_root check_prerequisites detect_base64_decode_flag setup_variables SUMMARY_ERROR="" SUMMARY_WARNING="" detect_platform check_platform_support check_existing_install detect_tmux resolve_release_urls ohai "Resolving release metadata" fetch_release_metadata print_install_banner ensure_tmux_ready if should_prompt; then wait_for_user fi setup_temp_dir download_release verify_checksum install_binary print_success } main "$@"