From 99ed6f29ff7578fdcac13a30a6babe7055fdf376 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Thu, 30 Apr 2026 11:32:40 -0400 Subject: [PATCH 1/5] add install and uninstall bash scripts from pinecone-io/install.sh --- scripts/install.sh | 317 +++++++++++++++++++++++++++++++++++++++++++ scripts/uninstall.sh | 163 ++++++++++++++++++++++ 2 files changed, 480 insertions(+) create mode 100755 scripts/install.sh create mode 100755 scripts/uninstall.sh diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..ae0fddb --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,317 @@ +#!/bin/sh +# Copyright (c) Pinecone Systems, Inc. +# +# Install script for the Pinecone CLI (pc). +# +# This script detects your operating system and architecture, downloads the +# latest release of the Pinecone CLI from GitHub, verifies the checksum, and +# installs it to /usr/local/bin (or a directory of your choice). +# +# Usage: +# curl -fsSL https://pinecone.io/install.sh | sh +# +# Environment variables: +# PINECONE_VERSION Pin to a specific version (e.g. "0.4.2"). Default: latest. +# PINECONE_INSTALL Installation directory. Default: /usr/local/bin. +# PINECONE_NO_VERIFY Set to 1 to skip checksum verification. + +set -eu + +GITHUB_REPO="pinecone-io/cli" +BINARY_NAME="pc" + +# All the code is wrapped in a main function that gets called at the +# bottom of the file, so that a truncated partial download doesn't end +# up executing half a script. +main() { + INSTALL_DIR="${PINECONE_INSTALL:-/usr/local/bin}" + VERSION="${PINECONE_VERSION:-}" + NO_VERIFY="${PINECONE_NO_VERIFY:-0}" + + need_cmd uname + + # ------------------------------------------------------- + # Step 1: Detect OS and architecture + # ------------------------------------------------------- + OS="" + ARCH="" + FILENAME="" + + detect_platform + + # ------------------------------------------------------- + # Step 2: Find an HTTP download tool (curl or wget) + # ------------------------------------------------------- + HTTP="" + if command_exists curl; then + HTTP="curl" + elif command_exists wget; then + HTTP="wget" + else + err "Either curl or wget is required to download files. Please install one and try again." + fi + + # ------------------------------------------------------- + # Step 3: Resolve version + # ------------------------------------------------------- + if [ -z "$VERSION" ]; then + log "Fetching latest release version..." + VERSION=$(get_latest_version) + if [ -z "$VERSION" ]; then + err "Could not determine latest version. Set PINECONE_VERSION and try again." + fi + fi + + log "Installing Pinecone CLI v${VERSION} (${OS}/${ARCH})" + + # ------------------------------------------------------- + # Step 4: Build download URLs + # ------------------------------------------------------- + BASE_URL="https://github.com/${GITHUB_REPO}/releases/download/v${VERSION}" + ARCHIVE_URL="${BASE_URL}/${FILENAME}" + CHECKSUMS_URL="${BASE_URL}/pc_${VERSION}_checksums.txt" + + # ------------------------------------------------------- + # Step 5: Download and extract to a temp directory + # ------------------------------------------------------- + TMPDIR_ROOT="${TMPDIR:-/tmp}" + WORK_DIR=$(mktemp -d "${TMPDIR_ROOT}/pinecone-cli.XXXXXX") + trap 'rm -rf "$WORK_DIR"' EXIT + + log "Downloading ${ARCHIVE_URL}..." + download "$ARCHIVE_URL" "${WORK_DIR}/${FILENAME}" + + # ------------------------------------------------------- + # Step 6: Verify checksum (unless opted out) + # ------------------------------------------------------- + if [ "$NO_VERIFY" != "1" ]; then + verify_checksum + else + log "Skipping checksum verification (PINECONE_NO_VERIFY=1)" + fi + + # ------------------------------------------------------- + # Step 7: Extract the binary + # ------------------------------------------------------- + log "Extracting..." + tar -xzf "${WORK_DIR}/${FILENAME}" -C "$WORK_DIR" + + if [ ! -f "${WORK_DIR}/${BINARY_NAME}" ]; then + err "Archive did not contain expected binary '${BINARY_NAME}'. Contents of archive:" \ + "$(ls -la "$WORK_DIR")" + fi + + chmod +x "${WORK_DIR}/${BINARY_NAME}" + + # ------------------------------------------------------- + # Step 8: Install the binary + # ------------------------------------------------------- + install_binary + + # ------------------------------------------------------- + # Done + # ------------------------------------------------------- + log "" + log "Pinecone CLI v${VERSION} installed successfully to ${INSTALL_DIR}/${BINARY_NAME}" + log "" + log "Run 'pc --help' to get started." +} + +# ========================================================= +# Helpers +# ========================================================= + +log() { + printf '%s\n' "$@" +} + +err() { + printf 'Error: %s\n' "$@" >&2 + exit 1 +} + +need_cmd() { + if ! command_exists "$1"; then + err "'$1' is required but not found on your system." + fi +} + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# ========================================================= +# Platform detection +# ========================================================= + +detect_platform() { + local uname_os uname_arch + + uname_os="$(uname -s)" + uname_arch="$(uname -m)" + + case "$uname_os" in + Darwin) + OS="Darwin" + ARCH="all" + FILENAME="pc_Darwin_all.tar.gz" + ;; + Linux) + OS="Linux" + case "$uname_arch" in + x86_64|amd64) + ARCH="x86_64" + FILENAME="pc_Linux_x86_64.tar.gz" + ;; + aarch64|arm64) + ARCH="arm64" + FILENAME="pc_Linux_arm64.tar.gz" + ;; + i386|i686) + ARCH="i386" + FILENAME="pc_Linux_i386.tar.gz" + ;; + *) + err "Unsupported Linux architecture: ${uname_arch}" \ + "Supported architectures: x86_64, arm64, i386" + ;; + esac + ;; + *) + err "Unsupported operating system: ${uname_os}" \ + "This installer supports macOS (Darwin) and Linux." \ + "For Windows, download the .zip from https://github.com/${GITHUB_REPO}/releases" + ;; + esac +} + +# ========================================================= +# HTTP helpers +# ========================================================= + +download() { + local url="$1" + local dest="$2" + + case "$HTTP" in + curl) + curl -fSL --progress-bar -o "$dest" "$url" || err "Failed to download: ${url}" + ;; + wget) + wget -q --show-progress -O "$dest" "$url" || err "Failed to download: ${url}" + ;; + esac +} + +fetch() { + # Fetch URL contents to stdout (silent) + local url="$1" + case "$HTTP" in + curl) curl -fsSL "$url" ;; + wget) wget -qO- "$url" ;; + esac +} + +get_latest_version() { + # Use the GitHub API to get the latest release tag. + # Falls back to following the /releases/latest redirect if the API is rate-limited. + local tag + + tag=$(fetch "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" 2>/dev/null \ + | grep '"tag_name"' \ + | sed -E 's/.*"tag_name":[[:space:]]*"v?([^"]+)".*/\1/' ) || true + + if [ -z "$tag" ] && [ "$HTTP" = "curl" ]; then + # Fallback: follow the redirect and parse the URL + tag=$(curl -fsSL -o /dev/null -w '%{url_effective}' \ + "https://github.com/${GITHUB_REPO}/releases/latest" 2>/dev/null \ + | sed 's|.*/v||') || true + fi + + printf '%s' "$tag" +} + +# ========================================================= +# Checksum verification +# ========================================================= + +verify_checksum() { + local sha_cmd="" + + if command_exists sha256sum; then + sha_cmd="sha256sum" + elif command_exists shasum; then + sha_cmd="shasum -a 256" + else + log "Warning: Neither sha256sum nor shasum found. Skipping checksum verification." + return 0 + fi + + log "Verifying checksum..." + download "$CHECKSUMS_URL" "${WORK_DIR}/checksums.txt" + + local expected actual + expected=$(grep "${FILENAME}" "${WORK_DIR}/checksums.txt" | awk '{print $1}') + + if [ -z "$expected" ]; then + err "Could not find checksum for ${FILENAME} in checksums file." + fi + + actual=$($sha_cmd "${WORK_DIR}/${FILENAME}" | awk '{print $1}') + + if [ "$expected" != "$actual" ]; then + err "Checksum verification failed!" \ + "Expected: ${expected}" \ + "Actual: ${actual}" \ + "The downloaded file may be corrupted. Please try again." + fi + + log "Checksum verified." +} + +# ========================================================= +# Installation +# ========================================================= + +install_binary() { + # Create install directory if it doesn't exist, then move binary into it. + if [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; then + mv "${WORK_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}" + elif command_exists sudo; then + log "Password may be required to install to ${INSTALL_DIR}." + sudo sh -c "mkdir -p \"$INSTALL_DIR\" && mv \"${WORK_DIR}/${BINARY_NAME}\" \"${INSTALL_DIR}/${BINARY_NAME}\"" + elif command_exists doas; then + log "Password may be required to install to ${INSTALL_DIR}." + doas sh -c "mkdir -p \"$INSTALL_DIR\" && mv \"${WORK_DIR}/${BINARY_NAME}\" \"${INSTALL_DIR}/${BINARY_NAME}\"" + elif [ ! -d "$INSTALL_DIR" ]; then + # No sudo/doas but directory doesn't exist — try to create it (works if parent is writable) + mkdir -p "$INSTALL_DIR" 2>/dev/null || \ + err "Cannot create ${INSTALL_DIR} and neither sudo nor doas are available." \ + "Either run this script as root or set PINECONE_INSTALL to a writable directory:" \ + " curl -fsSL https://pinecone.io/install.sh | PINECONE_INSTALL=\$HOME/.local/bin sh" + mv "${WORK_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}" + else + err "Cannot write to ${INSTALL_DIR} and neither sudo nor doas are available." \ + "Either run this script as root or set PINECONE_INSTALL to a writable directory:" \ + " curl -fsSL https://pinecone.io/install.sh | PINECONE_INSTALL=\$HOME/.local/bin sh" + fi + + # Ensure the install directory is in PATH + case ":${PATH}:" in + *":${INSTALL_DIR}:"*) ;; + *) + log "" + log "NOTE: ${INSTALL_DIR} is not in your \$PATH." + log "Add it by running one of the following:" + log "" + log " # For bash" + log " echo 'export PATH=\"${INSTALL_DIR}:\$PATH\"' >> ~/.bashrc && source ~/.bashrc" + log "" + log " # For zsh" + log " echo 'export PATH=\"${INSTALL_DIR}:\$PATH\"' >> ~/.zshrc && source ~/.zshrc" + log "" + ;; + esac +} + +main diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh new file mode 100755 index 0000000..f756b81 --- /dev/null +++ b/scripts/uninstall.sh @@ -0,0 +1,163 @@ +#!/bin/sh +# Copyright (c) Pinecone Systems, Inc. +# +# Uninstall script for the Pinecone CLI (pc). +# +# This script removes the Pinecone CLI binary and optionally removes +# configuration and data files created by the CLI. +# +# Usage: +# curl -fsSL https://pinecone.io/uninstall.sh | sh +# +# Or, if you have the script locally: +# cat uninstall.sh | sh +# +# Environment variables: +# PINECONE_INSTALL Installation directory where pc was installed. Default: /usr/local/bin. +# PINECONE_KEEP_CONFIG Set to 1 to keep configuration files. Default: remove them. + +set -eu + +BINARY_NAME="pc" + +main() { + INSTALL_DIR="${PINECONE_INSTALL:-/usr/local/bin}" + KEEP_CONFIG="${PINECONE_KEEP_CONFIG:-0}" + + BINARY_PATH="${INSTALL_DIR}/${BINARY_NAME}" + + # ------------------------------------------------------- + # Step 0: Check for package-manager installations + # ------------------------------------------------------- + check_package_manager + + # ------------------------------------------------------- + # Step 1: Remove the binary + # ------------------------------------------------------- + remove_binary + + # ------------------------------------------------------- + # Step 2: Remove configuration and data files + # ------------------------------------------------------- + if [ "$KEEP_CONFIG" != "1" ]; then + remove_config + else + log "Keeping configuration files (PINECONE_KEEP_CONFIG=1)." + fi + + # ------------------------------------------------------- + # Done + # ------------------------------------------------------- + log "" + log "Pinecone CLI has been uninstalled." +} + +# ========================================================= +# Helpers +# ========================================================= + +log() { + printf '%s\n' "$@" +} + +err() { + printf 'Error: %s\n' "$@" >&2 + exit 1 +} + +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# ========================================================= +# Package-manager detection +# ========================================================= + +check_package_manager() { + PC_PATH="$(command -v pc 2>/dev/null || true)" + + # Homebrew: check if pc resolves into a Homebrew prefix (Cellar or Caskroom) + if [ -n "$PC_PATH" ] && command_exists brew; then + BREW_PREFIX="$(brew --prefix 2>/dev/null || true)" + REAL_PC="$(readlink "$PC_PATH" 2>/dev/null || true)" + case "$REAL_PC" in + "${BREW_PREFIX}"/Caskroom/*) + CASK_NAME="$(echo "$REAL_PC" | sed "s|${BREW_PREFIX}/Caskroom/||" | cut -d/ -f1)" + log "Pinecone CLI appears to have been installed via Homebrew (cask: ${CASK_NAME})." + log "You can uninstall it with:" + log "" + log " brew uninstall --cask ${CASK_NAME}" + log "" + exit 0 + ;; + "${BREW_PREFIX}"/Cellar/*) + FORMULA_NAME="$(echo "$REAL_PC" | sed "s|${BREW_PREFIX}/Cellar/||" | cut -d/ -f1)" + log "Pinecone CLI appears to have been installed via Homebrew (formula: ${FORMULA_NAME})." + log "You can uninstall it with:" + log "" + log " brew uninstall ${FORMULA_NAME}" + log "" + exit 0 + ;; + esac + fi + +} + +# ========================================================= +# Binary removal +# ========================================================= + +remove_binary() { + if [ ! -f "$BINARY_PATH" ]; then + log "Binary not found at ${BINARY_PATH}. It may have already been removed." + return 0 + fi + + log "Removing ${BINARY_PATH}..." + + if [ -w "$INSTALL_DIR" ]; then + rm -f "$BINARY_PATH" + elif command_exists sudo; then + log "Password may be required to remove ${BINARY_PATH}." + sudo rm -f "$BINARY_PATH" + elif command_exists doas; then + log "Password may be required to remove ${BINARY_PATH}." + doas rm -f "$BINARY_PATH" + else + err "Cannot write to ${INSTALL_DIR} and neither sudo nor doas are available." \ + "Either run this script as root or set PINECONE_INSTALL to the directory where pc was installed:" \ + " curl -fsSL https://pinecone.io/uninstall.sh | PINECONE_INSTALL=\$HOME/.local/bin sh" + fi + + log "Binary removed." +} + +# ========================================================= +# Configuration removal +# ========================================================= + +remove_config() { + local uname_os + uname_os="$(uname -s)" + + CONFIG_DIR="" + case "$uname_os" in + Darwin) + CONFIG_DIR="${HOME}/Library/Application Support/pinecone" + ;; + Linux) + CONFIG_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/pinecone" + ;; + esac + + if [ -n "$CONFIG_DIR" ] && [ -d "$CONFIG_DIR" ]; then + log "Removing configuration directory ${CONFIG_DIR}..." + rm -rf "$CONFIG_DIR" + log "Configuration removed." + else + log "No configuration directory found." + fi +} + +main From 2d3dd1579cbcb17435b0258504bdcffd41f085bc Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Thu, 30 Apr 2026 12:25:37 -0400 Subject: [PATCH 2/5] Fix Homebrew symlink detection and sudo escalation in install/uninstall scripts Resolve relative readlink paths to absolute before pattern-matching against BREW_PREFIX, so Homebrew-managed installs are correctly detected on macOS. Attempt unprivileged mkdir before falling through to sudo, so user-owned paths like /Users/austin/.local/bin are never created as root. --- scripts/install.sh | 13 ++++++------- scripts/uninstall.sh | 5 +++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/scripts/install.sh b/scripts/install.sh index ae0fddb..b952947 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -274,6 +274,12 @@ verify_checksum() { # ========================================================= install_binary() { + # Try unprivileged directory creation first so a user-owned path like + # $HOME/.local/bin is never created as root via sudo. + if [ ! -d "$INSTALL_DIR" ]; then + mkdir -p "$INSTALL_DIR" 2>/dev/null || true + fi + # Create install directory if it doesn't exist, then move binary into it. if [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; then mv "${WORK_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}" @@ -283,13 +289,6 @@ install_binary() { elif command_exists doas; then log "Password may be required to install to ${INSTALL_DIR}." doas sh -c "mkdir -p \"$INSTALL_DIR\" && mv \"${WORK_DIR}/${BINARY_NAME}\" \"${INSTALL_DIR}/${BINARY_NAME}\"" - elif [ ! -d "$INSTALL_DIR" ]; then - # No sudo/doas but directory doesn't exist — try to create it (works if parent is writable) - mkdir -p "$INSTALL_DIR" 2>/dev/null || \ - err "Cannot create ${INSTALL_DIR} and neither sudo nor doas are available." \ - "Either run this script as root or set PINECONE_INSTALL to a writable directory:" \ - " curl -fsSL https://pinecone.io/install.sh | PINECONE_INSTALL=\$HOME/.local/bin sh" - mv "${WORK_DIR}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}" else err "Cannot write to ${INSTALL_DIR} and neither sudo nor doas are available." \ "Either run this script as root or set PINECONE_INSTALL to a writable directory:" \ diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index f756b81..6f8777e 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -80,6 +80,11 @@ check_package_manager() { if [ -n "$PC_PATH" ] && command_exists brew; then BREW_PREFIX="$(brew --prefix 2>/dev/null || true)" REAL_PC="$(readlink "$PC_PATH" 2>/dev/null || true)" + # readlink may return a relative path on macOS; resolve it to absolute + case "$REAL_PC" in + /*) ;; + ?*) REAL_PC="$(cd "$(dirname "$PC_PATH")" && cd "$(dirname "$REAL_PC")" && pwd)/$(basename "$REAL_PC")" ;; + esac case "$REAL_PC" in "${BREW_PREFIX}"/Caskroom/*) CASK_NAME="$(echo "$REAL_PC" | sed "s|${BREW_PREFIX}/Caskroom/||" | cut -d/ -f1)" From 36ac618a2dcba542649175bffe10d03522c60765 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Thu, 30 Apr 2026 12:59:47 -0400 Subject: [PATCH 3/5] Fix checksum false matches and v-prefix double-encoding in install script Replace grep regex match with awk exact field match to prevent false checksum hits from SBOM or similarly-named files. Strip leading v from user-supplied PINECONE_VERSION to avoid double-encoding in the download URL. --- scripts/install.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/install.sh b/scripts/install.sh index b952947..1829dd9 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -26,6 +26,7 @@ BINARY_NAME="pc" main() { INSTALL_DIR="${PINECONE_INSTALL:-/usr/local/bin}" VERSION="${PINECONE_VERSION:-}" + VERSION="${VERSION#v}" NO_VERIFY="${PINECONE_NO_VERIFY:-0}" need_cmd uname @@ -251,7 +252,7 @@ verify_checksum() { download "$CHECKSUMS_URL" "${WORK_DIR}/checksums.txt" local expected actual - expected=$(grep "${FILENAME}" "${WORK_DIR}/checksums.txt" | awk '{print $1}') + expected=$(awk -v f="${FILENAME}" '$2 == f {print $1}' "${WORK_DIR}/checksums.txt") if [ -z "$expected" ]; then err "Could not find checksum for ${FILENAME} in checksums file." From 92dfdb2de8a51db15964df8b3ecc0d6197fe4827 Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Thu, 30 Apr 2026 13:14:32 -0400 Subject: [PATCH 4/5] Fix uninstall config path on macOS The CLI stores config at ~/.config/pinecone on all platforms, but the uninstall script was looking in ~/Library/Application Support/pinecone on macOS and silently leaving config behind. --- scripts/uninstall.sh | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index 6f8777e..6eef800 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -143,20 +143,9 @@ remove_binary() { # ========================================================= remove_config() { - local uname_os - uname_os="$(uname -s)" - - CONFIG_DIR="" - case "$uname_os" in - Darwin) - CONFIG_DIR="${HOME}/Library/Application Support/pinecone" - ;; - Linux) - CONFIG_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/pinecone" - ;; - esac - - if [ -n "$CONFIG_DIR" ] && [ -d "$CONFIG_DIR" ]; then + CONFIG_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/pinecone" + + if [ -d "$CONFIG_DIR" ]; then log "Removing configuration directory ${CONFIG_DIR}..." rm -rf "$CONFIG_DIR" log "Configuration removed." From 5d22e18e632bfe9f6d75fde87743aa8d10d7af7e Mon Sep 17 00:00:00 2001 From: Austin DeNoble Date: Thu, 30 Apr 2026 13:29:02 -0400 Subject: [PATCH 5/5] Fix Homebrew detection checking wrong binary path in uninstall script check_package_manager was using command -v pc, which resolves the first pc in /Users/austin/google-cloud-sdk/bin:/Users/austin/.sdkman/candidates/java/current/bin:/Users/austin/.sdkman/candidates/gradle/current/bin:/Users/austin/.nvm/versions/node/v22.21.1/bin:/Users/austin/apache-maven-3.9.6/bin:/Users/austin/.local/bin:/Users/austin/.cargo/bin:/usr/local/go/bin:/Users/austin/go/bin:/opt/homebrew/opt/llvm/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/opt/pmk/env/global/bin:/usr/local/go/bin:/Users/austin/.cargo/bin:/Applications/Warp.app/Contents/Resources/bin rather than the binary targeted by PINECONE_INSTALL. Now checks BINARY_PATH directly, matching what remove_binary would remove. --- scripts/uninstall.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index 6eef800..9a44806 100755 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -74,16 +74,14 @@ command_exists() { # ========================================================= check_package_manager() { - PC_PATH="$(command -v pc 2>/dev/null || true)" - # Homebrew: check if pc resolves into a Homebrew prefix (Cellar or Caskroom) - if [ -n "$PC_PATH" ] && command_exists brew; then + if [ -e "$BINARY_PATH" ] && command_exists brew; then BREW_PREFIX="$(brew --prefix 2>/dev/null || true)" - REAL_PC="$(readlink "$PC_PATH" 2>/dev/null || true)" + REAL_PC="$(readlink "$BINARY_PATH" 2>/dev/null || true)" # readlink may return a relative path on macOS; resolve it to absolute case "$REAL_PC" in /*) ;; - ?*) REAL_PC="$(cd "$(dirname "$PC_PATH")" && cd "$(dirname "$REAL_PC")" && pwd)/$(basename "$REAL_PC")" ;; + ?*) REAL_PC="$(cd "$(dirname "$BINARY_PATH")" && cd "$(dirname "$REAL_PC")" && pwd)/$(basename "$REAL_PC")" ;; esac case "$REAL_PC" in "${BREW_PREFIX}"/Caskroom/*)