diff options
author | Andre Arko <andre@arko.net> | 2014-12-07 22:21:27 -0800 |
---|---|---|
committer | Andre Arko <andre@arko.net> | 2014-12-07 22:21:27 -0800 |
commit | 8fbfe9b79f7ec9706b627793ce49b7607481ff5d (patch) | |
tree | 2f8be83873aa1ca87524780d2b8b07bf2f663869 | |
parent | 6140bc3b68bff39a938ff29a192146aaa9248903 (diff) | |
parent | 278122687006af1c553b64fbe6f6cf4b7950eec1 (diff) | |
download | bundler-8fbfe9b79f7ec9706b627793ce49b7607481ff5d.tar.gz |
Merge pull request #3278 from bundler/resolver_bug_fix
Resolver bug fixes and improvements
Conflicts:
CHANGELOG.md
-rw-r--r-- | CHANGELOG.md | 8 | ||||
-rw-r--r-- | lib/bundler/resolver.rb | 47 | ||||
-rw-r--r-- | spec/realworld/edgecases_spec.rb | 35 |
3 files changed, 76 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f46f0602..ba8e33b87b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 1.7.9 + +Bugfixes: + + - Fix an issue where bundler sometime spams one gem in Gemfile.lock (#3216, @Who828) + - Ensure bundle update installs the newer version of the gem (#3089, @Who828) + - Fix an regression which stopped Bundler from resolving some Gemfiles (#3059, #3248, @Who828) + ## 1.7.8 (2014-12-06) Bugfixes: diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 7c4a10482e..a8d3d1a7ff 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -110,7 +110,7 @@ module Bundler end end - attr_reader :errors, :started_at, :iteration_rate, :iteration_counter + attr_reader :errors, :started_at, :iteration_rate, :iteration_counter, :initial_reqs # Figures out the best possible configuration of gems that satisfies # the list of passed dependencies and any child dependencies without @@ -135,6 +135,7 @@ module Bundler end def initialize(index, source_requirements, base) + @initial_reqs = [] @errors = {} @base = base @index = index @@ -157,11 +158,12 @@ module Bundler activated.values.map { |s| s.to_specs }.flatten.compact end - def start(reqs) + def start(reqs, current_traversal=false) + @initial_reqs = reqs.dup unless current_traversal activated = {} @gems_size = Hash[reqs.map { |r| [r, gems_size(r)] }] - resolve(reqs, activated) + resolve(reqs, activated, current_traversal) end class State < Struct.new(:reqs, :activated, :requirement, :possibles, :depth, :conflicts) @@ -171,13 +173,16 @@ module Bundler end def handle_conflict(current, states, existing=nil) - until current.nil? && existing.nil? + until current.nil? current_state = find_state(current, states) - existing_state = find_state(existing, states) return current if state_any?(current_state) + current = current.required_by.last if current + end + + until existing.nil? + existing_state = find_state(existing, states) return existing if state_any?(existing_state) existing = existing.required_by.last if existing - current = current.required_by.last if current end end @@ -224,7 +229,7 @@ module Bundler end def resolve_for_conflict(state) - raise version_conflict if state.nil? || state.possibles.empty? + return version_conflict if state.nil? || state.possibles.empty? reqs, activated, depth, conflicts = state.reqs.dup, state.activated.dup, state.depth, state.conflicts.dup requirement = state.requirement possible = state.possibles.pop @@ -251,7 +256,7 @@ module Bundler return reqs, activated, depth, conflicts end - def resolve(reqs, activated) + def resolve(reqs, activated, current_traversal) states = [] depth = 0 conflicts = Set.new @@ -310,17 +315,23 @@ module Bundler conflicts << current.name parent = current.required_by.last - if existing.respond_to?(:required_by) - parent = handle_conflict(current, states, existing.required_by[-2]) unless other_possible?(parent, states) + + if current_traversal + parent = handle_conflict(current, states) else - parent = handle_conflict(current, states) unless other_possible?(parent, states) + parent = handle_conflict(parent, states) end + if parent.nil? && !conflicts.empty? parent = states.reverse.detect { |i| conflicts.include?(i.name) && state_any?(i)} end - raise version_conflict if parent.nil? || parent.name == 'bundler' + if existing.respond_to?(:required_by) + parent = handle_conflict(parent, states, existing.required_by[-2]) unless other_possible?(parent, states) + end + + return version_conflict(current_traversal) if parent.nil? || parent.name == 'bundler' reqs, activated, depth, conflicts = resolve_conflict(parent, states) end @@ -364,6 +375,7 @@ module Bundler end end + state = State.new(reqs.dup, activated.dup, current, matching_versions, depth, conflicts) states << state requirement = state.possibles.pop @@ -418,8 +430,15 @@ module Bundler end end - def version_conflict - VersionConflict.new(errors.keys, error_message) + def version_conflict(current_traversal=true) + raise VersionConflict.new(errors.keys, error_message) if current_traversal + reset_state + start(initial_reqs, true) + end + + def reset_state + clear_search_cache + @errors = {} end # For a given conflicted requirement, print out what exactly went wrong diff --git a/spec/realworld/edgecases_spec.rb b/spec/realworld/edgecases_spec.rb index 263ac520b3..000ded4fd0 100644 --- a/spec/realworld/edgecases_spec.rb +++ b/spec/realworld/edgecases_spec.rb @@ -35,6 +35,41 @@ describe "real world edgecases", :realworld => true do expect(out).to include("activemodel 3.0.5") end + it "resolves dependencies correctly", :ruby => "1.9" do + install_gemfile <<-G + source "https://rubygems.org" + + gem 'rails', '~> 3.0' + gem 'capybara', '~> 2.2.0' + G + expect(out).to include("rails 3.2.21") + expect(out).to include("capybara 2.2.1") + end + + it "installs the latest version of gxapi_rails", :ruby => "1.9" do + install_gemfile <<-G + source "https://rubygems.org" + + gem "sass-rails" + gem "rails", "~> 3" + gem "gxapi_rails" + G + expect(out).to include("gxapi_rails 0.0.6") + end + + it "installs the latest version of i18n" do + install_gemfile <<-G + source "https://rubygems.org" + + gem "i18n", "~> 0.4" + gem "activesupport", "~> 3.0" + gem "activerecord", "~> 3.0" + gem "builder", "~> 2.1.2" + G + expect(out).to include("i18n 0.6.11") + expect(out).to include("activesupport 3.0.5") + end + # https://github.com/bundler/bundler/issues/1500 it "does not fail install because of gem plugins" do realworld_system_gems("open_gem --version 1.4.2", "rake --version 0.9.2") |