Avoid running rbenv rehash multiple times during bundle install

This is an attempt to work around the fact that Rubygems post_install
hooks may happen multiple times per single `bundle install` and ideally
we want `rbenv rehash` to run only once if new gems have been installed.
However, due to Bundler parallelism using `fork` on platforms that
support it, it's impossible for the child processes to communicate with
the master process to signal it to run `rbenv rehash` in the end.

This hooks into Bundler `install` command and runs `rbenv rehash` after
all gems have finished installing, but only if the install location was
system gems location and not a custom path (such as per-project
`vendor/bundle`).

This is limited because we can't tell whether any gems have been
installed at all, let alone do those gems have executables. However it's
better than having multiple `rbenv rehash` being run in parallel and
outputting confusing error messages as a result.
This commit is contained in:
Mislav Marohnić 2014-10-19 13:43:29 +02:00
parent 8dcd715ede
commit 7b289bcee6

View file

@ -6,13 +6,32 @@ hook = lambda do |installer|
`rbenv rehash`
end
rescue
warn "rbenv: error in gem-rehash (#{$!})"
warn "rbenv: error in gem-rehash (#{$!.class.name}: #{$!.message})"
end
end
begin
Gem.post_install(&hook)
Gem.post_uninstall(&hook)
rescue
warn "rbenv: error installing gem-rehash hooks (#{$!})"
if defined?(Bundler::Installer) && Bundler::Installer.respond_to?(:install)
Bundler::Installer.class_eval do
class << self
alias install_without_rbenv_rehash install
def install(root, definition, options = {})
result = install_without_rbenv_rehash(root, definition, options)
begin
if result && Gem.default_path.include?(Bundler.bundle_path.to_s)
`rbenv rehash`
end
rescue
warn "rbenv: error in Bundler post-install hook (#{$!.class.name}: #{$!.message})"
end
result
end
end
end
else
begin
Gem.post_install(&hook)
Gem.post_uninstall(&hook)
rescue
warn "rbenv: error installing gem-rehash hooks (#{$!.class.name}: #{$!.message})"
end
end