summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Giddins <segiddins@segiddins.me>2016-07-08 22:05:53 -0300
committerSamuel Giddins <segiddins@segiddins.me>2016-07-14 22:32:53 -0500
commitacc66784e0ab069e85c58e459a443e9449c40259 (patch)
treee6eb6810118d5b14fba6ed3a4e68b654cfbfab02
parent31a6e58c7846f69612c93f424496e2e4e8065f97 (diff)
downloadbundler-acc66784e0ab069e85c58e459a443e9449c40259.tar.gz
[RubygemsIntegration] Add support for reversing hooks
-rw-r--r--lib/bundler.rb5
-rw-r--r--lib/bundler/rubygems_integration.rb135
2 files changed, 79 insertions, 61 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb
index b8eed25d44..afc243c4f5 100644
--- a/lib/bundler.rb
+++ b/lib/bundler.rb
@@ -386,6 +386,11 @@ module Bundler
@root = nil
@settings = nil
@definition = nil
+ if defined?(@rubygems) && @rubygems
+ rubygems.undo_replacements
+ @rubygems = nil
+ end
+ Gem::Specification.reset
end
private
diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb
index af2e2f2fca..5fb3009241 100644
--- a/lib/bundler/rubygems_integration.rb
+++ b/lib/bundler/rubygems_integration.rb
@@ -19,6 +19,10 @@ module Bundler
Gem::Requirement.new(req_str).satisfied_by?(version)
end
+ def initialize
+ @replaced_methods = {}
+ end
+
def version
self.class.version
end
@@ -283,13 +287,11 @@ module Bundler
def reverse_rubygems_kernel_mixin
# Disable rubygems' gem activation system
- ::Kernel.class_eval do
- if private_method_defined?(:gem_original_require)
- alias_method :rubygems_require, :require
- alias_method :require, :gem_original_require
+ kernel = (class << ::Kernel; self; end)
+ [kernel, ::Kernel].each do |k|
+ if k.private_method_defined?(:gem_original_require)
+ redefine_method(k, :require, k.instance_method(:gem_original_require))
end
-
- undef gem
end
end
@@ -298,41 +300,44 @@ module Bundler
executables = specs.map(&:executables).flatten
- ::Kernel.send(:define_method, :gem) do |dep, *reqs|
- if 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.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)
+ break
+ end
+ reqs.pop if reqs.last.is_a?(Hash)
- 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
+ unless dep.respond_to?(:name) && dep.respond_to?(:requirement)
+ dep = Gem::Dependency.new(dep, reqs)
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
+
+ spec = specs.find {|s| s.name == dep.name }
+
+ 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
end
- raise e
- end
- true
+ true
+ end
end
end
@@ -463,9 +468,18 @@ module Bundler
end
end
- def redefine_method(klass, method, &block)
+ def undo_replacements
+ @replaced_methods.each do |(sym, klass), method|
+ redefine_method(klass, sym, method)
+ end
+ Gem.post_reset_hooks.reject! {|proc| proc.source_location.first == __FILE__ }
+ @replaced_methods.clear
+ end
+
+ def redefine_method(klass, method, unbound_method = nil, &block)
+ # puts "redefining #{klass} #{method} to #{unbound_method || block}"
begin
- if klass.instance_method(method) && method != :initialize
+ if instance_method = klass.instance_method(method) and method != :initialize
# doing this to ensure we also get private methods
klass.send(:remove_method, method)
end
@@ -473,7 +487,8 @@ module Bundler
# method isn't defined
nil
end
- klass.send(:define_method, method, &block)
+ @replaced_methods[[method, klass]] = instance_method
+ klass.send(:define_method, method, unbound_method || block.to_proc)
end
# Rubygems 1.4 through 1.6
@@ -489,7 +504,7 @@ module Bundler
def stub_rubygems(specs)
# Rubygems versions lower than 1.7 use SourceIndex#from_gems_in
source_index_class = (class << Gem::SourceIndex; self; end)
- source_index_class.send(:define_method, :from_gems_in) do |*args|
+ redefine_method(source_index, source_index_class) do |*args|
source_index = Gem::SourceIndex.new
source_index.spec_dirs = *args
source_index.add_specs(*specs)
@@ -688,25 +703,23 @@ module Bundler
end
end
- if RubygemsIntegration.provides?(">= 2.1.0")
- @rubygems = RubygemsIntegration::MoreFuture.new
- elsif RubygemsIntegration.provides?(">= 1.99.99")
- @rubygems = RubygemsIntegration::Future.new
- elsif RubygemsIntegration.provides?(">= 1.8.20")
- @rubygems = RubygemsIntegration::MoreModern.new
- elsif RubygemsIntegration.provides?(">= 1.8.5")
- @rubygems = RubygemsIntegration::Modern.new
- elsif RubygemsIntegration.provides?(">= 1.8.0")
- @rubygems = RubygemsIntegration::AlmostModern.new
- elsif RubygemsIntegration.provides?(">= 1.7.0")
- @rubygems = RubygemsIntegration::Transitional.new
- elsif RubygemsIntegration.provides?(">= 1.4.0")
- @rubygems = RubygemsIntegration::Legacy.new
- else # Rubygems 1.3.6 and 1.3.7
- @rubygems = RubygemsIntegration::Ancient.new
- end
-
- class << self
- attr_reader :rubygems
+ def self.rubygems
+ @rubygems ||= if RubygemsIntegration.provides?(">= 2.1.0")
+ RubygemsIntegration::MoreFuture.new
+ elsif RubygemsIntegration.provides?(">= 1.99.99")
+ RubygemsIntegration::Future.new
+ elsif RubygemsIntegration.provides?(">= 1.8.20")
+ RubygemsIntegration::MoreModern.new
+ elsif RubygemsIntegration.provides?(">= 1.8.5")
+ RubygemsIntegration::Modern.new
+ elsif RubygemsIntegration.provides?(">= 1.8.0")
+ RubygemsIntegration::AlmostModern.new
+ elsif RubygemsIntegration.provides?(">= 1.7.0")
+ RubygemsIntegration::Transitional.new
+ elsif RubygemsIntegration.provides?(">= 1.4.0")
+ RubygemsIntegration::Legacy.new
+ else # Rubygems 1.3.6 and 1.3.7
+ RubygemsIntegration::Ancient.new
+ end
end
end