diff --git a/libexec/rbenv-exec b/libexec/rbenv-exec index e05ce5110..2de3274b7 100755 --- a/libexec/rbenv-exec +++ b/libexec/rbenv-exec @@ -1,17 +1,21 @@ #!/usr/bin/env bash # -# Summary: Run an executable with the selected Ruby version +# Summary: Run an executable with the current Ruby version # -# Usage: rbenv exec [arg1 arg2...] +# Usage: rbenv exec [...] # -# Runs an executable by first preparing PATH so that the selected Ruby -# version's `bin' directory is at the front. +# Runs an executable by first prepending the current Ruby version's +# `bin' directory to PATH. # -# For example, if the currently selected Ruby version is 1.9.3-p327: -# rbenv exec bundle install +# For example, this invocation: # -# is equivalent to: -# PATH="$RBENV_ROOT/versions/1.9.3-p327/bin:$PATH" bundle install +# RBENV_VERSION=3.1.2 rbenv exec bundle install +# +# roughly translates to: +# +# PATH="$RBENV_ROOT/versions/3.1.2/bin:$PATH" bundle install +# +# See `rbenv help which' for information about the fallback mechanism. set -e [ -n "$RBENV_DEBUG" ] && set -x @@ -41,7 +45,7 @@ for script in "${scripts[@]}"; do done shift 1 -if [ "$RBENV_VERSION" != "system" ]; then +if [ "$RBENV_BIN_PATH" = "${RBENV_ROOT}/versions/${RBENV_VERSION}/bin" ]; then export PATH="${RBENV_BIN_PATH}:${PATH}" fi exec -a "$RBENV_COMMAND" "$RBENV_COMMAND_PATH" "$@" diff --git a/libexec/rbenv-which b/libexec/rbenv-which index 80f0df87e..c917c3b35 100755 --- a/libexec/rbenv-which +++ b/libexec/rbenv-which @@ -6,6 +6,17 @@ # # Displays the full path to the executable that rbenv will invoke when # you run the given command. +# +# If GEM_HOME is set, the result will be `$GEM_HOME/bin/' if +# it exists. +# +# If the current Ruby version is "system", the command will be looked up +# in PATH. +# +# For other Ruby versions, the command is first looked up in +# `$RBENV_ROOT/versions/$RBENV_VERSION/bin'. If it does not exist and if +# the command is not one of the core Ruby executables (e.g. "ruby", +# "gem", "bundle"), it will be looked up in PATH. set -e [ -n "$RBENV_DEBUG" ] && set -x @@ -36,15 +47,28 @@ fi RBENV_VERSION="${RBENV_VERSION:-$(rbenv-version-name)}" -if [ "$RBENV_VERSION" = "system" ]; then - PATH="$(remove_from_path "${RBENV_ROOT}/shims")" \ - RBENV_COMMAND_PATH="$(command -v "$RBENV_COMMAND" || true)" +if [[ -n "$GEM_HOME" && -x "${GEM_HOME}/bin/${RBENV_COMMAND}" ]]; then + RBENV_COMMAND_PATH="${GEM_HOME}/bin/${RBENV_COMMAND}" +elif [ "$RBENV_VERSION" = "system" ]; then + PATH="$(remove_from_path "${RBENV_ROOT}/shims")" RBENV_COMMAND_PATH="$(type -P "$RBENV_COMMAND" || true)" else RBENV_COMMAND_PATH="${RBENV_ROOT}/versions/${RBENV_VERSION}/bin/${RBENV_COMMAND}" -fi - -if [[ ! -x "$RBENV_COMMAND_PATH" && -n "$GEM_HOME" && -x "${GEM_HOME}/bin/${RBENV_COMMAND}" ]]; then - RBENV_COMMAND_PATH="${GEM_HOME}/bin/${RBENV_COMMAND}" + if [ ! -x "$RBENV_COMMAND_PATH" ]; then + # Look up the command in PATH as fallback. + case "$RBENV_COMMAND" in + ruby | rake | gem | bundle | bundler | irb | rdoc | ri ) + # Do not allow fallback to PATH for core Ruby commands. If any of these are missing + # in the current Ruby version, error out instead of allowing a potentially unrelated + # Ruby version to activate and potentially muck up the current project. + ;; + * ) + if PATH="$(remove_from_path "${RBENV_ROOT}/shims")" RBENV_COMMAND_FALLBACK="$(type -P "$RBENV_COMMAND")"; then + RBENV_COMMAND_PATH="$RBENV_COMMAND_FALLBACK" + fi + unset RBENV_COMMAND_FALLBACK + ;; + esac + fi fi OLDIFS="$IFS" diff --git a/test/exec.bats b/test/exec.bats index 1ee743578..7b33fd8a2 100644 --- a/test/exec.bats +++ b/test/exec.bats @@ -15,8 +15,7 @@ create_executable() { } @test "fails with invalid version" { - export RBENV_VERSION="2.0" - run rbenv-exec ruby -v + RBENV_VERSION="2.0" run rbenv-exec ruby -v assert_failure "rbenv: version \`2.0' is not installed (set by RBENV_VERSION environment variable)" } @@ -29,6 +28,7 @@ create_executable() { } @test "completes with names of executables" { + # shellcheck disable=SC2030,SC2031 export RBENV_VERSION="2.0" create_executable "ruby" "#!/bin/sh" create_executable "rake" "#!/bin/sh" @@ -49,13 +49,13 @@ hellos=(\$(printf "hello\\tugly world\\nagain")) echo HELLO="\$(printf ":%s" "\${hellos[@]}")" SH - export RBENV_VERSION=system - IFS=$' \t\n' run rbenv-exec env + RBENV_VERSION=system IFS=$' \t\n' run rbenv-exec env assert_success assert_line "HELLO=:hello:ugly:world:again" } @test "forwards all arguments" { + # shellcheck disable=SC2030,SC2031 export RBENV_VERSION="2.0" create_executable "ruby" <" { + # shellcheck disable=SC2030,SC2031 export RBENV_VERSION="2.0" # emulate `ruby -S' behavior