From 0b76658d7da7ba6bc42a25c2802c4ac72778cd02 Mon Sep 17 00:00:00 2001 From: Nikhil Sinha Date: Mon, 12 Oct 2026 19:34:27 +0530 Subject: [PATCH 1/4] fix: install script make installer platform aware, shell profile safe --- scripts/download.sh | 213 +++++++++++++++++++++++++++++++------------- 1 file changed, 150 insertions(+), 63 deletions(-) diff --git a/scripts/download.sh b/scripts/download.sh index d22b7403b..83291377d 100755 --- a/scripts/download.sh +++ b/scripts/download.sh @@ -1,89 +1,176 @@ -#!/bin/zsh +#!/bin/sh -# supported CPU architectures and operating systems -SUPPORTED_ARCH=("x86_64" "arm64") -SUPPORTED_OS=("linux" "darwin") DOWNLOAD_BASE_URL="https://github.com/parseablehq/parseable/releases/download" -ARM_APPLE_PREFIX="Parseable_OSS_aarch64-apple-darwin" -ARM_LINUX_PREFIX="Parseable_OSS_aarch64-unknown-linux-gnu" -INTEL_LINUX_PREFIX="Parseable_OSS_x86_64-unknown-linux-gnu" -PARSEABLE_PREFIX=${ARM_APPLE_PREFIX} +INSTALL_DIR="${HOME}/.parseable" +BIN_DIR="${INSTALL_DIR}/bin" +BIN_NAME="${BIN_DIR}/parseable" -# Get the system's CPU architecture and operating system +# Get the system's CPU architecture and operating system. CPU_ARCH=$(uname -m) OS=$(uname -s | tr '[:upper:]' '[:lower:]') -printf "\n=========================\n" -printf "Detected CPU architecture: %s\n" "$CPU_ARCH" -printf "Detected operating system: %s\n" "$OS" +printf '\n=========================\n' +printf 'Detected CPU architecture: %s\n' "$CPU_ARCH" +printf 'Detected operating system: %s\n' "$OS" -SHELL_NAME=$(basename $SHELL) -RC_FILE=".${SHELL_NAME}rc" -RC_FILE_PATH="${HOME}/${RC_FILE}" -INSTALL_DIR="${HOME}/.parseable" -BIN_DIR="${INSTALL_DIR}/bin" -BIN_NAME="${BIN_DIR}/parseable" +# Select one downloader and use it for both the release lookup and the binary. +if command -v curl >/dev/null 2>&1; then + DOWNLOADER="curl" +elif command -v wget >/dev/null 2>&1; then + DOWNLOADER="wget" +else + printf 'Error: Neither curl nor wget was found. Please install either curl or wget.\n' >&2 + exit 1 +fi -# Check if the CPU architecture is supported -if ! echo "${SUPPORTED_ARCH[@]}" | grep -q "\\b${CPU_ARCH}\\b"; then - echo "Error: Unsupported CPU architecture (${CPU_ARCH})." +# Match the platform names used by the release assets. Linux commonly reports +# ARM64 as "aarch64", while macOS reports it as "arm64". +case "${OS}_${CPU_ARCH}" in + darwin_arm64) + PARSEABLE_PREFIX="Parseable_OSS_aarch64-apple-darwin" + ;; + linux_arm64|linux_aarch64) + PARSEABLE_PREFIX="Parseable_OSS_aarch64-unknown-linux-gnu" + ;; + linux_x86_64|linux_amd64) + PARSEABLE_PREFIX="Parseable_OSS_x86_64-unknown-linux-gnu" + ;; + *) + printf 'Error: unsupported platform %s/%s.\n' "$OS" "$CPU_ARCH" >&2 + exit 1 + ;; +esac + +# Parseable's Linux release binaries require glibc. +if [ "$OS" = "linux" ]; then + MUSL_FOUND="false" + if command -v ldd >/dev/null 2>&1 && ldd --version 2>&1 | grep -qi musl; then + MUSL_FOUND="true" + else + for MUSL_LOADER in /lib/ld-musl-*.so.1; do + if [ -e "$MUSL_LOADER" ]; then + MUSL_FOUND="true" + break + fi + done + fi + if [ "$MUSL_FOUND" = "true" ]; then + printf 'Error: Alpine Linux and other musl-based systems are not supported by the available release binaries.\n' >&2 + exit 1 + fi +fi + +# Get the latest release tag from the GitHub API. +fetch_release() { + case "$DOWNLOADER" in + curl) + curl -fsSL "https://api.github.com/repos/parseablehq/parseable/releases/latest" + ;; + wget) + wget -q -O - "https://api.github.com/repos/parseablehq/parseable/releases/latest" + ;; + esac +} +if ! release=$(fetch_release); then + printf 'Error: Could not fetch the latest release information.\n' >&2 exit 1 fi -# Check if the OS is supported -if ! echo "${SUPPORTED_OS[@]}" | grep -q "\\b${OS}\\b"; then - echo "Error: Unsupported operating system (${OS})." +release_tag=$(printf '%s\n' "$release" | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1) +if [ -z "$release_tag" ]; then + printf 'Error: Could not determine the latest release version.\n' >&2 exit 1 fi -# Get the latest release information using GitHub API -release=$(curl -s "https://api.github.com/repos/parseablehq/parseable/releases/latest") -# find the release tag -release_tag=$(echo "$release" | grep -o "\"tag_name\":\s*\"[^\"]*\"" | cut -d '"' -f 4) -if [[ -z "$release_tag" ]]; then - echo "Error: Could not determine the latest release version." +printf 'Latest Parseable version: %s\n' "$release_tag" + +download_url="${DOWNLOAD_BASE_URL}/${release_tag}/${PARSEABLE_PREFIX}" + +if [ -d "$INSTALL_DIR" ]; then + printf "A previous version of Parseable already exists. Run 'parseable --version' to check the version,\n" + printf 'or remove %s before installing a new version.\n' "$INSTALL_DIR" exit 1 fi +mkdir -p "$BIN_DIR" || { + printf 'Error: Could not create installation directory %s.\n' "$BIN_DIR" >&2 + exit 1 +} -printf "Latest Parseable version: $release_tag\n" - -# Determine the appropriate binary prefix based on OS and CPU architecture -declare -A PREFIX_MAP=( - ["darwin_arm64"]=$ARM_APPLE_PREFIX - ["linux_arm64"]=$ARM_LINUX_PREFIX - ["linux_x86_64"]=$INTEL_LINUX_PREFIX -) -key="${OS}_${CPU_ARCH}" -PARSEABLE_PREFIX=${PREFIX_MAP[$key]:-""} || { - echo "Error: unsupported platform $OS/$CPU_ARCH"; exit 1; +TEMP_BIN="${BIN_NAME}.tmp" +cleanup_install() { + rm -f "$TEMP_BIN" "$BIN_NAME" + rmdir "$BIN_DIR" "$INSTALL_DIR" 2>/dev/null || : } +trap 'cleanup_install' 0 +trap 'cleanup_install; exit 1' 1 2 15 -download_url=${DOWNLOAD_BASE_URL}/${release_tag}/${PARSEABLE_PREFIX} +printf 'Downloading Parseable version %s, for OS: %s, CPU architecture: %s\n' "$release_tag" "$OS" "$CPU_ARCH" +printf 'Download URL: %s\n\n' "$download_url" -if [[ -d ${INSTALL_DIR} ]]; then - printf "A Previous version of parseable already exists. Run 'parseable --version' to check the version." - printf "or consider removing that before new installation\n" +download_binary() { + case "$DOWNLOADER" in + curl) + curl -fL -o "$TEMP_BIN" "$download_url" + ;; + wget) + wget -q -O "$TEMP_BIN" "$download_url" + ;; + esac +} +if ! download_binary; then + printf 'Error: download failed.\n' >&2 exit 1 -else - mkdir -p ${BIN_DIR} fi -# Download the binary using curl or wget -printf "Downloading Parseable version $release_tag, for OS: $OS, CPU architecture: $CPU_ARCH\n" -printf "Download URL: $download_url\n\n" - -if command -v curl &>/dev/null; then - curl -fL -o "${BIN_NAME}" "$download_url" || { echo "Error: download failed"; exit 1; } -elif command -v wget &>/dev/null; then - wget -q -O "${BIN_NAME}" "$download_url" || { echo "Error: download failed"; exit 1; } -else - echo "Error: Neither curl nor wget found. Please install either curl or wget." +chmod +x "$TEMP_BIN" || { + printf 'Error: Could not make the downloaded binary executable.\n' >&2 exit 1 -fi +} +mv "$TEMP_BIN" "$BIN_NAME" || { + printf 'Error: Could not finish installing %s.\n' "$BIN_NAME" >&2 + exit 1 +} +trap - 0 1 2 15 -printf "Parseable Server was successfully installed at: ${BIN_NAME}\n" +printf 'Parseable Server was successfully installed at: %s\n' "$BIN_NAME" -chmod +x "${BIN_NAME}" +# Use the user's login shell to select its startup file. Do not source that file +# here: this installer may be running under a different shell via `... | sh`. +SHELL_NAME=${SHELL##*/} +case "$SHELL_NAME" in + zsh) + RC_FILE_PATH="${ZDOTDIR:-$HOME}/.zshrc" + ;; + bash) + if [ "$OS" = "darwin" ]; then + RC_FILE_PATH="${HOME}/.bash_profile" + for BASH_PROFILE in .bash_profile .bash_login .profile; do + if [ -f "${HOME}/${BASH_PROFILE}" ]; then + RC_FILE_PATH="${HOME}/${BASH_PROFILE}" + break + fi + done + else + RC_FILE_PATH="${HOME}/.bashrc" + fi + ;; + sh|dash|ksh) + RC_FILE_PATH="${HOME}/.profile" + ;; + *) + RC_FILE_PATH="" + ;; +esac -PATH_STR="export PATH=${BIN_DIR}"':$PATH' -echo ${PATH_STR} >> ${RC_FILE_PATH} -source ${RC_FILE_PATH} +PATH_STR="export PATH=\"${BIN_DIR}:\$PATH\"" +if [ -n "$RC_FILE_PATH" ]; then + if grep -Fqx "$PATH_STR" "$RC_FILE_PATH" 2>/dev/null; then + printf 'Parseable is already configured in %s.\n' "$RC_FILE_PATH" + elif printf '%s\n' "$PATH_STR" >> "$RC_FILE_PATH"; then + printf 'Added Parseable to PATH in %s.\n' "$RC_FILE_PATH" + else + printf 'Warning: Could not update %s.\n' "$RC_FILE_PATH" >&2 + fi +else + printf 'No supported shell profile was detected.\n' +fi +printf 'To use Parseable in the current shell, run:\n %s\n' "$PATH_STR" From 2e8ba3c017f181d921e65dd229915e8e128727cd Mon Sep 17 00:00:00 2001 From: Nikhil Sinha Date: Mon, 12 Oct 2026 19:43:20 +0530 Subject: [PATCH 2/4] coderabbit comments fix --- scripts/download.sh | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/scripts/download.sh b/scripts/download.sh index 83291377d..b0a75458f 100755 --- a/scripts/download.sh +++ b/scripts/download.sh @@ -92,10 +92,12 @@ if [ -d "$INSTALL_DIR" ]; then fi mkdir -p "$BIN_DIR" || { printf 'Error: Could not create installation directory %s.\n' "$BIN_DIR" >&2 + rmdir "$BIN_DIR" "$INSTALL_DIR" 2>/dev/null || : exit 1 } TEMP_BIN="${BIN_NAME}.tmp" +# Remove files and empty directories created by an incomplete installation. cleanup_install() { rm -f "$TEMP_BIN" "$BIN_NAME" rmdir "$BIN_DIR" "$INSTALL_DIR" 2>/dev/null || : @@ -106,6 +108,7 @@ trap 'cleanup_install; exit 1' 1 2 15 printf 'Downloading Parseable version %s, for OS: %s, CPU architecture: %s\n' "$release_tag" "$OS" "$CPU_ARCH" printf 'Download URL: %s\n\n' "$download_url" +# Download the selected release asset to the temporary installation path. download_binary() { case "$DOWNLOADER" in curl) @@ -141,17 +144,13 @@ case "$SHELL_NAME" in RC_FILE_PATH="${ZDOTDIR:-$HOME}/.zshrc" ;; bash) - if [ "$OS" = "darwin" ]; then - RC_FILE_PATH="${HOME}/.bash_profile" - for BASH_PROFILE in .bash_profile .bash_login .profile; do - if [ -f "${HOME}/${BASH_PROFILE}" ]; then - RC_FILE_PATH="${HOME}/${BASH_PROFILE}" - break - fi - done - else - RC_FILE_PATH="${HOME}/.bashrc" - fi + RC_FILE_PATH="${HOME}/.bash_profile" + for BASH_PROFILE in .bash_profile .bash_login .profile; do + if [ -f "${HOME}/${BASH_PROFILE}" ]; then + RC_FILE_PATH="${HOME}/${BASH_PROFILE}" + break + fi + done ;; sh|dash|ksh) RC_FILE_PATH="${HOME}/.profile" From d87e9afa0f8da7d82c840c1b34e80dd5f2bc8987 Mon Sep 17 00:00:00 2001 From: Nikhil Sinha Date: Mon, 12 Oct 2026 20:12:30 +0530 Subject: [PATCH 3/4] coderabbit comments fix --- scripts/download.sh | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/scripts/download.sh b/scripts/download.sh index b0a75458f..414589a0e 100755 --- a/scripts/download.sh +++ b/scripts/download.sh @@ -161,14 +161,25 @@ case "$SHELL_NAME" in esac PATH_STR="export PATH=\"${BIN_DIR}:\$PATH\"" -if [ -n "$RC_FILE_PATH" ]; then - if grep -Fqx "$PATH_STR" "$RC_FILE_PATH" 2>/dev/null; then - printf 'Parseable is already configured in %s.\n' "$RC_FILE_PATH" - elif printf '%s\n' "$PATH_STR" >> "$RC_FILE_PATH"; then - printf 'Added Parseable to PATH in %s.\n' "$RC_FILE_PATH" +# Add the PATH export to a shell profile unless it is already present. +append_path() { + PROFILE_PATH=$1 + if grep -Fqx "$PATH_STR" "$PROFILE_PATH" 2>/dev/null; then + printf 'Parseable is already configured in %s.\n' "$PROFILE_PATH" + elif printf '%s\n' "$PATH_STR" >> "$PROFILE_PATH"; then + printf 'Added Parseable to PATH in %s.\n' "$PROFILE_PATH" else - printf 'Warning: Could not update %s.\n' "$RC_FILE_PATH" >&2 + printf 'Warning: Could not update %s.\n' "$PROFILE_PATH" >&2 fi +} + +if [ "$SHELL_NAME" = "bash" ]; then + append_path "${HOME}/.bashrc" + if [ "$RC_FILE_PATH" != "${HOME}/.bashrc" ]; then + append_path "$RC_FILE_PATH" + fi +elif [ -n "$RC_FILE_PATH" ]; then + append_path "$RC_FILE_PATH" else printf 'No supported shell profile was detected.\n' fi From f105e251099de4f0a6f4fb5c9398034f9f49a313 Mon Sep 17 00:00:00 2001 From: Nikhil Sinha Date: Mon, 12 Oct 2026 20:48:28 +0530 Subject: [PATCH 4/4] add separator newline when missing --- scripts/download.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/download.sh b/scripts/download.sh index 414589a0e..86117fc5a 100755 --- a/scripts/download.sh +++ b/scripts/download.sh @@ -166,7 +166,12 @@ append_path() { PROFILE_PATH=$1 if grep -Fqx "$PATH_STR" "$PROFILE_PATH" 2>/dev/null; then printf 'Parseable is already configured in %s.\n' "$PROFILE_PATH" - elif printf '%s\n' "$PATH_STR" >> "$PROFILE_PATH"; then + elif { + if [ -s "$PROFILE_PATH" ] && ! tail -c 1 "$PROFILE_PATH" | grep -q '^$'; then + printf '\n' + fi + printf '%s\n' "$PATH_STR" + } >> "$PROFILE_PATH"; then printf 'Added Parseable to PATH in %s.\n' "$PROFILE_PATH" else printf 'Warning: Could not update %s.\n' "$PROFILE_PATH" >&2