diff options
author | Samuel Giddins <segiddins@segiddins.me> | 2017-04-08 17:28:58 -0500 |
---|---|---|
committer | Samuel Giddins <segiddins@segiddins.me> | 2017-04-13 20:40:29 -0500 |
commit | b05df750e92a2c12b0d47c0b9bff619bb024a0d5 (patch) | |
tree | 68715031276773dd0545d79610361ea56b7585a9 | |
parent | fe617daaaad4d4d3a48bcce90e39caff9145cfbb (diff) | |
download | bundler-b05df750e92a2c12b0d47c0b9bff619bb024a0d5.tar.gz |
Avoid deadlocking when installing with a lockfile missing dependencies
-rw-r--r-- | .rubocop_todo.yml | 21 | ||||
-rw-r--r-- | lib/bundler/endpoint_specification.rb | 12 | ||||
-rw-r--r-- | lib/bundler/lazy_specification.rb | 2 | ||||
-rw-r--r-- | lib/bundler/remote_specification.rb | 8 | ||||
-rw-r--r-- | lib/bundler/shared_helpers.rb | 15 | ||||
-rw-r--r-- | spec/lock/lockfile_spec.rb | 23 |
6 files changed, 53 insertions, 28 deletions
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d03086eab2..7d16768980 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2017-03-30 23:48:11 +0900 using RuboCop version 0.48.0. +# on 2017-04-08 17:26:10 -0500 using RuboCop version 0.48.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -72,12 +72,12 @@ Lint/UselessAssignment: - 'lib/bundler/index.rb' - 'lib/bundler/installer.rb' -# Offense count: 444 +# Offense count: 451 # Configuration parameters: CountComments, ExcludedMethods. Metrics/BlockLength: - Max: 980 + Max: 988 -# Offense count: 1991 +# Offense count: 2035 # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # URISchemes: http, https Metrics/LineLength: @@ -141,7 +141,7 @@ Style/CaseEquality: - 'lib/bundler/match_platform.rb' - 'lib/bundler/rubygems_ext.rb' -# Offense count: 24 +# Offense count: 25 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: nested, compact Style/ClassAndModuleChildren: @@ -163,11 +163,11 @@ Style/ConditionalAssignment: - 'lib/bundler/source/git.rb' - 'lib/bundler/source/rubygems.rb' -# Offense count: 154 +# Offense count: 158 Style/Documentation: Enabled: false -# Offense count: 300 +# Offense count: 304 # Cop supports --auto-correct. Style/EmptyLineAfterMagicComment: Enabled: false @@ -205,7 +205,7 @@ Style/GlobalVars: - 'lib/bundler/cli.rb' - 'spec/spec_helper.rb' -# Offense count: 18 +# Offense count: 17 # Configuration parameters: MinBodyLength. Style/GuardClause: Exclude: @@ -217,7 +217,6 @@ Style/GuardClause: - 'lib/bundler/definition.rb' - 'lib/bundler/dsl.rb' - 'lib/bundler/installer.rb' - - 'lib/bundler/lockfile_parser.rb' - 'lib/bundler/runtime.rb' - 'lib/bundler/source/path/installer.rb' - 'lib/bundler/source_list.rb' @@ -241,14 +240,14 @@ Style/IfUnlessModifierOfIfUnless: Style/IndentArray: EnforcedStyle: consistent -# Offense count: 33 +# Offense count: 34 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent Style/IndentHeredoc: Enabled: false -# Offense count: 8 +# Offense count: 9 # Cop supports --auto-correct. # Configuration parameters: InverseMethods, InverseBlocks. Style/InverseMethods: diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb index 5e14f03265..1fb5b29732 100644 --- a/lib/bundler/endpoint_specification.rb +++ b/lib/bundler/endpoint_specification.rb @@ -5,8 +5,8 @@ module Bundler ILLFORMED_MESSAGE = 'Ill-formed requirement ["#<YAML::Syck::DefaultKey'.freeze include MatchPlatform - attr_reader :name, :version, :platform, :dependencies, :required_rubygems_version, :required_ruby_version, :checksum - attr_accessor :source, :remote + attr_reader :name, :version, :platform, :required_rubygems_version, :required_ruby_version, :checksum + attr_accessor :source, :remote, :dependencies def initialize(name, version, platform, dependencies, metadata = nil) @name = name @@ -91,13 +91,7 @@ module Bundler end def __swap__(spec) - without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) } - if (extra_deps = spec.runtime_dependencies.map(&without_type).-(dependencies.map(&without_type))) && extra_deps.any? - Bundler.ui.debug "#{full_name} from #{remote} has corrupted API dependencies (API returned #{dependencies}, real spec has (#{spec.runtime_dependencies}))" - raise APIResponseMismatchError, - "Downloading #{full_name} revealed dependencies not in the API (#{extra_deps.map(&:to_s).join(", ")})." \ - "\nInstalling with `--full-index` should fix the problem." - end + SharedHelpers.ensure_same_dependencies(spec, dependencies, spec.dependencies) @remote_specification = spec end diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 46f50844e1..9a8268a2d5 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -79,7 +79,7 @@ module Bundler "To use the platform-specific version of the gem, run `bundle config specific_platform true` and install again." search = source.specs.search(self).last end - search.dependencies = dependencies if search.is_a?(RemoteSpecification) + search.dependencies = dependencies if search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification) search end end diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb index 82b5cb8c6f..cd076939c4 100644 --- a/lib/bundler/remote_specification.rb +++ b/lib/bundler/remote_specification.rb @@ -51,13 +51,7 @@ module Bundler # once the remote gem is downloaded, the backend specification will # be swapped out. def __swap__(spec) - without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list) } - if (extra_deps = spec.runtime_dependencies.map(&without_type).-(dependencies.map(&without_type))) && extra_deps.any? - Bundler.ui.debug "#{full_name} from #{remote} has corrupted API dependencies (API returned #{dependencies}, real spec has (#{spec.runtime_dependencies}))" - raise APIResponseMismatchError, - "Downloading #{full_name} revealed dependencies not in the API (#{extra_deps.map(&without_type).map(&:to_s).join(", ")})." \ - "\nInstalling with `--full-index` should fix the problem." - end + SharedHelpers.ensure_same_dependencies(spec, dependencies, spec.dependencies) @_remote_specification = spec end diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index 086624b383..cb8e142769 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -152,6 +152,21 @@ module Bundler end end + def ensure_same_dependencies(spec, old, new) + new = new.reject {|d| d.type == :development } + old = old.reject {|d| d.type == :development } + + without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) } + new.map!(&without_type) + old.map!(&without_type) + + extra_deps = new - old + return if extra_deps.empty? + raise APIResponseMismatchError, + "Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.map(&:to_s).join(", ")})." \ + "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem." + end + private def find_gemfile diff --git a/spec/lock/lockfile_spec.rb b/spec/lock/lockfile_spec.rb index 7d768e337c..86a23dbe3d 100644 --- a/spec/lock/lockfile_spec.rb +++ b/spec/lock/lockfile_spec.rb @@ -1258,6 +1258,29 @@ RSpec.describe "the lockfile format" do L end + it "raises a helpful error message when the lockfile is missing deps" do + lockfile <<-L + GEM + remote: file:#{gem_repo1}/ + specs: + rack_middleware (1.0) + + PLATFORMS + #{local} + + DEPENDENCIES + rack_middleware + L + + install_gemfile <<-G + source "file:#{gem_repo1}" + gem "rack_middleware" + G + + expect(out).to include("Downloading rack_middleware-1.0 revealed dependencies not in the API or the lockfile (rack (= 0.9.1))."). + and include("Either installing with `--full-index` or running `bundle update rack_middleware` should fix the problem.") + end + describe "a line ending" do def set_lockfile_mtime_to_known_value time = Time.local(2000, 1, 1, 0, 0, 0) |