summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Rafaniello <jrafanie@redhat.com>2016-06-16 17:36:05 -0400
committerJoe Rafaniello <jrafanie@redhat.com>2016-06-17 12:57:28 -0400
commit33e238d3b0a0a779ef7de1af02e0b34138f3cb66 (patch)
tree687c4d2baa933150e01c9f2f0961439321056612
parent8920da0e6610ed2a1ce52c7ec66fa5a91bbb6a2a (diff)
downloadbundler-33e238d3b0a0a779ef7de1af02e0b34138f3cb66.tar.gz
Detect changes in path specs by comparing locked specs to source specs
Previously, we'd wrongly conclude there are no path changes when there are changes. We'd parse the Gemfile.lock and compare the source.specs, the gemspecs currently in the path, to what's in the Gemfile.lock's locked.specs. Unfortunately, locked.specs for Path sources creates an Index with the specs from the filesystem and NOT what we already parsed from the Gemfile.lock! In other words, we compare the filesystems specs for a path to itself and always conclude "No changes detected!" Instead, we build an index with specs for the source we want from the already parsed Gemfile.lock. We use this index to compare to the current source.specs index from the filesystem. Ironically, this issue was masked by the bug from our prior fix, namely that dependencies_for_source_changed? always would conclude that there were changes. Because of that bug, it would short circuit out of the nothing_changed? method and force a re-resolve with path gems, which would properly build the Gemfile.lock from the prior parsed one. Undo some test changes needed to get the first fix to pass.
-rw-r--r--lib/bundler/definition.rb9
-rw-r--r--spec/bundler/definition_spec.rb113
-rw-r--r--spec/install/gemfile/path_spec.rb5
3 files changed, 117 insertions, 10 deletions
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 852f343509..efc249be91 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -482,7 +482,7 @@ module Bundler
end
end
- !locked || unlocking || dependencies_for_source_changed?(locked) || source.specs != locked.specs
+ !locked || unlocking || dependencies_for_source_changed?(source) || specs_for_source_changed?(source)
end
def dependencies_for_source_changed?(source)
@@ -492,6 +492,13 @@ module Bundler
Set.new(deps_for_source) != Set.new(locked_deps_for_source)
end
+ def specs_for_source_changed?(source)
+ locked_index = Index.new
+ locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
+
+ source.specs != locked_index
+ end
+
# Get all locals and override their matching sources.
# Return true if any of the locals changed (for example,
# they point to a new revision) or depend on new specs.
diff --git a/spec/bundler/definition_spec.rb b/spec/bundler/definition_spec.rb
index 6e347dbdc2..02049b557a 100644
--- a/spec/bundler/definition_spec.rb
+++ b/spec/bundler/definition_spec.rb
@@ -3,13 +3,12 @@ require "spec_helper"
require "bundler/definition"
describe Bundler::Definition do
- before do
- allow(Bundler).to receive(:settings) { Bundler::Settings.new(".") }
- allow(Bundler).to receive(:default_gemfile) { Pathname.new("Gemfile") }
- allow(Bundler).to receive(:ui) { double("UI", :info => "", :debug => "") }
- end
-
describe "#lock" do
+ before do
+ allow(Bundler).to receive(:settings) { Bundler::Settings.new(".") }
+ allow(Bundler).to receive(:default_gemfile) { Pathname.new("Gemfile") }
+ allow(Bundler).to receive(:ui) { double("UI", :info => "", :debug => "") }
+ end
context "when it's not possible to write to the file" do
subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) }
@@ -31,4 +30,106 @@ describe Bundler::Definition do
end
end
end
+
+ describe "detects changes" do
+ it "for a path gem with changes" do
+ build_lib "foo", "1.0", :path => lib_path("foo")
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "foo", :path => "#{lib_path("foo")}"
+ G
+
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
+ end
+
+ bundle :install, :env => { "DEBUG" => 1 }
+
+ expect(out).to match(/re-resolving dependencies/)
+ lockfile_should_be <<-G
+ PATH
+ remote: #{lib_path("foo")}
+ specs:
+ foo (1.0)
+ rack (= 1.0)
+
+ GEM
+ remote: file:#{gem_repo1}/
+ specs:
+ rack (1.0.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ foo!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+ end
+
+ it "for a path gem with deps and no changes" do
+ build_lib "foo", "1.0", :path => lib_path("foo") do |s|
+ s.add_dependency "rack", "1.0"
+ end
+
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "foo", :path => "#{lib_path("foo")}"
+ G
+
+ bundle :check, :env => { "DEBUG" => 1 }
+
+ expect(out).to match(/using resolution from the lockfile/)
+ lockfile_should_be <<-G
+ PATH
+ remote: #{lib_path("foo")}
+ specs:
+ foo (1.0)
+ rack (= 1.0)
+
+ GEM
+ remote: file:#{gem_repo1}/
+ specs:
+ rack (1.0.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ foo!
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+ end
+
+ it "for a rubygems gem" do
+ install_gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "foo"
+ G
+
+ bundle :check, :env => { "DEBUG" => 1 }
+
+ expect(out).to match(/using resolution from the lockfile/)
+ lockfile_should_be <<-G
+ GEM
+ remote: file:#{gem_repo1}/
+ specs:
+ foo (1.0)
+
+ PLATFORMS
+ ruby
+
+ DEPENDENCIES
+ foo
+
+ BUNDLED WITH
+ #{Bundler::VERSION}
+ G
+ end
+ end
end
diff --git a/spec/install/gemfile/path_spec.rb b/spec/install/gemfile/path_spec.rb
index de4e80cb6a..39b0aed788 100644
--- a/spec/install/gemfile/path_spec.rb
+++ b/spec/install/gemfile/path_spec.rb
@@ -415,7 +415,7 @@ describe "bundle install with explicit source paths" do
build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "bar"
end
- build_lib "bar", "1.0", :path => lib_path("foo")
+ build_lib "bar", "1.0", :path => lib_path("foo/bar")
install_gemfile <<-G
gem "foo", :path => "#{lib_path("foo")}"
@@ -433,7 +433,7 @@ describe "bundle install with explicit source paths" do
end
it "unlocks all gems when a child dependency gem is updated" do
- build_lib "bar", "2.0", :path => lib_path("foo")
+ build_lib "bar", "2.0", :path => lib_path("foo/bar")
bundle "install"
@@ -452,7 +452,6 @@ describe "bundle install with explicit source paths" do
end
it "gets dependencies that are updated in the path" do
- build_lib "rack", "1.0.0", :path => lib_path("foo")
build_lib "foo", "1.0", :path => lib_path("foo") do |s|
s.add_dependency "rack"
end