Skip to content

Commit 63bec47

Browse files
authored
Merge pull request #3439 from rubygems/fatkodima-require-hooks
Add plugin hooks for Bundler.require
2 parents 44ba022 + f6f79f4 commit 63bec47

File tree

6 files changed

+169
-19
lines changed

6 files changed

+169
-19
lines changed

bundler/lib/bundler.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ def setup(*groups)
184184
# Bundler.require(:test) # requires second_gem
185185
#
186186
def require(*groups)
187+
load_plugins
187188
setup(*groups).require(*groups)
188189
end
189190

@@ -560,6 +561,23 @@ def feature_flag
560561
@feature_flag ||= FeatureFlag.new(VERSION)
561562
end
562563

564+
def load_plugins(definition = Bundler.definition)
565+
return if defined?(@load_plugins_ran)
566+
567+
Bundler.rubygems.load_plugins
568+
569+
requested_path_gems = definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
570+
path_plugin_files = requested_path_gems.map do |spec|
571+
Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
572+
rescue TypeError
573+
error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
574+
raise Gem::InvalidSpecificationException, error_message
575+
end.flatten
576+
Bundler.rubygems.load_plugin_files(path_plugin_files)
577+
Bundler.rubygems.load_env_plugins
578+
@load_plugins_ran = true
579+
end
580+
563581
def reset!
564582
reset_paths!
565583
Plugin.reset!

bundler/lib/bundler/installer.rb

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def run(options)
8181

8282
if resolve_if_needed(options)
8383
ensure_specs_are_compatible!
84-
load_plugins
84+
Bundler.load_plugins(@definition)
8585
options.delete(:jobs)
8686
else
8787
options[:jobs] = 1 # to avoid the overhead of Bundler::Worker
@@ -213,20 +213,6 @@ def installation_parallelization(options)
213213
Bundler.settings.processor_count
214214
end
215215

216-
def load_plugins
217-
Gem.load_plugins
218-
219-
requested_path_gems = @definition.requested_specs.select {|s| s.source.is_a?(Source::Path) }
220-
path_plugin_files = requested_path_gems.map do |spec|
221-
Bundler.rubygems.spec_matches_for_glob(spec, "rubygems_plugin#{Bundler.rubygems.suffix_pattern}")
222-
rescue TypeError
223-
error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
224-
raise Gem::InvalidSpecificationException, error_message
225-
end.flatten
226-
Gem.load_plugin_files(path_plugin_files)
227-
Gem.load_env_plugins
228-
end
229-
230216
def ensure_specs_are_compatible!
231217
@definition.specs.each do |spec|
232218
unless spec.matches_current_ruby?

bundler/lib/bundler/plugin/events.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,30 @@ def self.defined_event?(event)
5656
# Includes an Array of Bundler::Dependency objects
5757
# GEM_AFTER_INSTALL_ALL = "after-install-all"
5858
define :GEM_AFTER_INSTALL_ALL, "after-install-all"
59+
60+
# @!parse
61+
# A hook called before each individual gem is required
62+
# Includes a Bundler::Dependency.
63+
# GEM_BEFORE_REQUIRE = "before-require"
64+
define :GEM_BEFORE_REQUIRE, "before-require"
65+
66+
# @!parse
67+
# A hook called after each individual gem is required
68+
# Includes a Bundler::Dependency.
69+
# GEM_AFTER_REQUIRE = "after-require"
70+
define :GEM_AFTER_REQUIRE, "after-require"
71+
72+
# @!parse
73+
# A hook called before any gems require
74+
# Includes an Array of Bundler::Dependency objects.
75+
# GEM_BEFORE_REQUIRE_ALL = "before-require-all"
76+
define :GEM_BEFORE_REQUIRE_ALL, "before-require-all"
77+
78+
# @!parse
79+
# A hook called after all gems required
80+
# Includes an Array of Bundler::Dependency objects.
81+
# GEM_AFTER_REQUIRE_ALL = "after-require-all"
82+
define :GEM_AFTER_REQUIRE_ALL, "after-require-all"
5983
end
6084
end
6185
end

bundler/lib/bundler/rubygems_integration.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,18 @@ def loaded_gem_paths
156156
loaded_gem_paths.flatten
157157
end
158158

159+
def load_plugins
160+
Gem.load_plugins
161+
end
162+
163+
def load_plugin_files(plugin_files)
164+
Gem.load_plugin_files(plugin_files)
165+
end
166+
167+
def load_env_plugins
168+
Gem.load_env_plugins
169+
end
170+
159171
def ui=(obj)
160172
Gem::DefaultUserInteraction.ui = obj
161173
end

bundler/lib/bundler/runtime.rb

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,17 @@ def require(*groups)
4141
groups.map!(&:to_sym)
4242
groups = [:default] if groups.empty?
4343

44-
@definition.dependencies.each do |dep|
45-
# Skip the dependency if it is not in any of the requested groups, or
46-
# not for the current platform, or doesn't match the gem constraints.
47-
next unless (dep.groups & groups).any? && dep.should_include?
44+
dependencies = @definition.dependencies.select do |dep|
45+
# Select the dependency if it is in any of the requested groups, and
46+
# for the current platform, and matches the gem constraints.
47+
(dep.groups & groups).any? && dep.should_include?
48+
end
49+
50+
Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE_ALL, dependencies)
4851

52+
dependencies.each do |dep|
4953
required_file = nil
54+
Plugin.hook(Plugin::Events::GEM_BEFORE_REQUIRE, dep)
5055

5156
begin
5257
# Loop through all the specified autorequires for the
@@ -76,7 +81,13 @@ def require(*groups)
7681
end
7782
end
7883
end
84+
85+
Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE, dep)
7986
end
87+
88+
Plugin.hook(Plugin::Events::GEM_AFTER_REQUIRE_ALL, dependencies)
89+
90+
dependencies
8091
end
8192

8293
def self.definition_method(meth)

bundler/spec/plugins/hook_spec.rb

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,103 @@
106106
expect(out).to include "installed gem rack : installed"
107107
end
108108
end
109+
110+
context "before-require-all hook" do
111+
before do
112+
build_repo2 do
113+
build_plugin "before-require-all-plugin" do |s|
114+
s.write "plugins.rb", <<-RUBY
115+
Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE_ALL do |deps|
116+
puts "gems to be required \#{deps.map(&:name).join(", ")}"
117+
end
118+
RUBY
119+
end
120+
end
121+
122+
bundle "plugin install before-require-all-plugin --source #{file_uri_for(gem_repo2)}"
123+
end
124+
125+
it "runs before all rubygems are required" do
126+
install_gemfile_and_bundler_require
127+
expect(out).to include "gems to be required rake, rack"
128+
end
129+
end
130+
131+
context "before-require hook" do
132+
before do
133+
build_repo2 do
134+
build_plugin "before-require-plugin" do |s|
135+
s.write "plugins.rb", <<-RUBY
136+
Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_BEFORE_REQUIRE do |dep|
137+
puts "requiring gem \#{dep.name}"
138+
end
139+
RUBY
140+
end
141+
end
142+
143+
bundle "plugin install before-require-plugin --source #{file_uri_for(gem_repo2)}"
144+
end
145+
146+
it "runs before each rubygem is required" do
147+
install_gemfile_and_bundler_require
148+
expect(out).to include "requiring gem rake"
149+
expect(out).to include "requiring gem rack"
150+
end
151+
end
152+
153+
context "after-require-all hook" do
154+
before do
155+
build_repo2 do
156+
build_plugin "after-require-all-plugin" do |s|
157+
s.write "plugins.rb", <<-RUBY
158+
Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE_ALL do |deps|
159+
puts "required gems \#{deps.map(&:name).join(", ")}"
160+
end
161+
RUBY
162+
end
163+
end
164+
165+
bundle "plugin install after-require-all-plugin --source #{file_uri_for(gem_repo2)}"
166+
end
167+
168+
it "runs after all rubygems are required" do
169+
install_gemfile_and_bundler_require
170+
expect(out).to include "required gems rake, rack"
171+
end
172+
end
173+
174+
context "after-require hook" do
175+
before do
176+
build_repo2 do
177+
build_plugin "after-require-plugin" do |s|
178+
s.write "plugins.rb", <<-RUBY
179+
Bundler::Plugin::API.hook Bundler::Plugin::Events::GEM_AFTER_REQUIRE do |dep|
180+
puts "required gem \#{dep.name}"
181+
end
182+
RUBY
183+
end
184+
end
185+
186+
bundle "plugin install after-require-plugin --source #{file_uri_for(gem_repo2)}"
187+
end
188+
189+
it "runs after each rubygem is required" do
190+
install_gemfile_and_bundler_require
191+
expect(out).to include "required gem rake"
192+
expect(out).to include "required gem rack"
193+
end
194+
end
195+
196+
def install_gemfile_and_bundler_require
197+
install_gemfile <<-G
198+
source "#{file_uri_for(gem_repo1)}"
199+
gem "rake"
200+
gem "rack"
201+
G
202+
203+
ruby <<-RUBY
204+
require "bundler"
205+
Bundler.require
206+
RUBY
207+
end
109208
end

0 commit comments

Comments
 (0)