Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 78 additions & 49 deletions scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -259,61 +259,90 @@ echo "Verify with:"
echo " $PREFIX/$BINARY_NAME version"
echo ""

# PATH handling for the fallback case. install.ps1 persists the PATH
# entry on Windows (SetEnvironmentVariable, User scope) — do the same on
# Unix by writing to the rc file the user's shell actually reads. The old
# print-only advice silently failed on Ubuntu: ~/.profile adds
# ~/.local/bin only at *login* and only if it already existed, but the
# installer creates it mid-session, so a new (non-login) terminal reading
# ~/.bashrc never picks it up.
case ":$PATH:" in
*":$PREFIX:"*) ;; # already on PATH — nothing to do
*)
shell_name="$(basename "${SHELL:-sh}")"
case "$shell_name" in
zsh) rc="$HOME/.zshrc" ;;
bash)
# macOS Terminal opens a login shell (reads .bash_profile);
# Linux terminals are interactive non-login (read .bashrc).
if [ "$OS" = "darwin" ]; then rc="$HOME/.bash_profile"; else rc="$HOME/.bashrc"; fi
;;
fish) rc="$HOME/.config/fish/config.fish" ;;
*) rc="$HOME/.profile" ;;
esac
# PATH handling. install.ps1 persists the PATH entry on Windows
# (SetEnvironmentVariable, User scope) — do the same on Unix by writing to
# the rc file the user's shell actually reads. The old print-only advice
# silently failed on Ubuntu: ~/.profile adds ~/.local/bin only at *login*
# and only if it already existed, but the installer creates it mid-session,
# so a new (non-login) terminal reading ~/.bashrc never picks it up.
#
# Decide whether to persist a PATH entry to the user's shell rc:
# - a user-local prefix (under $HOME — the unprivileged `curl | sh` fallback)
# ALWAYS needs one, even when a one-off `export` already put it on $PATH for
# this shell (that won't survive into a new terminal);
# - a non-$HOME prefix that ISN'T on $PATH (e.g. `--prefix /opt/tracebloc`)
# also needs one;
# - a non-$HOME prefix already on $PATH (e.g. the default /usr/local/bin) is
# on PATH for every shell and needs nothing.
# ($HOME is stripped of a trailing slash first so a HOME like "/home/u/" can't
# misclassify "/home/u/.local/bin" via a "/home/u//*" pattern it won't match.)
home_dir="${HOME%/}"
persist=no
case "$PREFIX" in
"$home_dir"/*) persist=yes ;;
*) case ":$PATH:" in *":$PREFIX:"*) ;; *) persist=yes ;; esac ;;
esac

if [ "$persist" = "yes" ]; then
shell_name="$(basename "${SHELL:-sh}")"
case "$shell_name" in
zsh) rc="$HOME/.zshrc" ;;
bash)
# macOS Terminal opens a login shell (reads .bash_profile);
# Linux terminals are interactive non-login (read .bashrc).
if [ "$OS" = "darwin" ]; then rc="$HOME/.bash_profile"; else rc="$HOME/.bashrc"; fi
;;
fish) rc="$HOME/.config/fish/config.fish" ;;
*) rc="$HOME/.profile" ;;
esac

if [ "$shell_name" = "fish" ]; then
path_line="fish_add_path $PREFIX"
else
path_line="export PATH=\"$PREFIX:\$PATH\""
fi
if [ "$shell_name" = "fish" ]; then
path_line="fish_add_path $PREFIX"
else
path_line="export PATH=\"$PREFIX:\$PATH\""
fi

added=0
mkdir -p "$(dirname "$rc")" 2>/dev/null || true
if grep -qsF "$PREFIX" "$rc" 2>/dev/null; then
added=1 # rc already references it — leave it alone (idempotent)
# Group the append so the redirection-open error (e.g. an
# existing but read-only rc, or an unwritable parent dir) is
# suppressed too: `cmd >> "$rc" 2>/dev/null` leaks the shell's
# "Permission denied" because the >> open is attempted before
# 2>/dev/null applies. Wrapping in { ... } 2>/dev/null puts the
# stderr redirect in scope first, so the fallback message below
# is the only thing the user sees.
elif { printf '\n# Added by the tracebloc CLI installer\n%s\n' "$path_line" >> "$rc"; } 2>/dev/null; then
added=1
fi
# Track three outcomes precisely so the message can neither over- nor
# under-claim: already configured / freshly added / couldn't write.
state=failed
mkdir -p "$(dirname "$rc")" 2>/dev/null || true
# Idempotency: only an actual, non-comment PATH op that references $PREFIX
# counts as "already configured" — a bare comment or an unrelated line that
# merely mentions the dir must NOT pass, or we'd claim success while a new
# shell still can't find the binary (#61). Match PATH= / PATH+= /
# fish_add_path / zsh's path+=() (case-insensitive); the [^A-Za-z_] guard
# keeps PYTHONPATH=/MYPATH= out.
if grep -v '^[[:space:]]*#' "$rc" 2>/dev/null \
| grep -iE '(^|[^A-Za-z_])path[+]?=|fish_add_path' \
| grep -qF "$PREFIX"; then
state=present # rc already persists it — leave it alone
# Group the append so the redirection-open error (e.g. a read-only rc, or
# an unwritable parent dir) is suppressed too: `cmd >> "$rc" 2>/dev/null`
# leaks the shell's "Permission denied" because the >> open is attempted
# before 2>/dev/null applies. Wrapping in { ... } 2>/dev/null puts the
# stderr redirect in scope first.
elif { printf '\n# Added by the tracebloc CLI installer\n%s\n' "$path_line" >> "$rc"; } 2>/dev/null; then
state=added
fi

echo ""
if [ "$added" = "1" ]; then
echo ""
case "$state" in
added)
echo "Added $PREFIX to your PATH in $rc."
echo "Open a new terminal — or load it now: . \"$rc\""
else
echo "Note: $PREFIX is not on \$PATH and the installer couldn't update your shell config."
echo "Add this line, then open a new terminal:"
;;
present)
echo "$PREFIX is already in your PATH config ($rc) — nothing to add."
echo "If a new terminal can't find it yet, open one — or load it now: . \"$rc\""
;;
*)
echo "Note: the installer couldn't update your shell config ($rc)."
echo "Add this line to it (or your shell's startup file), then open a new terminal:"
echo " $path_line"
fi
echo ""
;;
esac
;;
esac
echo ""
fi

echo "First steps:"
echo " $BINARY_NAME cluster info # confirm CLI can reach your cluster"
Expand Down
Loading