diff options
author | tomhuda <tomhuda@tilde.io> | 2012-03-07 00:51:31 -0800 |
---|---|---|
committer | tomhuda <tomhuda@tilde.io> | 2012-03-07 00:51:31 -0800 |
commit | e31a1c7b24d3dfbce7ed39b6a723dd20f7d08c95 (patch) | |
tree | 89802ff67e901587aa019ca36c4bdd722c60fe69 | |
parent | 6d4962dbad7c620045a02393a5878b29ab11a55b (diff) | |
download | bundler-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.rb | 5 | ||||
-rw-r--r-- | lib/bundler/lockfile_parser.rb | 21 | ||||
-rw-r--r-- | spec/lock/lockfile_spec.rb | 70 | ||||
-rw-r--r-- | spec/support/helpers.rb | 6 |
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 : {} |