summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomhuda <tomhuda@tilde.io>2012-03-07 00:51:31 -0800
committertomhuda <tomhuda@tilde.io>2012-03-07 00:51:31 -0800
commite31a1c7b24d3dfbce7ed39b6a723dd20f7d08c95 (patch)
tree89802ff67e901587aa019ca36c4bdd722c60fe69
parent6d4962dbad7c620045a02393a5878b29ab11a55b (diff)
downloadbundler-e31a1c7b24d3dfbce7ed39b6a723dd20f7d08c95.tar.gz
Clean up corrupted lockfiles
Bundler 1.1.pre.5 introduced a bug that could introduce duplicate GIT sections, which then caused duplicate copies of gems in the GIT sections. This commit makes the LockfileParser aware of the bug, and has it clean up any corrupted lockfiles.
-rw-r--r--lib/bundler/lazy_specification.rb5
-rw-r--r--lib/bundler/lockfile_parser.rb21
-rw-r--r--spec/lock/lockfile_spec.rb70
-rw-r--r--spec/support/helpers.rb6
4 files changed, 101 insertions, 1 deletions
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index e9d6b22656..b10d142b74 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -25,6 +25,11 @@ module Bundler
end
end
+ def ==(other)
+ [name, version, dependencies, platform, source] ==
+ [other.name, other.version, other.dependencies, other.platform, other.source]
+ end
+
def satisfies?(dependency)
@name == dependency.name && dependency.requirement.satisfied_by?(Gem::Version.new(@version))
end
diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb
index bd79070547..813f24ace3 100644
--- a/lib/bundler/lockfile_parser.rb
+++ b/lib/bundler/lockfile_parser.rb
@@ -1,5 +1,15 @@
require "strscan"
+# Some versions of the Bundler 1.1 RC series introduced corrupted
+# lockfiles. There were two major problems:
+#
+# * multiple copies of the same GIT section appeared in the lockfile
+# * when this happened, those sections got multiple copies of gems
+# in those sections.
+#
+# As a result, Bundler 1.1 contains code that fixes the earlier
+# corruption. We will remove this fix-up code in Bundler 1.2.
+
module Bundler
class LockfileParser
attr_reader :sources, :dependencies, :specs, :platforms
@@ -37,6 +47,12 @@ module Bundler
@opts, @type = {}, line
when " specs:"
@current_source = TYPES[@type].from_lock(@opts)
+
+ # Strip out duplicate GIT sections
+ if @sources.include?(@current_source)
+ @current_source = @sources.find { |s| s == @current_source }
+ end
+
@sources << @current_source
when /^ ([a-z]+): (.*)$/i
value = $2
@@ -89,7 +105,10 @@ module Bundler
platform = $3 ? Gem::Platform.new($3) : Gem::Platform::RUBY
@current_spec = LazySpecification.new(name, version, platform)
@current_spec.source = @current_source
- @specs << @current_spec
+
+ # Avoid introducing multiple copies of the same spec (caused by
+ # duplicate GIT sections)
+ @specs << @current_spec unless @specs.include?(@current_spec)
elsif line =~ %r{^ {6}#{NAME_VERSION}$}
name, version = $1, $2
version = version.split(',').map { |d| d.strip } if version
diff --git a/spec/lock/lockfile_spec.rb b/spec/lock/lockfile_spec.rb
index d920571edd..07f614101a 100644
--- a/spec/lock/lockfile_spec.rb
+++ b/spec/lock/lockfile_spec.rb
@@ -670,6 +670,76 @@ describe "the lockfile format" do
end
+ # Some versions of the Bundler 1.1 RC series introduced corrupted
+ # lockfiles. There were two major problems:
+ #
+ # * multiple copies of the same GIT section appeared in the lockfile
+ # * when this happened, those sections got multiple copies of gems
+ # in those sections.
+ it "fix corrupted lockfiles" do
+ build_git "omg", :path => lib_path('omg')
+ revision = revision_for(lib_path('omg'))
+
+ gemfile <<-G
+ source "file://#{gem_repo1}"
+ gem "omg", :git => "#{lib_path('omg')}", :branch => 'master'
+ G
+
+ bundle "install --path vendor"
+ should_be_installed "omg 1.0"
+
+ # Create a Gemfile.lock that has duplicate GIT sections
+ lockfile <<-L
+ GIT
+ remote: #{lib_path('omg')}
+ revision: #{revision}
+ branch: master
+ specs:
+ omg (1.0)
+
+ GIT
+ remote: #{lib_path('omg')}
+ revision: #{revision}
+ branch: master
+ specs:
+ omg (1.0)
+
+ GEM
+ remote: file:#{gem_repo1}/
+ specs:
+
+ PLATFORMS
+ #{local}
+
+ DEPENDENCIES
+ omg!
+ L
+
+ FileUtils.rm_rf(bundled_app('vendor'))
+ bundle "install"
+ should_be_installed "omg 1.0"
+
+ # Confirm that duplicate specs do not appear
+ File.read(bundled_app('Gemfile.lock')).should == strip_whitespace(<<-L)
+ GIT
+ remote: #{lib_path('omg')}
+ revision: #{revision}
+ branch: master
+ specs:
+ omg (1.0)
+
+ GEM
+ remote: file:#{gem_repo1}/
+ specs:
+
+ PLATFORMS
+ #{local}
+
+ DEPENDENCIES
+ omg!
+ L
+ end
+
describe "line endings" do
def set_lockfile_mtime_to_known_value
time = Time.local(2000, 1, 1, 0, 0, 0)
diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb
index 1466dc992a..c7f5c5bcdc 100644
--- a/spec/support/helpers.rb
+++ b/spec/support/helpers.rb
@@ -162,6 +162,12 @@ module Spec
end
end
+ def strip_whitespace(str)
+ # Trim the leading spaces
+ spaces = str[/\A\s+/, 0] || ""
+ str.gsub(/^#{spaces}/, '')
+ end
+
def install_gemfile(*args)
gemfile(*args)
opts = args.last.is_a?(Hash) ? args.last : {}