@@ -249,6 +249,16 @@ def self.bin_path(name, exec_name = nil, *requirements)
249249 find_spec_for_exe ( name , exec_name , requirements ) . bin_file exec_name
250250 end
251251
252+ def self . find_and_activate_spec_for_exe ( name , exec_name , requirements )
253+ spec = find_spec_for_exe name , exec_name , requirements
254+ Gem ::LOADED_SPECS_MUTEX . synchronize do
255+ spec . activate
256+ finish_resolve
257+ end
258+ spec
259+ end
260+ private_class_method :find_and_activate_spec_for_exe
261+
252262 def self . find_spec_for_exe ( name , exec_name , requirements )
253263 raise ArgumentError , "you must supply exec_name" unless exec_name
254264
@@ -273,6 +283,35 @@ def self.find_spec_for_exe(name, exec_name, requirements)
273283 end
274284 private_class_method :find_spec_for_exe
275285
286+ ##
287+ # Find and load the full path to the executable for gem +name+. If the
288+ # +exec_name+ is not given, an exception will be raised, otherwise the
289+ # specified executable's path is returned. +requirements+ allows
290+ # you to specify specific gem versions.
291+ #
292+ # A side effect of this method is that it will activate the gem that
293+ # contains the executable.
294+ #
295+ # This method should *only* be used in bin stub files.
296+
297+ def self . activate_and_load_bin_path ( name , exec_name = nil , *requirements )
298+ spec = find_and_activate_spec_for_exe name , exec_name , requirements
299+
300+ if spec . name == "bundler"
301+ # Make sure there's no version of Bundler in `$LOAD_PATH` that's different
302+ # from the version we just activated. If that was the case (it happens
303+ # when testing Bundler from ruby/ruby), we would load Bundler extensions
304+ # to RubyGems from the copy in `$LOAD_PATH` but then load the binstub from
305+ # an installed copy, causing those copies to be mixed and yet more
306+ # redefinition warnings.
307+ #
308+ require_path = $LOAD_PATH. resolve_feature_path ( "bundler" ) . last . delete_suffix ( "/bundler.rb" )
309+ Gem . load_bundler_extensions ( spec . version ) if spec . full_require_paths . include? ( require_path )
310+ end
311+
312+ load spec . bin_file ( exec_name )
313+ end
314+
276315 ##
277316 # Find the full path to the executable for gem +name+. If the +exec_name+
278317 # is not given, an exception will be raised, otherwise the
@@ -285,12 +324,7 @@ def self.find_spec_for_exe(name, exec_name, requirements)
285324 # This method should *only* be used in bin stub files.
286325
287326 def self . activate_bin_path ( name , exec_name = nil , *requirements ) # :nodoc:
288- spec = find_spec_for_exe name , exec_name , requirements
289- Gem ::LOADED_SPECS_MUTEX . synchronize do
290- spec . activate
291- finish_resolve
292- end
293- spec . bin_file exec_name
327+ find_and_activate_spec_for_exe ( name , exec_name , requirements ) . bin_file exec_name
294328 end
295329
296330 ##
0 commit comments