summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThe Bundler Bot <bot@bundler.io>2017-02-18 16:46:06 +0000
committerSamuel Giddins <segiddins@segiddins.me>2017-02-22 11:54:12 +1100
commitf0b146043d2478e8a0ad0d0790b382cfd4fe2948 (patch)
tree46ebecefc28f24bfcf4b3955e9078fdd1e752005
parent711ea8d212b22fc062a69be6b2768887cf737f8e (diff)
downloadbundler-f0b146043d2478e8a0ad0d0790b382cfd4fe2948.tar.gz
Auto merge of #5427 - bundler:seg-api-missing-dependencies, r=indirect
Fail gracefully when installing a spec where the API is missing deps Fixes https://github.com/bundler/bundler/issues/5426 Closes https://github.com/bundler/bundler/issues/5339 (cherry picked from commit 42215fe7279bd90d48f2d4e09227d327e007b5bc)
-rw-r--r--lib/bundler/endpoint_specification.rb7
-rw-r--r--lib/bundler/errors.rb1
-rw-r--r--lib/bundler/installer/gem_installer.rb2
-rw-r--r--lib/bundler/lazy_specification.rb9
-rw-r--r--lib/bundler/remote_specification.rb7
-rw-r--r--lib/bundler/source/rubygems/remote.rb4
-rw-r--r--spec/bundler/remote_specification_spec.rb4
-rw-r--r--spec/install/gemfile/platform_spec.rb26
-rw-r--r--spec/install/gemfile/specific_platform_spec.rb20
-rw-r--r--spec/install/gems/compact_index_spec.rb16
-rw-r--r--spec/support/artifice/compact_index_wrong_dependencies.rb16
11 files changed, 108 insertions, 4 deletions
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index 4f5377d3cc..5e14f03265 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -91,6 +91,13 @@ module Bundler
end
def __swap__(spec)
+ without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) }
+ if (extra_deps = spec.runtime_dependencies.map(&without_type).-(dependencies.map(&without_type))) && extra_deps.any?
+ Bundler.ui.debug "#{full_name} from #{remote} has corrupted API dependencies (API returned #{dependencies}, real spec has (#{spec.runtime_dependencies}))"
+ raise APIResponseMismatchError,
+ "Downloading #{full_name} revealed dependencies not in the API (#{extra_deps.map(&:to_s).join(", ")})." \
+ "\nInstalling with `--full-index` should fix the problem."
+ end
@remote_specification = spec
end
diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb
index ecd9260ea0..9ef1286936 100644
--- a/lib/bundler/errors.rb
+++ b/lib/bundler/errors.rb
@@ -54,6 +54,7 @@ module Bundler
class PluginError < BundlerError; status_code(29); end
class SudoNotPermittedError < BundlerError; status_code(30); end
class ThreadCreationError < BundlerError; status_code(33); end
+ class APIResponseMismatchError < BundlerError; status_code(34); end
class GemfileEvalError < GemfileError; end
class MarshalError < StandardError; end
diff --git a/lib/bundler/installer/gem_installer.rb b/lib/bundler/installer/gem_installer.rb
index b6eb221389..0589d14e40 100644
--- a/lib/bundler/installer/gem_installer.rb
+++ b/lib/bundler/installer/gem_installer.rb
@@ -16,7 +16,7 @@ module Bundler
Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
generate_executable_stubs
return true, post_install_message
- rescue Bundler::InstallHookError, Bundler::SecurityError
+ rescue Bundler::InstallHookError, Bundler::SecurityError, APIResponseMismatchError
raise
rescue Errno::ENOSPC
return false, out_of_space_message
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index ed21a9aad4..adafa42342 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -72,7 +72,14 @@ module Bundler
@specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name
source.gemspec.tap {|s| s.source = source }
else
- source.specs.search(search_object).last
+ search = source.specs.search(search_object).last
+ if search && search.platform != platform && !search.runtime_dependencies.-(dependencies.reject {|d| d.type == :development }).empty?
+ Bundler.ui.warn "Unable to use the platform-specific (#{search.platform}) version of #{name} (#{version}) " \
+ "because it has different dependencies from the #{platform} version. " \
+ "To use the platform-specific version of the gem, run `bundle config specific_platform true` and install again."
+ search = source.specs.search(self).last
+ end
+ search
end
end
diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb
index 944ff1adbd..e5f9c78b00 100644
--- a/lib/bundler/remote_specification.rb
+++ b/lib/bundler/remote_specification.rb
@@ -49,6 +49,13 @@ module Bundler
# once the remote gem is downloaded, the backend specification will
# be swapped out.
def __swap__(spec)
+ without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list) }
+ if (extra_deps = spec.runtime_dependencies.map(&without_type).-(dependencies.map(&without_type))) && extra_deps.any?
+ Bundler.ui.debug "#{full_name} from #{remote} has corrupted API dependencies (API returned #{dependencies}, real spec has (#{spec.runtime_dependencies}))"
+ raise APIResponseMismatchError,
+ "Downloading #{full_name} revealed dependencies not in the API (#{extra_deps.map(&without_type).map(&:to_s).join(", ")})." \
+ "\nInstalling with `--full-index` should fix the problem."
+ end
@_remote_specification = spec
end
diff --git a/lib/bundler/source/rubygems/remote.rb b/lib/bundler/source/rubygems/remote.rb
index 92f8a40588..b49e645506 100644
--- a/lib/bundler/source/rubygems/remote.rb
+++ b/lib/bundler/source/rubygems/remote.rb
@@ -30,6 +30,10 @@ module Bundler
end
end
+ def to_s
+ "rubygems remote at #{anonymized_uri}"
+ end
+
private
def apply_auth(uri, auth)
diff --git a/spec/bundler/remote_specification_spec.rb b/spec/bundler/remote_specification_spec.rb
index d958ca85eb..03eeccb528 100644
--- a/spec/bundler/remote_specification_spec.rb
+++ b/spec/bundler/remote_specification_spec.rb
@@ -128,8 +128,8 @@ describe Bundler::RemoteSpecification do
end
describe "#__swap__" do
- let(:spec) { double(:spec) }
- let(:new_spec) { double(:new_spec) }
+ let(:spec) { double(:spec, :dependencies => []) }
+ let(:new_spec) { double(:new_spec, :runtime_dependencies => []) }
before { subject.instance_variable_set(:@_remote_specification, spec) }
diff --git a/spec/install/gemfile/platform_spec.rb b/spec/install/gemfile/platform_spec.rb
index e9d42b93d4..299f8ad155 100644
--- a/spec/install/gemfile/platform_spec.rb
+++ b/spec/install/gemfile/platform_spec.rb
@@ -88,6 +88,32 @@ describe "bundle install across platforms" do
expect(the_bundle).to include_gems "nokogiri 1.4.2 JAVA", "weakling 0.0.3"
end
+ it "works with gems that have extra platform-specific runtime dependencies" do
+ simulate_platform x64_mac
+
+ update_repo2 do
+ build_gem "facter", "2.4.6"
+ build_gem "facter", "2.4.6" do |s|
+ s.platform = "universal-darwin"
+ s.add_runtime_dependency "CFPropertyList"
+ end
+ build_gem "CFPropertyList"
+ end
+
+ install_gemfile! <<-G
+ source "file://#{gem_repo2}"
+
+ gem "facter"
+ G
+
+ expect(out).to include "Unable to use the platform-specific (universal-darwin) version of facter (2.4.6) " \
+ "because it has different dependencies from the ruby version. " \
+ "To use the platform-specific version of the gem, run `bundle config specific_platform true` and install again."
+
+ expect(the_bundle).to include_gem "facter 2.4.6"
+ expect(the_bundle).not_to include_gem "CFPropertyList"
+ end
+
it "fetches gems again after changing the version of Ruby" do
gemfile <<-G
source "file://#{gem_repo1}"
diff --git a/spec/install/gemfile/specific_platform_spec.rb b/spec/install/gemfile/specific_platform_spec.rb
index 3e12f94c86..0bb08ef08b 100644
--- a/spec/install/gemfile/specific_platform_spec.rb
+++ b/spec/install/gemfile/specific_platform_spec.rb
@@ -39,6 +39,13 @@ describe "bundle install with specific_platform enabled" do
build_gem("google-protobuf", "3.0.0.alpha.2.0")
build_gem("google-protobuf", "3.0.0.alpha.1.1")
build_gem("google-protobuf", "3.0.0.alpha.1.0")
+
+ build_gem("facter", "2.4.6")
+ build_gem("facter", "2.4.6") do |s|
+ s.platform = "universal-darwin"
+ s.add_runtime_dependency "CFPropertyList"
+ end
+ build_gem("CFPropertyList")
end
end
@@ -67,6 +74,19 @@ describe "bundle install with specific_platform enabled" do
to all(exist)
end
+ it "uses the platform-specific gem with extra dependencies" do
+ install_gemfile! <<-G
+ source "file:#{gem_repo2}"
+ gem "facter"
+ G
+
+ expect(the_bundle.locked_gems.platforms).to eq([pl("ruby"), pl("x86_64-darwin-15")])
+ expect(the_bundle).to include_gems("facter 2.4.6 universal-darwin", "CFPropertyList 1.0")
+ expect(the_bundle.locked_gems.specs.map(&:full_name)).to eq(["CFPropertyList-1.0",
+ "facter-2.4.6",
+ "facter-2.4.6-universal-darwin"])
+ end
+
context "when adding a platform via lock --add_platform" do
it "adds the foreign platform" do
install_gemfile!(google_protobuf)
diff --git a/spec/install/gems/compact_index_spec.rb b/spec/install/gems/compact_index_spec.rb
index 04cc5d740e..fc2c8358c9 100644
--- a/spec/install/gems/compact_index_spec.rb
+++ b/spec/install/gems/compact_index_spec.rb
@@ -753,4 +753,20 @@ The checksum of /versions does not match the checksum provided by the server! So
gem "rack"
G
end
+
+ it "doesn't explode when the API dependencies are wrong" do
+ install_gemfile <<-G, :artifice => "compact_index_wrong_dependencies", :env => { "DEBUG" => "true" }
+ source "#{source_uri}"
+ gem "rails"
+ G
+ deps = [Gem::Dependency.new("rake", "= 10.0.2"),
+ Gem::Dependency.new("actionpack", "= 2.3.2"),
+ Gem::Dependency.new("activerecord", "= 2.3.2"),
+ Gem::Dependency.new("actionmailer", "= 2.3.2"),
+ Gem::Dependency.new("activeresource", "= 2.3.2")]
+ expect(out).to include(<<-E.strip).and include("rails-2.3.2 from rubygems remote at #{source_uri}/ has corrupted API dependencies")
+Downloading rails-2.3.2 revealed dependencies not in the API (#{deps.join(", ")}).
+Installing with `--full-index` should fix the problem.
+ E
+ end
end
diff --git a/spec/support/artifice/compact_index_wrong_dependencies.rb b/spec/support/artifice/compact_index_wrong_dependencies.rb
new file mode 100644
index 0000000000..25935f5e5d
--- /dev/null
+++ b/spec/support/artifice/compact_index_wrong_dependencies.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+require File.expand_path("../compact_index", __FILE__)
+
+Artifice.deactivate
+
+class CompactIndexWrongDependencies < CompactIndexAPI
+ get "/info/:name" do
+ etag_response do
+ gem = gems.find {|g| g.name == params[:name] }
+ gem.versions.each {|gv| gv.dependencies.clear } if gem
+ CompactIndex.info(gem ? gem.versions : [])
+ end
+ end
+end
+
+Artifice.activate_with(CompactIndexWrongDependencies)