From a8df5d587cb8da3537bd0ecbb11ac6016828c75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Wed, 15 Oct 2014 03:39:04 +0200 Subject: [PATCH 1/3] Avoid changing directories during rehash process --- libexec/rbenv-rehash | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/libexec/rbenv-rehash b/libexec/rbenv-rehash index 5ec195ec..d89af7fa 100755 --- a/libexec/rbenv-rehash +++ b/libexec/rbenv-rehash @@ -70,9 +70,10 @@ SH # of the first shim in the shims directory, assume rbenv has been # upgraded and the existing shims need to be removed. remove_outdated_shims() { - for shim in *; do + local shim + for shim in "$SHIM_PATH"/*; do if ! diff "$PROTOTYPE_SHIM_PATH" "$shim" >/dev/null 2>&1; then - for shim in *; do rm -f "$shim"; done + rm -f "$SHIM_PATH"/* fi break done @@ -82,10 +83,9 @@ remove_outdated_shims() { # registered for installation as a shim. In this way, plugins may call # `make_shims` with a glob to register many shims at once. make_shims() { - local shims=("$@") - - for file in "${shims[@]}"; do - local shim="${file##*/}" + local file shim + for file; do + shim="${file##*/}" register_shim "$shim" done } @@ -110,9 +110,10 @@ register_shim() { # `registered_shims` array and create a link if one does not already # exist. install_registered_shims() { - local shim + local shim file for shim in "${registered_shims[@]}"; do - [ -e "$shim" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$shim" + file="${SHIM_PATH}/${shim}" + [ -e "$file" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$file" done } @@ -122,16 +123,13 @@ install_registered_shims() { # removed. remove_stale_shims() { local shim - for shim in *; do - if [[ "$registered_shims_index" != *"/$shim/"* ]]; then + for shim in "$SHIM_PATH"/*; do + if [[ "$registered_shims_index" != *"/${shim##*/}/"* ]]; then rm -f "$shim" fi done } - -# Change to the shims directory. -cd "$SHIM_PATH" shopt -s nullglob # Create the prototype shim, then register shims for all known @@ -140,8 +138,6 @@ create_prototype_shim remove_outdated_shims make_shims ../versions/*/bin/* -# Restore the previous working directory. -cd "$OLDPWD" # Allow plugins to register shims. OLDIFS="$IFS" @@ -152,8 +148,5 @@ for script in "${scripts[@]}"; do source "$script" done -# Change back to the shims directory to install the registered shims -# and remove stale shims. -cd "$SHIM_PATH" install_registered_shims remove_stale_shims From 89d4e8a0e0e16a4afd7c834d28d1ba21b81a8182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Wed, 15 Oct 2014 04:05:41 +0200 Subject: [PATCH 2/3] Speed up rehash process when there are many Ruby versions On my system that has 25 versions under rbenv, this speeds up rehash almost 3-fold: - before: 391 ms - after: 134 ms This is achieved by removing duplicate names of executables before registering them as shims. Since most Rubies will share a lot of the same executable names ("ruby", "rake", "bundle", ...), this is a considerable reduction in number of shims registered. --- libexec/rbenv-rehash | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libexec/rbenv-rehash b/libexec/rbenv-rehash index d89af7fa..df221e65 100755 --- a/libexec/rbenv-rehash +++ b/libexec/rbenv-rehash @@ -79,6 +79,14 @@ remove_outdated_shims() { done } +# List basenames of executables for every Ruby version +list_executable_names() { + local file + for file in "$RBENV_ROOT"/versions/*/bin/*; do + echo "${file##*/}" + done +} + # The basename of each argument passed to `make_shims` will be # registered for installation as a shim. In this way, plugins may call # `make_shims` with a glob to register many shims at once. @@ -136,7 +144,7 @@ shopt -s nullglob # executables. create_prototype_shim remove_outdated_shims -make_shims ../versions/*/bin/* +make_shims $(list_executable_names | sort -u) # Allow plugins to register shims. From 1381c2ca79dc515406f82cbac380706ad9c9ec55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Wed, 15 Oct 2014 05:12:28 +0200 Subject: [PATCH 3/3] Simplify the shims registration implementation in `rbenv-rehash` It doesn't need to be a bash array and we don't need a separate index of shims registered. Simply keep everything in a space-separated string and use that as an index as well. This assumes that executable names *never* have spaces in them. --- libexec/rbenv-rehash | 23 ++++++----------------- test/rehash.bats | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/libexec/rbenv-rehash b/libexec/rbenv-rehash index df221e65..19f9daa5 100755 --- a/libexec/rbenv-rehash +++ b/libexec/rbenv-rehash @@ -98,28 +98,17 @@ make_shims() { done } -# Create an empty array for the list of registered shims and an empty -# string to use as a search index. -registered_shims=() -registered_shims_index="" +registered_shims=" " -# We will keep track of shims registered for installation with the -# global `registered_shims` array and with a global search index -# string. The array will let us iterate over all registered shims. The -# index string will let us quickly check whether a shim with the given -# name has been registered or not. +# Registers the name of a shim to be generated. register_shim() { - local shim="$@" - registered_shims["${#registered_shims[@]}"]="$shim" - registered_shims_index="$registered_shims_index/$shim/" + registered_shims="${registered_shims}${1} " } -# To install all the registered shims, we iterate over the -# `registered_shims` array and create a link if one does not already -# exist. +# Install all the shims registered via `make_shims` or `register_shim` directly. install_registered_shims() { local shim file - for shim in "${registered_shims[@]}"; do + for shim in $registered_shims; do file="${SHIM_PATH}/${shim}" [ -e "$file" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$file" done @@ -132,7 +121,7 @@ install_registered_shims() { remove_stale_shims() { local shim for shim in "$SHIM_PATH"/*; do - if [[ "$registered_shims_index" != *"/${shim##*/}/"* ]]; then + if [[ "$registered_shims" != *" ${shim##*/} "* ]]; then rm -f "$shim" fi done diff --git a/test/rehash.bats b/test/rehash.bats index ba12a245..74f55a97 100755 --- a/test/rehash.bats +++ b/test/rehash.bats @@ -53,7 +53,7 @@ ruby OUT } -@test "removes stale shims" { +@test "removes outdated shims" { mkdir -p "${RBENV_ROOT}/shims" touch "${RBENV_ROOT}/shims/oldshim1" chmod +x "${RBENV_ROOT}/shims/oldshim1" @@ -67,6 +67,25 @@ OUT assert [ ! -e "${RBENV_ROOT}/shims/oldshim1" ] } +@test "do exact matches when removing stale shims" { + create_executable "2.0" "unicorn_rails" + create_executable "2.0" "rspec-core" + + rbenv-rehash + + cp "$RBENV_ROOT"/shims/{rspec-core,rspec} + cp "$RBENV_ROOT"/shims/{rspec-core,rails} + cp "$RBENV_ROOT"/shims/{rspec-core,uni} + chmod +x "$RBENV_ROOT"/shims/{rspec,rails,uni} + + run rbenv-rehash + assert_success "" + + assert [ ! -e "${RBENV_ROOT}/shims/rails" ] + assert [ ! -e "${RBENV_ROOT}/shims/rake" ] + assert [ ! -e "${RBENV_ROOT}/shims/uni" ] +} + @test "binary install locations containing spaces" { create_executable "dirname1 p247" "ruby" create_executable "dirname2 preview1" "rspec"