Enable fallback to PATH from rbenv shims

Previously, when someone activated rbenv shim `foo`, rbenv would error out if `RBENV_ROOT/versions/RBENV_VERSION/bin/foo` did not exist.

This change allows `foo` to be additionally looked up in PATH as fallback. This prevents a case where one of the Ruby versions is shadowing a system-wide command of the same name, preventing the use of the global command across all other Ruby versions.

rbenv used to be strict around this, allowing the fallback to avoid ever falling back to system Ruby for invocations like `bundle` if the current Ruby version did not yet install Bundler. The current approach prevents this scenario by explicitly disallowing fallback for the following executables: ruby, rake, gem, bundle, bundler, irb, rdoc, ri.
This commit is contained in:
Mislav Marohnić 2022-10-07 16:16:34 +02:00
parent 6b1cc34610
commit 5ce2fd8a2f
No known key found for this signature in database
3 changed files with 64 additions and 16 deletions

View file

@ -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 <command> [arg1 arg2...]
# Usage: rbenv exec <command> [<args>...]
#
# 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" "$@"

View file

@ -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/<command>' 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"

View file

@ -78,6 +78,26 @@ ${RBENV_ROOT}/versions/2.0/bin/ruby
OUT
}
@test "prepends Ruby to PATH" {
export RBENV_VERSION="2.0"
create_executable "ruby" <<SH
#!$BASH
echo \$PATH
SH
run rbenv-exec ruby
assert_success
[[ $output == "${RBENV_ROOT}/versions/${RBENV_VERSION}/bin:"* ]]
}
@test "does not modify PATH for fallback" {
export RBENV_VERSION="2.0"
create_executable "ruby" "#!/bin/sh"
run rbenv-exec bash -c 'echo $PATH'
assert_success "$PATH"
}
@test "supports ruby -S <cmd>" {
export RBENV_VERSION="2.0"