Atomic rehash

This commit is contained in:
Sam Stephenson 2011-08-15 01:16:13 -05:00
parent 3efdf6a243
commit dd8a005c7d

View file

@ -1,31 +1,67 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e 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() { create_prototype_shim() {
cat > .rbenv-shim <<SH cat > "$PROTOTYPE_SHIM_PATH" <<SH
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
exec rbenv exec "\${0##*/}" "\$@" exec rbenv exec "\${0##*/}" "\$@"
SH SH
chmod +x .rbenv-shim chmod +x "$PROTOTYPE_SHIM_PATH"
} }
# Make shims by iterating over every filename argument and creating a
# hard link from the prototype shim to a file of the same name in the
# shims directory, if one does not already exist.
make_shims() { make_shims() {
local glob="$@" local glob="$@"
for file in $glob; do for file in $glob; do
local shim="${file##*/}" local shim="${file##*/}"
[ -e "$shim" ] || ln -f .rbenv-shim "$shim" [ -e "$shim" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$shim"
done done
} }
mkdir -p "${HOME}/.rbenv/shims" # Empty out the shims directory and make it the working directory.
cd "${HOME}/.rbenv/shims" rm -f "$SHIM_PATH"/*
rm -f * cd "$SHIM_PATH"
# Create the prototype shim, then make shims for all known binaries.
create_prototype_shim create_prototype_shim
make_shims ../versions/*/bin/* make_shims ../versions/*/bin/*
# Find and run any plugins that might want to make shims too.
shopt -s nullglob shopt -s nullglob
RBENV_REHASH_PLUGINS=(/etc/rbenv.d/rehash/*.bash ${HOME}/.rbenv/rbenv.d/rehash/*.bash) RBENV_REHASH_PLUGINS=(/etc/rbenv.d/rehash/*.bash ${HOME}/.rbenv/rbenv.d/rehash/*.bash)
shopt -u nullglob shopt -u nullglob
@ -33,5 +69,3 @@ shopt -u nullglob
for script in ${RBENV_REHASH_PLUGINS[@]}; do for script in ${RBENV_REHASH_PLUGINS[@]}; do
source $script source $script
done done
rm -f .rbenv-shim