diff options
author | The Bundler Bot <bot@bundler.io> | 2017-02-18 16:46:06 +0000 |
---|---|---|
committer | Samuel Giddins <segiddins@segiddins.me> | 2017-02-22 11:54:12 +1100 |
commit | f0b146043d2478e8a0ad0d0790b382cfd4fe2948 (patch) | |
tree | 46ebecefc28f24bfcf4b3955e9078fdd1e752005 | |
parent | 711ea8d212b22fc062a69be6b2768887cf737f8e (diff) | |
download | bundler-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.rb | 7 | ||||
-rw-r--r-- | lib/bundler/errors.rb | 1 | ||||
-rw-r--r-- | lib/bundler/installer/gem_installer.rb | 2 | ||||
-rw-r--r-- | lib/bundler/lazy_specification.rb | 9 | ||||
-rw-r--r-- | lib/bundler/remote_specification.rb | 7 | ||||
-rw-r--r-- | lib/bundler/source/rubygems/remote.rb | 4 | ||||
-rw-r--r-- | spec/bundler/remote_specification_spec.rb | 4 | ||||
-rw-r--r-- | spec/install/gemfile/platform_spec.rb | 26 | ||||
-rw-r--r-- | spec/install/gemfile/specific_platform_spec.rb | 20 | ||||
-rw-r--r-- | spec/install/gems/compact_index_spec.rb | 16 | ||||
-rw-r--r-- | spec/support/artifice/compact_index_wrong_dependencies.rb | 16 |
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) |