summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md8
-rw-r--r--lib/bundler/resolver.rb47
-rw-r--r--spec/realworld/edgecases_spec.rb35
3 files changed, 76 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13b10aed85..16564d5acb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,14 @@ Features:
Documentation:
- add missing Gemfile global `path` explanation (@agenteo)
+## 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 218a69969d..709ad67a34 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
@@ -158,11 +159,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)
@@ -172,13 +174,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
@@ -225,7 +230,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
@@ -252,7 +257,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
@@ -311,17 +316,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
@@ -365,6 +376,7 @@ module Bundler
end
end
+
state = State.new(reqs.dup, activated.dup, current, matching_versions, depth, conflicts)
states << state
requirement = state.possibles.pop
@@ -419,8 +431,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")