lib/bundler/rubygems_integration.rb in bundler-1.14.6 vs lib/bundler/rubygems_integration.rb in bundler-1.15.0.pre.1
- old
+ new
@@ -78,10 +78,14 @@
return false if spec.extensions.empty?
default
end
+ def stub_set_spec(stub, spec)
+ stub.instance_variable_set(:@spec, spec)
+ end
+
def path(obj)
obj.to_s
end
def platforms
@@ -318,52 +322,57 @@
redefine_method(k, :require, k.instance_method(:gem_original_require))
end
end
end
- def replace_gem(specs)
+ def binstubs_call_gem?
+ true
+ end
+
+ def stubs_provide_full_functionality?
+ false
+ end
+
+ def replace_gem(specs, specs_by_name)
reverse_rubygems_kernel_mixin
- executables = specs.map(&:executables).flatten
+ executables = nil
kernel = (class << ::Kernel; self; end)
[kernel, ::Kernel].each do |kernel_class|
redefine_method(kernel_class, :gem) do |dep, *reqs|
- if executables.include? File.basename(caller.first.split(":").first)
+ executables ||= specs.map(&:executables).flatten if ::Bundler.rubygems.binstubs_call_gem?
+ if executables && executables.include?(File.basename(caller.first.split(":").first))
break
end
+
reqs.pop if reqs.last.is_a?(Hash)
unless dep.respond_to?(:name) && dep.respond_to?(:requirement)
dep = Gem::Dependency.new(dep, reqs)
end
- spec = specs.find {|s| s.name == dep.name }
+ if spec = specs_by_name[dep.name]
+ return true if dep.matches_spec?(spec)
+ end
- if spec.nil?
-
- e = Gem::LoadError.new "#{dep.name} is not part of the bundle. Add it to Gemfile."
- e.name = dep.name
- if e.respond_to?(:requirement=)
- e.requirement = dep.requirement
- else
- e.version_requirement = dep.requirement
- end
- raise e
- elsif dep !~ spec
- e = Gem::LoadError.new "can't activate #{dep}, already activated #{spec.full_name}. " \
- "Make sure all dependencies are added to Gemfile."
- e.name = dep.name
- if e.respond_to?(:requirement=)
- e.requirement = dep.requirement
- else
- e.version_requirement = dep.requirement
- end
- raise e
+ message = if spec.nil?
+ "#{dep.name} is not part of the bundle." \
+ " Add it to your #{Bundler.default_gemfile.basename}."
+ else
+ "can't activate #{dep}, already activated #{spec.full_name}. " \
+ "Make sure all dependencies are added to Gemfile."
end
- true
+ e = Gem::LoadError.new(message)
+ e.name = dep.name
+ if e.respond_to?(:requirement=)
+ e.requirement = dep.requirement
+ elsif e.respond_to?(:version_requirement=)
+ e.version_requirement = dep.requirement
+ end
+ raise e
end
# TODO: delete this in 2.0, it's a backwards compatibility shim
# see https://github.com/bundler/bundler/issues/5102
kernel_class.send(:public, :gem)
@@ -391,24 +400,38 @@
end
# Used to make bin stubs that are not created by bundler work
# under bundler. The new Gem.bin_path only considers gems in
# +specs+
- def replace_bin_path(specs)
+ def replace_bin_path(specs, specs_by_name)
gem_class = (class << Gem; self; end)
redefine_method(gem_class, :find_spec_for_exe) do |gem_name, *args|
exec_name = args.first
+ spec_with_name = specs_by_name[gem_name]
spec = if exec_name
- specs.find {|s| s.name == gem_name && s.executables.include?(exec_name) } ||
+ if spec_with_name && spec_with_name.executables.include?(exec_name)
+ spec_with_name
+ else
specs.find {|s| s.executables.include?(exec_name) }
+ end
else
- specs.find {|s| s.name == gem_name }
+ spec_with_name
end
- raise(Gem::Exception, "can't find executable #{exec_name}") unless spec
+
+ unless spec
+ message = "can't find executable #{exec_name} for gem #{gem_name}"
+ if !exec_name || spec_with_name.nil?
+ message += ". #{gem_name} is not currently included in the bundle, " \
+ "perhaps you meant to add it to your #{Bundler.default_gemfile.basename}?"
+ end
+ raise Gem::Exception, message
+ end
+
raise Gem::Exception, "no default executable for #{spec.full_name}" unless exec_name ||= spec.default_executable
+
unless spec.name == name
Bundler::SharedHelpers.major_deprecation \
"Bundler is using a binstub that was created for a different gem.\n" \
"You should run `bundle binstub #{gem_name}` " \
"to work around a system/bundle conflict."
@@ -421,12 +444,14 @@
return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle"
# Copy of Rubygems activate_bin_path impl
requirement = args.last
spec = find_spec_for_exe name, exec_name, [requirement]
- Gem::LOADED_SPECS_MUTEX.synchronize { spec.activate }
- spec.bin_file exec_name
+
+ gem_bin = File.join(spec.full_gem_path, spec.bindir, exec_name)
+ gem_from_path_bin = File.join(File.dirname(spec.loaded_from), spec.bindir, exec_name)
+ File.exist?(gem_bin) ? gem_bin : gem_from_path_bin
end
redefine_method(gem_class, :bin_path) do |name, *args|
exec_name = args.first
return ENV["BUNDLE_BIN_PATH"] if exec_name == "bundle"
@@ -448,15 +473,18 @@
end
# Replace or hook into Rubygems to provide a bundlerized view
# of the world.
def replace_entrypoints(specs)
- replace_gem(specs)
+ specs_by_name = specs.reduce({}) do |h, s|
+ h[s.name] = s
+ h
+ end
+ replace_gem(specs, specs_by_name)
stub_rubygems(specs)
-
- replace_bin_path(specs)
+ replace_bin_path(specs, specs_by_name)
replace_refresh
Gem.clear_paths
end
@@ -744,12 +772,18 @@
StubSpecification.from_stub(stub)
end
end
def backport_ext_builder_monitor
- require "rubygems/ext"
+ # So we can avoid requiring "rubygems/ext" in its entirety
+ Gem.module_eval <<-RB, __FILE__, __LINE__ + 1
+ module Ext
+ end
+ RB
+ require "rubygems/ext/builder"
+
Gem::Ext::Builder.class_eval do
unless const_defined?(:CHDIR_MONITOR)
const_set(:CHDIR_MONITOR, EXT_LOCK)
end
@@ -774,9 +808,24 @@
ENV["BUNDLE_GEMFILE"] ||= File.expand_path(gemfile)
runtime = Bundler.setup
Bundler.ui = nil
activated_spec_names = runtime.requested_specs.map(&:to_spec).sort_by(&:name)
[Gemdeps.new(runtime), activated_spec_names]
+ end
+
+ if provides?(">= 2.5.2")
+ # RubyGems-generated binstubs call Kernel#gem
+ def binstubs_call_gem?
+ false
+ end
+
+ # only 2.5.2+ has all of the stub methods we want to use, and since this
+ # is a performance optimization _only_,
+ # we'll restrict ourselves to the most
+ # recent RG versions instead of all versions that have stubs
+ def stubs_provide_full_functionality?
+ true
+ end
end
end
end
def self.rubygems