diff options
| -rw-r--r-- | lib/bundled_gems.rb | 18 | ||||
| -rw-r--r-- | test/test_bundled_gems.rb | 35 |
2 files changed, 53 insertions, 0 deletions
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb index eea70ca19a..b1e5470fc7 100644 --- a/lib/bundled_gems.rb +++ b/lib/bundled_gems.rb @@ -28,6 +28,8 @@ module Gem::BUNDLED_GEMS "syslog" => "3.4.0", }.freeze + SINCE_FAST_PATH = SINCE.transform_keys { |g| g.sub(/\A.*\-/, "") }.freeze + EXACT = { "abbrev" => true, "base64" => true, @@ -97,6 +99,22 @@ module Gem::BUNDLED_GEMS def self.warning?(name, specs: nil) # name can be a feature name or a file path with String or Pathname feature = File.path(name) + + # The actual checks needed to properly identify the gem being required + # are costly (see [Bug #20641]), so we first do a much cheaper check + # to exclude the vast majority of candidates. + if feature.include?("/") + # If requiring $LIBDIR/mutex_m.rb, we check SINCE_FAST_PATH["mutex_m"] + # We'll fail to warn requires for files that are not the entry point + # of the gem, e.g. require "logger/formatter.rb" won't warn. + # But that's acceptable because this warning is best effort, + # and in the overwhelming majority of case logger.rb will end + # up required. + return unless SINCE_FAST_PATH[File.basename(feature, ".*")] + else + return unless SINCE_FAST_PATH[feature] + end + # bootsnap expands `require "csv"` to `require "#{LIBDIR}/csv.rb"`, # and `require "syslog"` to `require "#{ARCHDIR}/syslog.so"`. name = feature.delete_prefix(ARCHDIR) diff --git a/test/test_bundled_gems.rb b/test/test_bundled_gems.rb new file mode 100644 index 0000000000..36f7324336 --- /dev/null +++ b/test/test_bundled_gems.rb @@ -0,0 +1,35 @@ +require_relative "rubygems/helper" +require "rubygems" +require "bundled_gems" + +class TestBundlerGem < Gem::TestCase + def setup + Gem::BUNDLED_GEMS::WARNED.clear + end + + def teardown + Gem::BUNDLED_GEMS::WARNED.clear + end + + def test_warning + assert Gem::BUNDLED_GEMS.warning?("rss", specs: {}) + assert_nil Gem::BUNDLED_GEMS.warning?("rss", specs: {}) + end + + def test_no_warning_warning + assert_nil Gem::BUNDLED_GEMS.warning?("some_gem", specs: {}) + assert_nil Gem::BUNDLED_GEMS.warning?("/path/to/some_gem.rb", specs: {}) + end + + def test_warning_libdir + path = File.join(::RbConfig::CONFIG.fetch("rubylibdir"), "rss.rb") + assert Gem::BUNDLED_GEMS.warning?(path, specs: {}) + assert_nil Gem::BUNDLED_GEMS.warning?(path, specs: {}) + end + + def test_warning_archdir + path = File.join(::RbConfig::CONFIG.fetch("rubyarchdir"), "syslog.so") + assert Gem::BUNDLED_GEMS.warning?(path, specs: {}) + assert_nil Gem::BUNDLED_GEMS.warning?(path, specs: {}) + end +end |
