diff --git a/INSTALL.md b/INSTALL.md index 16beb95..7e8bddb 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -20,7 +20,10 @@ sh "$installer_file" ``` The installer supports Intel/AMD64 and ARM64. It writes to `/usr/local/bin` -when that directory is writable, otherwise it uses `$HOME/.local/bin`. +when that directory is writable and already on `PATH`, otherwise it uses +`$HOME/.local/bin`. When necessary, it adds that directory to the appropriate +zsh, bash, or POSIX shell profile and prints the command needed for the current +shell. In GitHub Actions, it updates `$GITHUB_PATH` instead. To install a specific version or directory: @@ -35,3 +38,9 @@ sh "$installer_file" \ `STACKDOME_VERSION` and `STACKDOME_INSTALL_DIR` provide the same settings for automation. Explicit flags take precedence over environment variables. + +Agents and CI systems that manage `PATH` themselves can disable profile changes: + +```sh +sh "$installer_file" --no-modify-path +``` diff --git a/install.sh b/install.sh index db44068..98cfe0a 100755 --- a/install.sh +++ b/install.sh @@ -7,6 +7,7 @@ release_base_url=${STACKDOME_RELEASE_BASE_URL:-https://github.com/${repository}/ api_base_url=${STACKDOME_API_BASE_URL:-https://api.github.com} version=${STACKDOME_VERSION:-} install_dir=${STACKDOME_INSTALL_DIR:-} +modify_path=true tmp_dir= staged_binary= @@ -19,6 +20,7 @@ Install the Stackdome CLI on macOS or Linux. Options: --version Install a specific release (for example, v0.0.2-alpha) --install-dir Install stackdome into this directory + --no-modify-path Do not persist the install directory in PATH -h, --help Show this help Environment: @@ -54,6 +56,90 @@ download() { fi } +path_contains() { + target_path=$1 + old_ifs=$IFS + IFS=: + glob_was_disabled=false + case $- in + *f*) glob_was_disabled=true ;; + *) set -f ;; + esac + + path_found=false + for path_entry in ${PATH:-}; do + if [ "$path_entry" = "$target_path" ]; then + path_found=true + break + fi + done + + [ "$glob_was_disabled" = true ] || set +f + IFS=$old_ifs + [ "$path_found" = true ] +} + +quote_for_shell() { + printf '%s' "$1" | sed "s/'/'\"'\"'/g" +} + +append_line_once() { + destination=$1 + line=$2 + + if [ -f "$destination" ] && grep -Fqx "$line" "$destination"; then + return 0 + fi + printf '\n# Added by the Stackdome CLI installer\n%s\n' "$line" >>"$destination" +} + +persist_path() { + if [ -n "${GITHUB_PATH:-}" ]; then + if ! grep -Fqx "$install_dir" "$GITHUB_PATH" 2>/dev/null; then + printf '%s\n' "$install_dir" >>"$GITHUB_PATH" || return 1 + fi + path_config_file=$GITHUB_PATH + return 0 + fi + + [ -n "${HOME:-}" ] || return 1 + [ "$install_dir" = "$HOME/.local/bin" ] || return 1 + + shell_path=${SHELL:-} + shell_name=${shell_path##*/} + case "$shell_name" in + zsh) + profile_dir=${ZDOTDIR:-$HOME} + profile=$profile_dir/.zshrc + ;; + bash) + profile_dir=$HOME + if [ "$os" = darwin ]; then + if [ -f "$HOME/.bash_profile" ]; then + profile=$HOME/.bash_profile + elif [ -f "$HOME/.bash_login" ]; then + profile=$HOME/.bash_login + elif [ -f "$HOME/.profile" ]; then + profile=$HOME/.profile + else + profile=$HOME/.bash_profile + fi + else + profile=$HOME/.bashrc + fi + ;; + sh | dash | ksh) + profile_dir=$HOME + profile=$HOME/.profile + ;; + *) return 1 ;; + esac + + mkdir -p "$profile_dir" || return 1 + append_line_once "$profile" 'export PATH="$HOME/.local/bin:$PATH"' || return 1 + path_config_file=$profile +} + while [ "$#" -gt 0 ]; do case "$1" in --version) @@ -66,6 +152,10 @@ while [ "$#" -gt 0 ]; do install_dir=$2 shift 2 ;; + --no-modify-path) + modify_path=false + shift + ;; -h | --help) usage exit 0 @@ -93,8 +183,12 @@ esac if [ -n "$install_dir" ]; then : -elif [ -d /usr/local/bin ] && [ -w /usr/local/bin ]; then +elif path_contains /usr/local/bin && [ -d /usr/local/bin ] && [ -w /usr/local/bin ]; then install_dir=/usr/local/bin +elif [ -n "${HOME:-}" ] && path_contains "$HOME/.local/bin"; then + install_dir=$HOME/.local/bin +elif [ -n "${HOME:-}" ] && path_contains "$HOME/bin" && [ -d "$HOME/bin" ] && [ -w "$HOME/bin" ]; then + install_dir=$HOME/bin else [ -n "${HOME:-}" ] || fail "HOME is not set; set STACKDOME_INSTALL_DIR" install_dir=$HOME/.local/bin @@ -148,7 +242,16 @@ mv -f "$staged_binary" "$install_dir/stackdome" || fail "could not install stack staged_binary= printf 'Installed Stackdome CLI %s to %s/stackdome\n' "$version" "$install_dir" -case ":${PATH:-}:" in - *":$install_dir:"*) ;; - *) printf 'warning: %s is not on your PATH; add it before running stackdome\n' "$install_dir" >&2 ;; -esac +if ! path_contains "$install_dir"; then + path_config_file= + if [ "$modify_path" = true ] && persist_path; then + printf 'Configured %s in PATH via %s.\n' "$install_dir" "$path_config_file" >&2 + elif [ "$modify_path" = true ]; then + printf 'warning: %s is not on your PATH; add it before running stackdome\n' "$install_dir" >&2 + else + printf 'PATH modification skipped by --no-modify-path.\n' >&2 + fi + printf 'Run this command to use stackdome in the current shell:\n' >&2 + quoted_install_dir=$(quote_for_shell "$install_dir") + printf ' export PATH='"'"'%s'"'"':"$PATH"\n' "$quoted_install_dir" >&2 +fi