ruby-changes:65085
From: nagachika <ko1@a...>
Date: Sat, 30 Jan 2021 20:44:52 +0900 (JST)
Subject: [ruby-changes:65085] 99b4f20fd6 (ruby_2_7): Merge RubyGems-3.1.6 [Bug #16926]
https://git.ruby-lang.org/ruby.git/commit/?id=99b4f20fd6 From 99b4f20fd65075d2d9ee02f8c7a6b5d6a914ce31 Mon Sep 17 00:00:00 2001 From: nagachika <nagachika@r...> Date: Sat, 30 Jan 2021 20:43:44 +0900 Subject: Merge RubyGems-3.1.6 [Bug #16926] https://github.com/ruby/ruby/pull/4122 --- lib/rubygems.rb | 23 ++++--- lib/rubygems/core_ext/kernel_require.rb | 60 ++++++++---------- lib/rubygems/test_case.rb | 1 + test/rubygems/test_bundled_ca.rb | 1 + test/rubygems/test_kernel.rb | 19 ++++++ test/rubygems/test_require.rb | 104 ++++++++++++++++++++++++++++++++ version.h | 8 +-- 7 files changed, 167 insertions(+), 49 deletions(-) diff --git a/lib/rubygems.rb b/lib/rubygems.rb index d8b4dc7..f8ca703 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -9,7 +9,7 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems.rb#L9 require 'rbconfig' module Gem - VERSION = "3.1.5".freeze + VERSION = "3.1.6".freeze end # Must be first since it unloads the prelude from 1.9.2 @@ -659,22 +659,25 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} https://github.com/ruby/ruby/blob/trunk/lib/rubygems.rb#L659 index = $LOAD_PATH.index RbConfig::CONFIG['sitelibdir'] - index + index || 0 + end + + ## + # The number of paths in the `$LOAD_PATH` from activated gems. Used to + # prioritize `-I` and `ENV['RUBYLIB`]` entries during `require`. + + def self.activated_gem_paths + @activated_gem_paths ||= 0 end ## # Add a list of paths to the $LOAD_PATH at the proper place. def self.add_to_load_path(*paths) - insert_index = load_path_insert_index + @activated_gem_paths = activated_gem_paths + paths.size - if insert_index - # gem directories must come after -I and ENV['RUBYLIB'] - $LOAD_PATH.insert(insert_index, *paths) - else - # we are probably testing in core, -I and RUBYLIB don't apply - $LOAD_PATH.unshift(*paths) - end + # gem directories must come after -I and ENV['RUBYLIB'] + $LOAD_PATH.insert(Gem.load_path_insert_index, *paths) end @yaml_loaded = false diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb index 60f4d18..115ae0c 100644 --- a/lib/rubygems/core_ext/kernel_require.rb +++ b/lib/rubygems/core_ext/kernel_require.rb @@ -39,49 +39,40 @@ module Kernel https://github.com/ruby/ruby/blob/trunk/lib/rubygems/core_ext/kernel_require.rb#L39 path = path.to_path if path.respond_to? :to_path - # Ensure -I beats a default gem - # https://github.com/rubygems/rubygems/pull/1868 - resolved_path = begin - rp = nil - $LOAD_PATH[0...Gem.load_path_insert_index || -1].each do |lp| - safe_lp = lp.dup.tap(&Gem::UNTAINT) - begin - if File.symlink? safe_lp # for backward compatibility - next - end - rescue SecurityError - RUBYGEMS_ACTIVATION_MONITOR.exit - raise - end - + if spec = Gem.find_unresolved_default_spec(path) + # Ensure -I beats a default gem + resolved_path = begin + rp = nil + load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths Gem.suffixes.each do |s| - full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}")) - if File.file?(full_path) - rp = full_path - break + $LOAD_PATH[0...load_path_check_index].each do |lp| + safe_lp = lp.dup.tap(&Gem::UNTAINT) + begin + if File.symlink? safe_lp # for backward compatibility + next + end + rescue SecurityError + RUBYGEMS_ACTIVATION_MONITOR.exit + raise + end + + full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}")) + if File.file?(full_path) + rp = full_path + break + end end + break if rp end - break if rp - end - rp - end - - if resolved_path - begin - RUBYGEMS_ACTIVATION_MONITOR.exit - return gem_original_require(resolved_path) - rescue LoadError - RUBYGEMS_ACTIVATION_MONITOR.enter + rp end - end - if spec = Gem.find_unresolved_default_spec(path) begin Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease) rescue Exception RUBYGEMS_ACTIVATION_MONITOR.exit raise - end + end unless resolved_path end # If there are no unresolved deps, then we can use just try @@ -157,8 +148,7 @@ module Kernel https://github.com/ruby/ruby/blob/trunk/lib/rubygems/core_ext/kernel_require.rb#L148 RUBYGEMS_ACTIVATION_MONITOR.enter begin - if load_error.message.start_with?("Could not find") or - (load_error.message.end_with?(path) and Gem.try_activate(path)) + if load_error.message.end_with?(path) and Gem.try_activate(path) require_again = true end ensure diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 8940320..c6f5f29 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -385,6 +385,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni https://github.com/ruby/ruby/blob/trunk/lib/rubygems/test_case.rb#L385 Gem::Security.reset Gem.loaded_specs.clear + Gem.instance_variable_set(:@activated_gem_paths, 0) Gem.clear_default_specs Bundler.reset! diff --git a/test/rubygems/test_bundled_ca.rb b/test/rubygems/test_bundled_ca.rb index 9538d6b..4224755 100644 --- a/test/rubygems/test_bundled_ca.rb +++ b/test/rubygems/test_bundled_ca.rb @@ -62,5 +62,6 @@ if ENV["CI"] || ENV["TEST_SSL"] https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_bundled_ca.rb#L62 def test_accessing_new_index assert_https('index.rubygems.org') end + end end diff --git a/test/rubygems/test_kernel.rb b/test/rubygems/test_kernel.rb index b9f9b5e..daf9b57 100644 --- a/test/rubygems/test_kernel.rb +++ b/test/rubygems/test_kernel.rb @@ -91,6 +91,25 @@ class TestKernel < Gem::TestCase https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_kernel.rb#L91 refute $:.any? { |p| %r{a-1/bin} =~ p } end + def test_gem_failing_inside_require_doesnt_cause_double_exceptions + File.write("activate.rb", "gem('a', '= 999')\n") + + require "open3" + + output, _ = Open3.capture2e( + { "GEM_HOME" => Gem.paths.home }, + Gem.ruby, + "-I", + File.expand_path("../../lib", __dir__), + "-r", + "./activate.rb" + ) + + load_errors = output.split("\n").select { |line| line.include?("Could not find")} + + assert_equal 1, load_errors.size + end + def test_gem_bundler quick_gem 'bundler', '1' quick_gem 'bundler', '2.a' diff --git a/test/rubygems/test_require.rb b/test/rubygems/test_require.rb index aa2675a..392ede7 100644 --- a/test/rubygems/test_require.rb +++ b/test/rubygems/test_require.rb @@ -45,6 +45,35 @@ class TestGemRequire < Gem::TestCase https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_require.rb#L45 refute require(path), "'#{path}' was not yet required" end + def test_respect_loaded_features_caching_like_standard_require + dir = Dir.mktmpdir("test_require", @tempdir) + + lp1 = File.join dir, 'foo1' + foo1 = File.join lp1, 'foo.rb' + + FileUtils.mkdir_p lp1 + File.open(foo1, 'w') { |f| f.write "class Object; HELLO = 'foo1' end" } + + lp = $LOAD_PATH.dup + + $LOAD_PATH.unshift lp1 + assert_require 'foo' + assert_equal "foo1", ::Object::HELLO + + lp2 = File.join dir, 'foo2' + foo2 = File.join lp2, 'foo.rb' + + FileUtils.mkdir_p lp2 + File.open(foo2, 'w') { |f| f.write "class Object; HELLO = 'foo2' end" } + + $LOAD_PATH.unshift lp2 + refute_require 'foo' + assert_equal "foo1", ::Object::HELLO + ensure + $LOAD_PATH.replace lp + Object.send :remove_const, :HELLO if Object.const_defined? :HELLO + end + # Providing -I on the commandline should always beat gems def test_dash_i_beats_gems a1 = util_spec "a", "1", {"b" => "= 1"}, "lib/test_gem_require_a.rb" @@ -120,6 +149,24 @@ class TestGemRequire < Gem::TestCase https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_require.rb#L149 Object.send :remove_const, :HELLO if Object.const_defined? :HELLO end + def test_dash_i_respects_default_library_extension_priority + skip "extensions don't quite work on jruby" if Gem.java_platform? + + dash_i_ext_arg = util_install_extension_file('a') + dash_i_lib_arg = util_install_ruby_file('a') + + lp = $LOAD_PATH.dup + + begin + $LOAD_PATH.unshift dash_i_lib_arg + $LOAD_PATH.unshift dash_i_ext_arg + assert_require 'a' + assert_match(/a\.rb$/, $LOADED_FEATURES.last) + ensure + $LOAD_PATH.replace lp + end + end + def test_concurrent_require Object.const_set :FILE_ENTERED_LATCH, Latch.new(2) Object.const_set :FILE_EXIT_LATCH, Latch.new(1) @@ -364,6 +411,17 @@ class TestGemRequire < Gem::TestCase https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_require.rb#L411 assert_equal 0, times_called end + def test_second_gem_require_does_not_resolve_path_manually_before_going_through_standard_require + a1 = util_spec "a", "1", nil, "lib/test_gem_require_a.rb" + install_gem a1 + + assert_require "test_gem_require_a" + + stub(:gem_original_require, ->(path) { assert_equal "test_gem_require_a", path }) do + require "test_gem_require_a" + end + end + def test_realworld_default_gem testing_ruby_repo = !ENV["GEM_COMMAND"].nil? skip "this test can't work under ruby-core setup" if testing_ruby_repo || java_platform? @@ -539,4 +597,50 @@ class TestGemRequire < Gem::TestCase https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_require.rb#L597 $VERBOSE = old_verbose end + (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/