summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/bundled_gems.rb18
-rw-r--r--test/test_bundled_gems.rb35
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