From 1afd8df50f551835f0fba3285a9b4e6da36b4a6c Mon Sep 17 00:00:00 2001 From: ojab Date: Thu, 3 May 2018 10:01:46 +0000 Subject: [PATCH 1/8] Use realpath in clean_load_path what happens next will shock you: ``` From: /real_path/.rvm/gems/ruby-2.5.1/gems/bundler-1.16.2/lib/bundler/shared_helpers.rb @ line 339 Bundler::SharedHelpers#clean_load_path: 330: def clean_load_path 331: # handle 1.9 where system gems are always on the load path 332: return unless defined?(::Gem) 333: 334: bundler_lib = bundler_ruby_lib 335: 336: loaded_gem_paths = Bundler.rubygems.loaded_gem_paths 337: 338: binding.pry => 339: $LOAD_PATH.reject! do |p| 340: path = File.expand_path(p) 341: path = File.realpath(path) if File.exist?(path) 342: next if path.start_with?(bundler_lib) 343: loaded_gem_paths.delete(p) 344: end 345: $LOAD_PATH.uniq! 346: end [1] pry(#)> bundler_lib => "/real_path/.rvm/gems/ruby-2.5.1/gems/bundler-1.16.2/lib" [2] pry(#)> loaded_gem_paths => ["/symlinked_path/.rvm/gems/ruby-2.5.1@global/gems/did_you_mean-1.2.0/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/bundler-1.16.2/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/byebug-10.0.2/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/extensions/x86_64-linux/2.5.0/byebug-10.0.2", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/coderay-1.1.2/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/method_source-0.9.0/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/pry-0.11.3/lib", "/symlinked_path/.rvm/gems/ruby-2.5.1/gems/pry-byebug-3.6.0/lib", "/real_path/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/fileutils-1.0.2/lib", "/real_path/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/gems/psych-3.0.2/lib", "/real_path/.rvm/rubies/ruby-2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-linux/2.5.0/psych-3.0.2"] ``` basically we're not rejecting `bundler_lib` because symlink there and real path in $LOAD_PATH Fixes #6465 --- .travis.yml | 2 +- lib/bundler/shared_helpers.rb | 6 ++++- spec/runtime/setup_spec.rb | 44 +++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 543df2bcda5..87b951665d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ addons: secure: "TrzIv116JLGUxm6PAUskCYrv8KTDguncKROVwbnjVPKTGDAgoDderd8JUdDEXrKoZ9qGLD2TPYKExt9/QDl71E+qHdWnVqWv4HKCUk2P9z/VLKzHuggOUBkCXiJUhjywUieCJhI3N92bfq2EjSBbu2/OFHqWOjLQ+QCooTEBjv8=" rvm: - - 2.5.0 + - 2.5.1 - 2.4.3 - 2.3.6 diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 45185209f14..1ae10afd07d 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -336,7 +336,11 @@ def clean_load_path loaded_gem_paths = Bundler.rubygems.loaded_gem_paths $LOAD_PATH.reject! do |p| - next if File.expand_path(p).start_with?(bundler_lib) + expanded_p = File.expand_path(p) + next if expanded_p.start_with?(bundler_lib) + if File.exist?(expanded_p) && File.respond_to?(:realpath) + next if File.realpath(expanded_p).start_with?(bundler_lib) + end loaded_gem_paths.delete(p) end $LOAD_PATH.uniq! diff --git a/spec/runtime/setup_spec.rb b/spec/runtime/setup_spec.rb index e84cdaabf5c..4f8e70f8eb3 100644 --- a/spec/runtime/setup_spec.rb +++ b/spec/runtime/setup_spec.rb @@ -857,6 +857,50 @@ def clean_load_path(lp) expect(out).to eq("true\ntrue") end + context "with bundler is located in symlinked GEM_HOME" do + let(:gem_home) { Dir.mktmpdir } + let(:symlinked_gem_home) { Tempfile.new("gem_home") } + let(:bundler_dir) { File.expand_path("../../..", __FILE__) } + let(:bundler_lib) { File.join(bundler_dir, "lib") } + + before do + FileUtils.ln_sf(gem_home, symlinked_gem_home.path) + gems_dir = File.join(gem_home, "gems") + specifications_dir = File.join(gem_home, "specifications") + Dir.mkdir(gems_dir) + Dir.mkdir(specifications_dir) + + FileUtils.ln_s(bundler_dir, File.join(gems_dir, "bundler-#{Bundler::VERSION}")) + + gemspec = File.read("#{bundler_dir}/bundler.gemspec"). + sub("Bundler::VERSION", %("#{Bundler::VERSION}")) + gemspec = gemspec.lines.reject {|line| line =~ %r{lib/bundler/version} }.join + + File.open(File.join(specifications_dir, "bundler.gemspec"), "wb") do |f| + f.write(gemspec) + end + end + + it "should succesfully require 'bundler/setup'" do + install_gemfile "" + + ENV["GEM_PATH"] = symlinked_gem_home.path + + ruby <<-R + if $LOAD_PATH.include?("#{bundler_lib}") + # We should use bundler from GEM_PATH for this test, so we should + # remove path to the bundler source tree + $LOAD_PATH.delete("#{bundler_lib}") + else + raise "We don't have #{bundler_lib} in $LOAD_PATH" + end + puts (require 'bundler/setup') + R + + expect(out).to eql("true") + end + end + it "stubs out Gem.refresh so it does not reveal system gems" do system_gems "rack-1.0.0" From e97d0d70bc22f889927c0df4edbbb9ef541575ba Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Mon, 9 Jul 2018 20:38:19 -0700 Subject: [PATCH 2/8] recursively follow symlinks --- lib/bundler/shared_helpers.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 1ae10afd07d..05928fc4d01 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -336,16 +336,18 @@ def clean_load_path loaded_gem_paths = Bundler.rubygems.loaded_gem_paths $LOAD_PATH.reject! do |p| - expanded_p = File.expand_path(p) - next if expanded_p.start_with?(bundler_lib) - if File.exist?(expanded_p) && File.respond_to?(:realpath) - next if File.realpath(expanded_p).start_with?(bundler_lib) - end + next if resolve_path(p).start_with?(bundler_lib) loaded_gem_paths.delete(p) end $LOAD_PATH.uniq! end + def resolve_path(path) + expanded = File.expand_path(path) + expanded = File.realpath(expanded) until expanded == File.realpath(expanded) + expanded + end + def prints_major_deprecations? require "bundler" deprecation_release = Bundler::VERSION.split(".").drop(1).include?("99") From 736c583936aa0a2f4fd70be4d8bb7208ce3fdd2d Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Mon, 9 Jul 2018 20:39:57 -0700 Subject: [PATCH 3/8] follow symlinks in bundler_ruby_lib as well --- lib/bundler/shared_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 05928fc4d01..08c6bed2121 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -324,7 +324,7 @@ def set_rubylib end def bundler_ruby_lib - File.expand_path("../..", __FILE__) + resolve_path File.expand_path("../..", __FILE__) end def clean_load_path From b91dd5da08d2e92378e169fe7ebeff20b26b01db Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Mon, 9 Jul 2018 21:16:18 -0700 Subject: [PATCH 4/8] prevent explosions on Ruby 1.8 --- lib/bundler/shared_helpers.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 08c6bed2121..e4cbbba2ba0 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -344,7 +344,11 @@ def clean_load_path def resolve_path(path) expanded = File.expand_path(path) - expanded = File.realpath(expanded) until expanded == File.realpath(expanded) + + if File.respond_to?(:realpath) + expanded = File.realpath(expanded) until expanded == File.realpath(expanded) + end + expanded end From ec39b742f0f6ace27302649ac63a57400fbaf454 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Mon, 9 Jul 2018 21:19:44 -0700 Subject: [PATCH 5/8] delete non-gem copies of Bundler in site_ruby --- spec/spec_helper.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 228b9e5aa3a..1685178a34e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,6 +12,13 @@ module Gem end end +# Delete any copies of Bundler that have been dumped into site_ruby without +# a gemspec. RubyGems cannot manage that Bundler, and so our tricks to make +# sure that the correct version of Bundler loads will stop working. +Dir.glob(File.join(RbConfig::CONFIG["sitelibdir"], "bundler*")).each do |f| + FileUtils.rm_rf f +end + begin require File.expand_path("../support/path.rb", __FILE__) spec = Gem::Specification.load(Spec::Path.gemspec.to_s) From 67f026cc6aa3d1fccae250f8243dafab1f96cf74 Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Mon, 9 Jul 2018 21:24:37 -0700 Subject: [PATCH 6/8] use FileUtils _after_ it is required --- spec/spec_helper.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1685178a34e..1d4d4b537e5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,13 +12,6 @@ module Gem end end -# Delete any copies of Bundler that have been dumped into site_ruby without -# a gemspec. RubyGems cannot manage that Bundler, and so our tricks to make -# sure that the correct version of Bundler loads will stop working. -Dir.glob(File.join(RbConfig::CONFIG["sitelibdir"], "bundler*")).each do |f| - FileUtils.rm_rf f -end - begin require File.expand_path("../support/path.rb", __FILE__) spec = Gem::Specification.load(Spec::Path.gemspec.to_s) @@ -35,6 +28,13 @@ module Gem require "uri" require "digest" +# Delete any copies of Bundler that have been dumped into site_ruby without +# a gemspec. RubyGems cannot manage that Bundler, and so our tricks to make +# sure that the correct version of Bundler loads will stop working. +Dir.glob(File.join(RbConfig::CONFIG["sitelibdir"], "bundler*")).each do |f| + FileUtils.rm_rf f +end + if File.expand_path(__FILE__) =~ %r{([^\w/\.-])} abort "The bundler specs cannot be run from a path that contains special characters (particularly #{$1.inspect})" end From 8779946b56c33d45855350482c00c828825d667d Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Mon, 9 Jul 2018 21:43:47 -0700 Subject: [PATCH 7/8] maybe this will resolve the intermittent Travis failures --- spec/spec_helper.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1d4d4b537e5..f7a6b43d4b5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -31,8 +31,9 @@ module Gem # Delete any copies of Bundler that have been dumped into site_ruby without # a gemspec. RubyGems cannot manage that Bundler, and so our tricks to make # sure that the correct version of Bundler loads will stop working. -Dir.glob(File.join(RbConfig::CONFIG["sitelibdir"], "bundler*")).each do |f| - FileUtils.rm_rf f +require "fileutils" +Dir.glob(File.join(RbConfig::CONFIG["sitelibdir"], "bundler*")).each do |file| + FileUtils.rm_rf(file) end if File.expand_path(__FILE__) =~ %r{([^\w/\.-])} From 865ec52ae87c29473405ce587977dd3eaef453ae Mon Sep 17 00:00:00 2001 From: Andre Arko Date: Mon, 9 Jul 2018 22:50:45 -0700 Subject: [PATCH 8/8] only realpath things that exist --- lib/bundler/shared_helpers.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index e4cbbba2ba0..f9ac9a760aa 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -344,9 +344,10 @@ def clean_load_path def resolve_path(path) expanded = File.expand_path(path) + return expanded unless File.respond_to?(:realpath) - if File.respond_to?(:realpath) - expanded = File.realpath(expanded) until expanded == File.realpath(expanded) + while File.exist?(expanded) && File.realpath(expanded) != expanded + expanded = File.realpath(expanded) end expanded