Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not use symlinks in GEM_PATH #4425

eregon opened this issue Jul 9, 2018 · 4 comments

Do not use symlinks in GEM_PATH #4425

eregon opened this issue Jul 9, 2018 · 4 comments


Copy link

eregon commented Jul 9, 2018


RVM uses symlinks in GEM_PATH.
For instance, I have GEM_PATH=~/.rvm/gems/truffleruby-1.0.0-rc3:~/.rvm/gems/truffleruby-1.0.0-rc3@global.
The problem is this makes everything more fragile, because all paths comparisons using values derived from GEM_PATH or Gem.path need to canonicalize those paths before comparison or they end up incorrect.

As in example, bundle exec is broken with latest RVM for TruffleRuby and JRuby 9.2.
MRI is lucky and avoids the problem due to Bundler being installed in site_ruby (a path without symlinks) due to the RubyGems update.
Of course, one could argue it's just a bug of Bundler 1.16.2, but this is unlikely to be the only instance relying on gems paths not having symlinks.

RVM is the only Ruby manager doing so AFAIK, and as such the only one to break in such a situation.

Steps to reproduce

  1. rvm install jruby-
  2. touch Rakefile Gemflie
  3. bundle exec rake

The same happens with rvm install truffleruby.

Recent RVM installs bundler in the @global gemset (which has a path with symlinks in GEM_PATH), which triggers this problem.

Expected behavior

That bundle exec rake works.

Actual behavior

$ rvm install jruby-
$ bundle exec rake
bundler: failed to load command: rake (/home/eregon/.rvm/gems/jruby-
LoadError: no such file to load -- bundler/ruby_version
  /home/eregon/.rvm/rubies/jruby- `metadata_dependencies'
  /home/eregon/.rvm/rubies/jruby- `expanded_dependencies'
  /home/eregon/.rvm/rubies/jruby- `resolve'
  /home/eregon/.rvm/rubies/jruby- `specs'
  /home/eregon/.rvm/rubies/jruby- `specs_for'
  /home/eregon/.rvm/rubies/jruby- `requested_specs'
  /home/eregon/.rvm/rubies/jruby- `block in requested_specs'
  /home/eregon/.rvm/rubies/jruby- `setup'
  /home/eregon/.rvm/rubies/jruby- `setup'
  /home/eregon/.rvm/rubies/jruby- `<main>'
  org/jruby/ `require'
  /home/eregon/.rvm/rubies/jruby- `require'
$ rvm install truffleruby
$ bundle exec rake
/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler.rb:70:in `ui': cannot load such file -- bundler/ui (LoadError)
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/definition.rb:253:in `resolve'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/definition.rb:171:in `specs'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/definition.rb:238:in `specs_for'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/definition.rb:227:in `requested_specs'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/runtime.rb:108:in `send'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/runtime.rb:108:in `requested_specs'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/runtime.rb:20:in `setup'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/patches/bundler/bundler/runtime.rb:9:in `setup'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler.rb:107:in `setup'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0/gems/bundler-1.16.2/lib/bundler/setup.rb:10:in `<top (required)>'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/mri/rubygems/core_ext/kernel_require.rb:133:in `gem_original_require'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/mri/rubygems/core_ext/kernel_require.rb:133:in `require'
	from /home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/lib/truffle/truffle/lazy-rubygems.rb:23:in `require'
	from /home/eregon/.rvm/gems/truffleruby-1.0.0-rc3@global/bin/truffleruby_executable_hooks:1:in `<main>'

Environment info


    uname:        "Linux localhost.localdomain 4.13.12-200.fc26.x86_64 #1 SMP Wed Nov 8 16:47:26 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux"
    name:         "Fedora"
    version:      "26"
    architecture: "x86_64"
    bash:         "/usr/bin/bash => GNU bash, version 4.4.12(1)-release (x86_64-redhat-linux-gnu)"
    zsh:          "/usr/bin/zsh => zsh 5.3.1 (x86_64-redhat-linux-gnu)"
    remote_path:  "fedora/26/x86_64"

    version:      "1.29.4 (master)"
    updated:      "12 minutes 31 seconds ago"
    path:         "/home/eregon/.rvm"
    autolibs:     "[4] Allow RVM to use package manager if found, install missing dependencies, install package manager (only OS X)."

    interpreter:  "truffleruby"
    version:      "1.0.0-rc3,"
    date:         "truffleruby 1.0.0-rc3, like ruby 2.4.4, GraalVM CE Native [x86_64-linux]"
    platform:     "x86_64-linux"
    patchlevel:   "truffleruby 1.0.0-rc3, like ruby 2.4.4, GraalVM CE Native [x86_64-linux]"
    full_version: "truffleruby 1.0.0-rc3, like ruby 2.4.4, GraalVM CE Native [x86_64-linux]"

    gem:          "/home/eregon/.rvm/gems/truffleruby-1.0.0-rc3"
    ruby:         "/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3"

    ruby:         "/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/bin/ruby"
    irb:          "/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/bin/irb"
    gem:          "/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/bin/gem"
    rake:         "/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/bin/rake"

    PATH:         "/home/eregon/.rvm/gems/truffleruby-1.0.0-rc3/bin:/home/eregon/.rvm/gems/truffleruby-1.0.0-rc3@global/bin:/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/bin:/home/eregon/.rvm/bin:/home/eregon/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/home/eregon/code/mx:/home/eregon/code/mspec/bin:/opt/crystal/bin"
    GEM_HOME:     "/home/eregon/.rvm/gems/truffleruby-1.0.0-rc3"
    GEM_PATH:     "/home/eregon/.rvm/gems/truffleruby-1.0.0-rc3:/home/eregon/.rvm/gems/truffleruby-1.0.0-rc3@global"
    MY_RUBY_HOME: "/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3"
    IRBRC:        "/home/eregon/.rvm/rubies/truffleruby-1.0.0-rc3/.irbrc"
    RUBYOPT:      ""
    gemset:       ""
Copy link
Contributor Author

eregon commented Jul 9, 2018

#4386 is very likely related to this issue by using symlinks in GEM_PATH for the global gemset.

The original issue reported to TruffleRuby: oracle/truffleruby#1383
The issue reported to JRuby: jruby/jruby#5240
The issue reported to Bundler: rubygems/bundler#6465

Copy link
Contributor Author

eregon commented Jul 9, 2018

Note that an easy workaround in this case in to re-install Bundler manually in the default gemset with:

rvm use myruby
gem install bundler
bundle exec rake # works

and that works because the default gemset is not a symlink.

Copy link
Contributor Author

eregon commented Jul 9, 2018

I tried fixing this myself but it seems a bit complicated.

Adding __rvm_readlink_deep rvm_ruby_global_gems_path and __rvm_readlink_deep rvm_ruby_gem_home in __rvm_gemset_select_only() expands the paths as expected, before setting GEM_HOME and GEM_PATH.

However, with that RVM is unable to find the current gemset with __rvm_current_gemset which just tries to parse GEM_HOME after the @.

I therefore tried something like this:

diff --git a/scripts/functions/gemset b/scripts/functions/gemset
index 5f8789c9..321496c5 100644
--- a/scripts/functions/gemset
+++ b/scripts/functions/gemset
@@ -3,17 +3,17 @@
   # Fetch the current gemset via GEM_HOME
-  \typeset current_gemset
-  current_gemset="${GEM_HOME:-}"
-  # We only care about the stuff to the right of the separator.
-  current_gemset="${current_gemset##*${rvm_gemset_separator:-@}}"
+  rvm_ruby_gem_home="${rvm_gems_path:-"$rvm_path/gems"}/$rvm_ruby_string"
+  for gemset in ${rvm_ruby_gem_home}*; do
+    echo "$gemset" 1>&2
+    __rvm_readlink_deep gemset
+    if [[ "${gemset}" == "${GEM_HOME:-}" ]] ; then
+      echo "${current_gemset}"
+      return
+    fi
+  done

-  if [[ "${current_gemset}" == "${GEM_HOME:-}" ]] ; then
-    echo ''
-  else
-    echo "${current_gemset}"
-  fi
+  echo ''

But that doesn't seem to work as $rvm_ruby_string is set to a wrong value like ruby-2.4.0 (and not truffleruby-1.0.0-rc3). I guess this value of $rvm_ruby_string somehow comes from the end of GEM_HOME which is ~/.rvm/rubies/truffleruby-1.0.0-rc3/lib/ruby/gems/2.4.0.

Copy link
Contributor Author

eregon commented Jul 16, 2018

I made a Pull Request to RubyGems which was merged rubygems/rubygems#2352.
This expands symlinks when reading the environment variables, which seems the perfect place to do it.

I wish RVM would not put symlinks in GEM_HOME/GEM_PATH in the first place, as this could still cause issues (on older RubyGems versions, and on other places that read these environment variables).
But given the current assumptions of the code and how the symlinks are used to detect the current gemset, this seems unlikely to happen, so I'll close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet

No branches or pull requests

2 participants