summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Giddins <segiddins@segiddins.me>2017-04-06 19:25:25 -0500
committerSamuel Giddins <segiddins@segiddins.me>2017-04-07 12:02:55 -0500
commit1b333a6768ce8708c7d01bffc27a46952e5b6011 (patch)
tree5043ac91c9d988d1a9e31a70801da12240c14203
parent8b95a4858e15cf667c70db8c4d9c0333a28b55e8 (diff)
downloadbundler-1b333a6768ce8708c7d01bffc27a46952e5b6011.tar.gz
[Git] Avoid loading full gemspecs in -rbundler/setup when stubs are available
-rw-r--r--lib/bundler/source/git.rb8
-rw-r--r--lib/bundler/source/path.rb10
-rw-r--r--lib/bundler/stub_specification.rb11
-rw-r--r--spec/runtime/require_spec.rb24
4 files changed, 50 insertions, 3 deletions
diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb
index c95c94583f..d92b741202 100644
--- a/lib/bundler/source/git.rb
+++ b/lib/bundler/source/git.rb
@@ -234,6 +234,7 @@ module Bundler
# The gemspecs we cache should already be evaluated.
spec = Bundler.load_gemspec(spec_path)
next unless spec
+ Bundler.rubygems.set_installed_by_version(spec)
Bundler.rubygems.validate(spec)
File.open(spec_path, "wb") {|file| file.write(spec.to_ruby) }
end
@@ -302,6 +303,13 @@ module Bundler
# no-op, since we validate when re-serializing the gemspec
def validate_spec(_spec); end
+
+ if defined?(::Gem::StubSpecification)
+ def load_gemspec(file)
+ stub = Gem::StubSpecification.gemspec_stub(file, install_path.parent, install_path.parent)
+ StubSpecification.from_stub(stub)
+ end
+ end
end
end
end
diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index 4b01496aac..0ad0a029f0 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -144,6 +144,12 @@ module Bundler
SharedHelpers.in_bundle? && app_cache_path.exist?
end
+ def load_gemspec(file)
+ return unless spec = Bundler.load_gemspec(file)
+ Bundler.rubygems.set_installed_by_version(spec)
+ spec
+ end
+
def validate_spec(spec)
Bundler.rubygems.validate(spec)
end
@@ -154,9 +160,9 @@ module Bundler
if File.directory?(expanded_path)
# We sort depth-first since `<<` will override the earlier-found specs
Dir["#{expanded_path}/#{@glob}"].sort_by {|p| -p.split(File::SEPARATOR).size }.each do |file|
- next unless spec = Bundler.load_gemspec(file)
+ next unless spec = load_gemspec(file)
spec.source = self
- Bundler.rubygems.set_installed_by_version(spec)
+
# Validation causes extension_dir to be calculated, which depends
# on #source, so we validate here instead of load_gemspec
validate_spec(spec)
diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb
index 9e43f06364..2e8938e12d 100644
--- a/lib/bundler/stub_specification.rb
+++ b/lib/bundler/stub_specification.rb
@@ -36,8 +36,17 @@ module Bundler
stub.default_gem
end
+ # This is what we do in bundler/rubygems_ext
def full_gem_path
- stub.full_gem_path
+ # this cannot check source.is_a?(Bundler::Plugin::API::Source)
+ # because that _could_ trip the autoload, and if there are unresolved
+ # gems at that time, this method could be called inside another require,
+ # thus raising with that constant being undefined. Better to check a method
+ if source.respond_to?(:path) || (source.respond_to?(:bundler_plugin_api_source?) && source.bundler_plugin_api_source?)
+ Pathname.new(loaded_from).dirname.expand_path(source.root).to_s.untaint
+ else
+ rg_full_gem_path
+ end
end
def full_require_paths
diff --git a/spec/runtime/require_spec.rb b/spec/runtime/require_spec.rb
index 716080deb0..c07f6344fd 100644
--- a/spec/runtime/require_spec.rb
+++ b/spec/runtime/require_spec.rb
@@ -383,6 +383,30 @@ RSpec.describe "Bundler.require" do
expect(out).to eq("WIN")
end
+
+ it "does not load git gemspecs that are used", :rubygems => ">= 2.3" do
+ build_git "foo"
+
+ install_gemfile! <<-G
+ gem "foo", :git => "#{lib_path("foo-1.0")}"
+ G
+
+ run! <<-R
+ path = Gem.loaded_specs["foo"].loaded_from
+ contents = File.read(path)
+ contents = contents.lines.insert(-2, "\n raise 'broken gemspec'\n").join
+ File.open(path, "w") do |f|
+ f.write contents
+ end
+ R
+
+ run! <<-R
+ Bundler.require
+ puts "WIN"
+ R
+
+ expect(out).to eq("WIN")
+ end
end
RSpec.describe "Bundler.require with platform specific dependencies" do