diff --git a/libexec/rbenv-rehash b/libexec/rbenv-rehash index 0259fe1b..e1078fc8 100755 --- a/libexec/rbenv-rehash +++ b/libexec/rbenv-rehash @@ -1,31 +1,67 @@ #!/usr/bin/env bash set -e +SHIM_PATH="${HOME}/.rbenv/shims" +PROTOTYPE_SHIM_PATH="${SHIM_PATH}/.rbenv-shim" + +# Create the shims directory if it doesn't already exist. +mkdir -p "$SHIM_PATH" + +# Ensure only one instance of rbenv-rehash is running at a time by +# setting the shell's `noclobber` option and attempting to write to +# the prototype shim file. If the file already exists, print a warning +# to stderr and exit with a non-zero status. +set -o noclobber +{ echo > "$PROTOTYPE_SHIM_PATH" +} 2>/dev/null || +{ echo "rbenv: cannot rehash: $PROTOTYPE_SHIM_PATH exists" + exit 1 +} >&2 +set +o noclobber + +# If we were able to obtain a lock, register a trap to clean up the +# prototype shim when the process exits. +trap remove_prototype_shim SIGINT SIGTERM EXIT + +remove_prototype_shim() { + rm -f "$PROTOTYPE_SHIM_PATH" +} + +# The prototype shim file is a script that re-execs itself, passing +# its filename and any arguments to `rbenv exec`. This file is +# hard-linked for every binary and then removed. The linking technique +# is fast, uses less disk space than unique files, and also serves as +# a locking mechanism. create_prototype_shim() { - cat > .rbenv-shim < "$PROTOTYPE_SHIM_PATH" <