Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

bundle-exec and binstubs inconsistent #4780

Closed
randomstuff opened this issue Jul 12, 2016 · 9 comments
Closed

bundle-exec and binstubs inconsistent #4780

randomstuff opened this issue Jul 12, 2016 · 9 comments

Comments

@randomstuff
Copy link

The manpage of bundle-exec claims that:

If you use the --binstubs flag in bundle install(1), Bundler will automatically create a directory
(which defaults to app_root/bin) containing all of the executables available from gems
in the bundle.

After using --binstubs, bin/rspec spec/my_spec.rb is identical to bundle exec rspec spec/my_spec.rb.

It does not seem to be completely accurate:

$ ./bin/puppet --version
3.7.5
$ bundle exec puppet --version
4.5.2

where 3.7.5 comes from Bundler (bundle install --path vendor/bundle --binstubs) and 4.5.2 comes from the system.

Differences in term of environment:

-_=./bin/puppet
+_=/usr/bin/bundle
-GEM_HOME=/home/foo/bar/vendor/bundle/ruby/2.3.0
-GEM_PATH=
-BUNDLE_BIN_PATH=/usr/lib/ruby/exe/bundle
+BUNDLE_BIN_PATH=/usr/share/rubygems-integration/all/gems/bundler-1.12.5/exe/bundle
-MANPATH=/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/puppet-3.7.5/man
@indirect
Copy link
Member

That is definitely a bug. What is /usr/share/rubygems-integration, what Ruby version manager are you using, and what is the output of bundle env?

@randomstuff
Copy link
Author

I'm using ruby and bundler shipped as Debian packages without any Ruby version manager. rubygem-integrations is a Debian package which:

makes Debian Ruby packages recognizable by Rubygems. Debian Ruby packages may be
used to satisfy Rubygems dependencies both with plain Rubygems and with Bundler.
This also allows one to use Debian Ruby packages to satisfy dependencies in Rails 3 applications.

So it's possible the bug might be in the Debian packaging.

bundle env gives:

Environment
    Bundler   1.12.5
    Rubygems  2.5.1
    Ruby      2.3.1p112 (2016-04-26 revision 0) [x86_64-linux-gnu]
    Git       2.8.1
Bundler settings
    path
      Set for your local app (/home/foo/bar/.bundle/config): "vendor/bundle"
    bin
      Set for your local app (/home/foo/bar/.bundle/config): "bin"
    disable_shared_gems
      Set for your local app (/home/foo/bar/.bundle/config): "true"
    orig_path
      Set via BUNDLE_ORIG_PATH: "/home/foo/.cabal/bin:/home/foo/.bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
Gemfile
    source 'https://rubygems.org'
    
    gem 'puppet', '~> 3.7.2'
    gem 'hiera', '~> 1.3.4'
    gem 'hiera-puppet', '~> 1.0.0'
    gem 'r10k', '~> 1.1.4'
    
    # vim:ft=ruby
Gemfile.lock
    GEM
      remote: https://rubygems.org/
      specs:
        CFPropertyList (2.2.8)
        colored (1.2)
        cri (2.4.1)
          colored (>= 1.2)
        facter (2.4.6)
          CFPropertyList (~> 2.2.6)
        hiera (1.3.4)
          json_pure
        hiera-puppet (1.0.0)
          hiera (~> 1.0)
        json_pure (2.0.1)
        log4r (1.1.10)
        puppet (3.7.5)
          facter (> 1.6, < 3)
          hiera (~> 1.0)
          json_pure
        r10k (1.1.4)
          colored (>= 1.2)
          cri (~> 2.4.0)
          json_pure
          log4r (>= 1.1.10)
          systemu (~> 2.5.2)
        systemu (2.5.2)
    
    PLATFORMS
      ruby
    
    DEPENDENCIES
      hiera (~> 1.3.4)
      hiera-puppet (~> 1.0.0)
      puppet (~> 3.7.2)
      r10k (~> 1.1.4)
    
    BUNDLED WITH
       1.12.5

@randomstuff
Copy link
Author

randomstuff commented Jul 12, 2016

I could not reproduce this with rbenv:

val "$(rbenv init -)"
# See https://github.com/rbenv/ruby-build/wiki#openssl-sslv3_method-undeclared-error
wget https://gist.githubusercontent.com/mislav/055441129184a1512bb5/raw
cat raw | rbenv install --patch 2.2.3
rbenv global 2.2.3
gem install bundler
gem env home  # /home/foo/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0
rbenv rehash
which bundle # /home/foo/.rbenv/shims/bundle
cat > Gemfile <<EOF
source 'https://rubygems.org'
gem 'puppet', '~> 3.7.2'
gem 'hiera', '~> 1.3.4'
gem 'hiera-puppet', '~> 1.0.0'
gem 'r10k', '~> 1.1.4'
EOF
bundle install --path vendor/bundler --binstubs
# Horrible hack for https://tickets.puppetlabs.com/browse/PUP-3796:
touch vendor/bundler/ruby/2.2.0/gems/puppet-3.7.5/lib/puppet/vendor/safe_yaml/lib/safe_yaml/syck_node_monkeypatch.rb
./bin/puppet --version       # 3.7.5
bundle exec puppet --version # 3.7.5
gem install puppet           # Installing 4.5.2
rbenv rehash
puppet --version             # 4.5.2
./bin/puppet --version       # 3.7.5
bundle exec puppet --version # 3.7.5

@indirect
Copy link
Member

I'm going to say that this seems like an issue with how debian packages ruby, then :/ Sorry I can't be more helpful than that!

@randomstuff
Copy link
Author

I investigated a bit the problem. The difference between the two commands lies in the ordering/initialization of the $LOAD_PATH.

With ./bin/puppet:

["/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/r10k-1.1.4/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/systemu-2.5.2/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/puppet-3.7.5/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/log4r-1.1.10/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/hiera-puppet-1.0.0/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/hiera-1.3.4/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/json_pure-2.0.1/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/facter-2.4.6/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/cri-2.4.1/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/colored-1.2/lib", "/usr/lib/ruby/vendor_ruby/gems/bundler-1.12.5/lib", "/usr/local/lib/site_ruby/2.3.0", "/usr/local/lib/x86_64-linux-gnu/site_ruby", "/usr/local/lib/site_ruby", "/usr/lib/ruby/vendor_ruby/2.3.0", "/usr/lib/x86_64-linux-gnu/ruby/vendor_ruby/2.3.0", "/usr/lib/ruby/vendor_ruby", "/usr/lib/ruby/2.3.0", "/usr/lib/x86_64-linux-gnu/ruby/2.3.0"]

With bundle exec:

["/usr/lib/ruby/vendor_ruby", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/r10k-1.1.4/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/systemu-2.5.2/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/puppet-3.7.5/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/log4r-1.1.10/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/hiera-puppet-1.0.0/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/hiera-1.3.4/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/json_pure-2.0.1/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/facter-2.4.6/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/cri-2.4.1/lib", "/home/foo/bar/vendor/bundle/ruby/2.3.0/gems/colored-1.2/lib", "/usr/lib/ruby/vendor_ruby/gems/bundler-1.12.5/lib", "/usr/local/lib/site_ruby/2.3.0", "/usr/local/lib/x86_64-linux-gnu/site_ruby", "/usr/local/lib/site_ruby", "/usr/lib/ruby/vendor_ruby/2.3.0", "/usr/lib/x86_64-linux-gnu/ruby/vendor_ruby/2.3.0", "/usr/lib/ruby/2.3.0", "/usr/lib/x86_64-linux-gnu/ruby/2.3.0"]

Debian ships packaged ruby libraries in /usr/lib/ruby/vendor_ruby. So with bundle exec the Puppet installed in /usr/lib/ruby/vendor_ruby gets loaded instead of the one in /home/foo/bar/vendor/bundle/ruby/2.3.0/gems/puppet-3.7.5/lib.

Bundler sets RUBYLIB=/usr/lib/ruby/vendor_ruby which is expected to:

Directories from this environment variable are searched before
the standard load path is searched.

In pratice what happens, is that when the Ruby interpreter initializes itself, it prepends the values from RUBYLIB into $LOAD_PATH:

  • when executing the binstub Bundler sets RUBYLIB (in require "bundler/setup") but the Ruby interpreter is already initialized and it is not prepended to $LOAD_PATH;
  • when executing bundle exec, Bundlet sets RUBYLIB and then exec a new Ruby interpreter. This Ruby interpreter sees RUBYLIB and prepends it to $LOAD_PATH

The $LOAD_PATH are different when using the binstubs and when using bundle exec which might lead to different results. The problems happens because Debian ships ruby packages in /usr/lib/ruby/vendor_ruby but still the problem is related to the fact that the two ways of executing Bundler-installed binaries result in a different $LOAD_PATH which might be seen as a bug in Bundler (?).

@randomstuff
Copy link
Author

Bundler adds /usr/lib/ruby/vendor_ruby to RUBYLIB because it is installed in /usr/lib/ruby/vendor_ruby and does (in bundler$ less shared_helpers):

def set_rubylib
  rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR)
  rubylib.unshift File.expand_path("../..", __FILE__)
  ENV["RUBYLIB"] = rubylib.uniq.join(File::PATH_SEPARATOR)
end

@segiddins
Copy link
Member

Why isn't bundler being installed into your gem home?

@randomstuff
Copy link
Author

@segiddins Yes, that's a solution. As Debian provides a package for it which I expected it to work. Now maybe, your answer will be « Well this is Debian's fault. Bundler should be installed alone in its own directory. » (as it happens when installing Bundler with gem and the issue I'm describing won't happen in this case) In this case I'd be totally happy and tell the Debian packagers about it :)

@randomstuff
Copy link
Author

Fo reference, I submitted a bug in Debian which has been closed with this fix:

Do not add system path to RUBYLIB.
Bundler adds it's own installation path in front of RUBYLIB, but when
this is the system ruby path, this causes system-wide installed gems
to be used before bundler-installed gems.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants