|
1 | | -#!/bin/zsh |
| 1 | +#!/bin/sh |
2 | 2 |
|
3 | | -# supported CPU architectures and operating systems |
4 | | -SUPPORTED_ARCH=("x86_64" "arm64") |
5 | | -SUPPORTED_OS=("linux" "darwin") |
6 | 3 | DOWNLOAD_BASE_URL="https://github.com/parseablehq/parseable/releases/download" |
7 | | -ARM_APPLE_PREFIX="Parseable_OSS_aarch64-apple-darwin" |
8 | | -ARM_LINUX_PREFIX="Parseable_OSS_aarch64-unknown-linux-gnu" |
9 | | -INTEL_LINUX_PREFIX="Parseable_OSS_x86_64-unknown-linux-gnu" |
10 | | -PARSEABLE_PREFIX=${ARM_APPLE_PREFIX} |
| 4 | +INSTALL_DIR="${HOME}/.parseable" |
| 5 | +BIN_DIR="${INSTALL_DIR}/bin" |
| 6 | +BIN_NAME="${BIN_DIR}/parseable" |
11 | 7 |
|
12 | | -# Get the system's CPU architecture and operating system |
| 8 | +# Get the system's CPU architecture and operating system. |
13 | 9 | CPU_ARCH=$(uname -m) |
14 | 10 | OS=$(uname -s | tr '[:upper:]' '[:lower:]') |
15 | 11 |
|
16 | | -printf "\n=========================\n" |
17 | | -printf "Detected CPU architecture: %s\n" "$CPU_ARCH" |
18 | | -printf "Detected operating system: %s\n" "$OS" |
| 12 | +printf '\n=========================\n' |
| 13 | +printf 'Detected CPU architecture: %s\n' "$CPU_ARCH" |
| 14 | +printf 'Detected operating system: %s\n' "$OS" |
19 | 15 |
|
20 | | -SHELL_NAME=$(basename $SHELL) |
21 | | -RC_FILE=".${SHELL_NAME}rc" |
22 | | -RC_FILE_PATH="${HOME}/${RC_FILE}" |
23 | | -INSTALL_DIR="${HOME}/.parseable" |
24 | | -BIN_DIR="${INSTALL_DIR}/bin" |
25 | | -BIN_NAME="${BIN_DIR}/parseable" |
| 16 | +# Select one downloader and use it for both the release lookup and the binary. |
| 17 | +if command -v curl >/dev/null 2>&1; then |
| 18 | + DOWNLOADER="curl" |
| 19 | +elif command -v wget >/dev/null 2>&1; then |
| 20 | + DOWNLOADER="wget" |
| 21 | +else |
| 22 | + printf 'Error: Neither curl nor wget was found. Please install either curl or wget.\n' >&2 |
| 23 | + exit 1 |
| 24 | +fi |
| 25 | + |
| 26 | +# Match the platform names used by the release assets. Linux commonly reports |
| 27 | +# ARM64 as "aarch64", while macOS reports it as "arm64". |
| 28 | +case "${OS}_${CPU_ARCH}" in |
| 29 | + darwin_arm64) |
| 30 | + PARSEABLE_PREFIX="Parseable_OSS_aarch64-apple-darwin" |
| 31 | + ;; |
| 32 | + linux_arm64|linux_aarch64) |
| 33 | + PARSEABLE_PREFIX="Parseable_OSS_aarch64-unknown-linux-gnu" |
| 34 | + ;; |
| 35 | + linux_x86_64|linux_amd64) |
| 36 | + PARSEABLE_PREFIX="Parseable_OSS_x86_64-unknown-linux-gnu" |
| 37 | + ;; |
| 38 | + *) |
| 39 | + printf 'Error: unsupported platform %s/%s.\n' "$OS" "$CPU_ARCH" >&2 |
| 40 | + exit 1 |
| 41 | + ;; |
| 42 | +esac |
| 43 | + |
| 44 | +# Parseable's Linux release binaries require glibc. |
| 45 | +if [ "$OS" = "linux" ]; then |
| 46 | + MUSL_FOUND="false" |
| 47 | + if command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then |
| 48 | + MUSL_FOUND="true" |
| 49 | + else |
| 50 | + for MUSL_LOADER in /lib/ld-musl-*.so.1; do |
| 51 | + if [ -e "$MUSL_LOADER" ]; then |
| 52 | + MUSL_FOUND="true" |
| 53 | + break |
| 54 | + fi |
| 55 | + done |
| 56 | + fi |
| 57 | + if [ "$MUSL_FOUND" = "true" ]; then |
| 58 | + printf 'Error: Alpine Linux and other musl-based systems are not supported by the available release binaries.\n' >&2 |
| 59 | + exit 1 |
| 60 | + fi |
| 61 | +fi |
26 | 62 |
|
27 | | -# Check if the CPU architecture is supported |
28 | | -if ! echo "${SUPPORTED_ARCH[@]}" | grep -q "\\b${CPU_ARCH}\\b"; then |
29 | | - echo "Error: Unsupported CPU architecture (${CPU_ARCH})." |
| 63 | +# Get the latest release tag from the GitHub API. |
| 64 | +fetch_release() { |
| 65 | + case "$DOWNLOADER" in |
| 66 | + curl) |
| 67 | + curl -fsSL "https://api.github.com/repos/parseablehq/parseable/releases/latest" |
| 68 | + ;; |
| 69 | + wget) |
| 70 | + wget -q -O - "https://api.github.com/repos/parseablehq/parseable/releases/latest" |
| 71 | + ;; |
| 72 | + esac |
| 73 | +} |
| 74 | +if ! release=$(fetch_release); then |
| 75 | + printf 'Error: Could not fetch the latest release information.\n' >&2 |
30 | 76 | exit 1 |
31 | 77 | fi |
32 | | -# Check if the OS is supported |
33 | | -if ! echo "${SUPPORTED_OS[@]}" | grep -q "\\b${OS}\\b"; then |
34 | | - echo "Error: Unsupported operating system (${OS})." |
| 78 | +release_tag=$(printf '%s\n' "$release" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1) |
| 79 | +if [ -z "$release_tag" ]; then |
| 80 | + printf 'Error: Could not determine the latest release version.\n' >&2 |
35 | 81 | exit 1 |
36 | 82 | fi |
37 | 83 |
|
38 | | -# Get the latest release information using GitHub API |
39 | | -release=$(curl -s "https://api.github.com/repos/parseablehq/parseable/releases/latest") |
40 | | -# find the release tag |
41 | | -release_tag=$(echo "$release" | grep -o "\"tag_name\":\s*\"[^\"]*\"" | cut -d '"' -f 4) |
42 | | -if [[ -z "$release_tag" ]]; then |
43 | | - echo "Error: Could not determine the latest release version." |
| 84 | +printf 'Latest Parseable version: %s\n' "$release_tag" |
| 85 | + |
| 86 | +download_url="${DOWNLOAD_BASE_URL}/${release_tag}/${PARSEABLE_PREFIX}" |
| 87 | + |
| 88 | +if [ -d "$INSTALL_DIR" ]; then |
| 89 | + printf "A previous version of Parseable already exists. Run 'parseable --version' to check the version,\n" |
| 90 | + printf 'or remove %s before installing a new version.\n' "$INSTALL_DIR" |
44 | 91 | exit 1 |
45 | 92 | fi |
| 93 | +mkdir -p "$BIN_DIR" || { |
| 94 | + printf 'Error: Could not create installation directory %s.\n' "$BIN_DIR" >&2 |
| 95 | + rmdir "$BIN_DIR" "$INSTALL_DIR" 2>/dev/null || : |
| 96 | + exit 1 |
| 97 | +} |
46 | 98 |
|
47 | | -printf "Latest Parseable version: $release_tag\n" |
48 | | - |
49 | | -# Determine the appropriate binary prefix based on OS and CPU architecture |
50 | | -declare -A PREFIX_MAP=( |
51 | | - ["darwin_arm64"]=$ARM_APPLE_PREFIX |
52 | | - ["linux_arm64"]=$ARM_LINUX_PREFIX |
53 | | - ["linux_x86_64"]=$INTEL_LINUX_PREFIX |
54 | | -) |
55 | | -key="${OS}_${CPU_ARCH}" |
56 | | -PARSEABLE_PREFIX=${PREFIX_MAP[$key]:-""} || { |
57 | | - echo "Error: unsupported platform $OS/$CPU_ARCH"; exit 1; |
| 99 | +TEMP_BIN="${BIN_NAME}.tmp" |
| 100 | +# Remove files and empty directories created by an incomplete installation. |
| 101 | +cleanup_install() { |
| 102 | + rm -f "$TEMP_BIN" "$BIN_NAME" |
| 103 | + rmdir "$BIN_DIR" "$INSTALL_DIR" 2>/dev/null || : |
58 | 104 | } |
| 105 | +trap 'cleanup_install' 0 |
| 106 | +trap 'cleanup_install; exit 1' 1 2 15 |
59 | 107 |
|
60 | | -download_url=${DOWNLOAD_BASE_URL}/${release_tag}/${PARSEABLE_PREFIX} |
| 108 | +printf 'Downloading Parseable version %s, for OS: %s, CPU architecture: %s\n' "$release_tag" "$OS" "$CPU_ARCH" |
| 109 | +printf 'Download URL: %s\n\n' "$download_url" |
61 | 110 |
|
62 | | -if [[ -d ${INSTALL_DIR} ]]; then |
63 | | - printf "A Previous version of parseable already exists. Run 'parseable --version' to check the version." |
64 | | - printf "or consider removing that before new installation\n" |
| 111 | +# Download the selected release asset to the temporary installation path. |
| 112 | +download_binary() { |
| 113 | + case "$DOWNLOADER" in |
| 114 | + curl) |
| 115 | + curl -fL -o "$TEMP_BIN" "$download_url" |
| 116 | + ;; |
| 117 | + wget) |
| 118 | + wget -q -O "$TEMP_BIN" "$download_url" |
| 119 | + ;; |
| 120 | + esac |
| 121 | +} |
| 122 | +if ! download_binary; then |
| 123 | + printf 'Error: download failed.\n' >&2 |
65 | 124 | exit 1 |
66 | | -else |
67 | | - mkdir -p ${BIN_DIR} |
68 | 125 | fi |
69 | 126 |
|
70 | | -# Download the binary using curl or wget |
71 | | -printf "Downloading Parseable version $release_tag, for OS: $OS, CPU architecture: $CPU_ARCH\n" |
72 | | -printf "Download URL: $download_url\n\n" |
73 | | - |
74 | | -if command -v curl &>/dev/null; then |
75 | | - curl -fL -o "${BIN_NAME}" "$download_url" || { echo "Error: download failed"; exit 1; } |
76 | | -elif command -v wget &>/dev/null; then |
77 | | - wget -q -O "${BIN_NAME}" "$download_url" || { echo "Error: download failed"; exit 1; } |
78 | | -else |
79 | | - echo "Error: Neither curl nor wget found. Please install either curl or wget." |
| 127 | +chmod +x "$TEMP_BIN" || { |
| 128 | + printf 'Error: Could not make the downloaded binary executable.\n' >&2 |
80 | 129 | exit 1 |
81 | | -fi |
| 130 | +} |
| 131 | +mv "$TEMP_BIN" "$BIN_NAME" || { |
| 132 | + printf 'Error: Could not finish installing %s.\n' "$BIN_NAME" >&2 |
| 133 | + exit 1 |
| 134 | +} |
| 135 | +trap - 0 1 2 15 |
82 | 136 |
|
83 | | -printf "Parseable Server was successfully installed at: ${BIN_NAME}\n" |
| 137 | +printf 'Parseable Server was successfully installed at: %s\n' "$BIN_NAME" |
84 | 138 |
|
85 | | -chmod +x "${BIN_NAME}" |
| 139 | +# Use the user's login shell to select its startup file. Do not source that file |
| 140 | +# here: this installer may be running under a different shell via `... | sh`. |
| 141 | +SHELL_NAME=${SHELL##*/} |
| 142 | +case "$SHELL_NAME" in |
| 143 | + zsh) |
| 144 | + RC_FILE_PATH="${ZDOTDIR:-$HOME}/.zshrc" |
| 145 | + ;; |
| 146 | + bash) |
| 147 | + RC_FILE_PATH="${HOME}/.bash_profile" |
| 148 | + for BASH_PROFILE in .bash_profile .bash_login .profile; do |
| 149 | + if [ -f "${HOME}/${BASH_PROFILE}" ]; then |
| 150 | + RC_FILE_PATH="${HOME}/${BASH_PROFILE}" |
| 151 | + break |
| 152 | + fi |
| 153 | + done |
| 154 | + ;; |
| 155 | + sh|dash|ksh) |
| 156 | + RC_FILE_PATH="${HOME}/.profile" |
| 157 | + ;; |
| 158 | + *) |
| 159 | + RC_FILE_PATH="" |
| 160 | + ;; |
| 161 | +esac |
86 | 162 |
|
87 | | -PATH_STR="export PATH=${BIN_DIR}"':$PATH' |
88 | | -echo ${PATH_STR} >> ${RC_FILE_PATH} |
89 | | -source ${RC_FILE_PATH} |
| 163 | +PATH_STR="export PATH=\"${BIN_DIR}:\$PATH\"" |
| 164 | +# Add the PATH export to a shell profile unless it is already present. |
| 165 | +append_path() { |
| 166 | + PROFILE_PATH=$1 |
| 167 | + if grep -Fqx "$PATH_STR" "$PROFILE_PATH" 2>/dev/null; then |
| 168 | + printf 'Parseable is already configured in %s.\n' "$PROFILE_PATH" |
| 169 | + elif { |
| 170 | + if [ -s "$PROFILE_PATH" ] && ! tail -c 1 "$PROFILE_PATH" | grep -q '^$'; then |
| 171 | + printf '\n' |
| 172 | + fi |
| 173 | + printf '%s\n' "$PATH_STR" |
| 174 | + } >> "$PROFILE_PATH"; then |
| 175 | + printf 'Added Parseable to PATH in %s.\n' "$PROFILE_PATH" |
| 176 | + else |
| 177 | + printf 'Warning: Could not update %s.\n' "$PROFILE_PATH" >&2 |
| 178 | + fi |
| 179 | +} |
| 180 | + |
| 181 | +if [ "$SHELL_NAME" = "bash" ]; then |
| 182 | + append_path "${HOME}/.bashrc" |
| 183 | + if [ "$RC_FILE_PATH" != "${HOME}/.bashrc" ]; then |
| 184 | + append_path "$RC_FILE_PATH" |
| 185 | + fi |
| 186 | +elif [ -n "$RC_FILE_PATH" ]; then |
| 187 | + append_path "$RC_FILE_PATH" |
| 188 | +else |
| 189 | + printf 'No supported shell profile was detected.\n' |
| 190 | +fi |
| 191 | +printf 'To use Parseable in the current shell, run:\n %s\n' "$PATH_STR" |
0 commit comments