Permalink
Browse files

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.
  • Loading branch information...
1 parent 6d4962d commit e31a1c7b24d3dfbce7ed39b6a723dd20f7d08c95 tomhuda committed Mar 7, 2012
Showing with 101 additions and 1 deletion.
  1. +5 −0 lib/bundler/lazy_specification.rb
  2. +20 −1 lib/bundler/lockfile_parser.rb
  3. +70 −0 spec/lock/lockfile_spec.rb
  4. +6 −0 spec/support/helpers.rb
@@ -25,6 +25,11 @@ def full_name
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
@@ -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 @@ def parse_source(line)
@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 @@ def parse_spec(line)
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
View
@@ -670,6 +670,76 @@
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)
View
@@ -162,6 +162,12 @@ def lockfile(*args)
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 : {}

0 comments on commit e31a1c7

Please sign in to comment.