diff options
author | Hiroshi SHIBATA <[email protected]> | 2024-03-25 17:09:56 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2024-03-25 08:09:56 +0000 |
commit | 2f654588d9e0cefff1c23529d2f2672029e1bd21 (patch) | |
tree | c8ef5eb47dd6b77e91cb59f2f69c3138b812df77 /lib | |
parent | 6d6818883b8f613fe9b6c72ac7eb9b313bba097b (diff) |
Backport https://github.com/ruby/ruby/pull/10347 (#10349)
Fix incorrect warning target with Zeitwerk and support warning with Bootsnap.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bundled_gems.rb | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/lib/bundled_gems.rb b/lib/bundled_gems.rb index 55286725c0..e756af61ea 100644 --- a/lib/bundled_gems.rb +++ b/lib/bundled_gems.rb @@ -95,8 +95,10 @@ module Gem::BUNDLED_GEMS end def self.warning?(name, specs: nil) - feature = File.path(name) # name can be a feature name or a file path with String or Pathname - name = feature.tr("/", "-") + # name can be a feature name or a file path with String or Pathname + feature = File.path(name) + # bootsnap expand `require "csv"` to `require "#{LIBDIR}/csv.rb"` + name = feature.delete_prefix(LIBDIR).chomp(".rb").tr("/", "-") name.sub!(LIBEXT, "") return if specs.include?(name) _t, path = $:.resolve_feature_path(feature) @@ -109,12 +111,7 @@ module Gem::BUNDLED_GEMS else return end - # Warning feature is not working correctly with Bootsnap. - # caller_locations returns: - # lib/ruby/3.3.0+0/bundled_gems.rb:65:in `block (2 levels) in replace_require' - # $GEM_HOME/gems/bootsnap-1.17.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'" - # ... - return if caller_locations(2).find {|c| c&.path.match?(/bootsnap/) } + return if WARNED[name] WARNED[name] = true if gem == true @@ -134,11 +131,29 @@ module Gem::BUNDLED_GEMS if defined?(Bundler) msg += " Add #{gem} to your Gemfile or gemspec." + # We detect the gem name from caller_locations. We need to skip 2 frames like: # lib/ruby/3.3.0+0/bundled_gems.rb:90:in `warning?'", # lib/ruby/3.3.0+0/bundler/rubygems_integration.rb:247:in `block (2 levels) in replace_require'", - location = caller_locations(3,1)[0]&.path - if File.file?(location) && !location.start_with?(Gem::BUNDLED_GEMS::LIBDIR) + # + # Additionally, we need to skip Bootsnap and Zeitwerk if present, these + # gems decorate Kernel#require, so they are not really the ones issuing + # the require call users should be warned about. Those are upwards. + frames_to_skip = 2 + location = nil + Thread.each_caller_location do |cl| + if frames_to_skip >= 1 + frames_to_skip -= 1 + next + end + + unless cl.path.match?(/bootsnap|zeitwerk/) + location = cl.path + break + end + end + + if location && File.file?(location) && !location.start_with?(Gem::BUNDLED_GEMS::LIBDIR) caller_gem = nil Gem.path.each do |path| if location =~ %r{#{path}/gems/([\w\-\.]+)} |