diff --git a/bundler/lib/bundler/installer/parallel_installer.rb b/bundler/lib/bundler/installer/parallel_installer.rb index c3bf5843b763..5b6680e5e12b 100644 --- a/bundler/lib/bundler/installer/parallel_installer.rb +++ b/bundler/lib/bundler/installer/parallel_installer.rb @@ -6,10 +6,11 @@ module Bundler class ParallelInstaller class SpecInstallation - attr_accessor :spec, :name, :post_install_message, :state, :error + attr_accessor :spec, :name, :full_name, :post_install_message, :state, :error def initialize(spec) @spec = spec @name = spec.name + @full_name = spec.full_name @state = :none @post_install_message = "" @error = nil @@ -49,14 +50,11 @@ def dependencies_installed?(all_specs) # Represents only the non-development dependencies, the ones that are # itself and are in the total list. def dependencies - @dependencies ||= begin - all_dependencies.reject {|dep| ignorable_dependency? dep } - end + @dependencies ||= all_dependencies.reject {|dep| ignorable_dependency? dep } end def missing_lockfile_dependencies(all_spec_names) - deps = all_dependencies.reject {|dep| ignorable_dependency? dep } - deps.reject {|dep| all_spec_names.include? dep.name } + dependencies.reject {|dep| all_spec_names.include? dep.name } end # Represents all dependencies @@ -65,7 +63,7 @@ def all_dependencies end def to_s - "#<#{self.class} #{@spec.full_name} (#{state})>" + "#<#{self.class} #{full_name} (#{state})>" end end @@ -99,12 +97,37 @@ def call install_serially end + check_for_unmet_dependencies + handle_error if failed_specs.any? @specs ensure worker_pool && worker_pool.stop end + def check_for_unmet_dependencies + unmet_dependencies = @specs.map do |s| + [ + s, + s.dependencies.reject {|dep| @specs.any? {|spec| dep.matches_spec?(spec.spec) } }, + ] + end.reject {|a| a.last.empty? } + return if unmet_dependencies.empty? + + warning = [] + warning << "Your lockfile doesn't include a valid resolution." + warning << "You can fix this by regenerating your lockfile or trying to manually editing the bad locked gems to a version that satisfies all dependencies." + warning << "The unmet dependencies are:" + + unmet_dependencies.each do |spec, unmet_spec_dependencies| + unmet_spec_dependencies.each do |unmet_spec_dependency| + warning << "* #{unmet_spec_dependency}, depended upon #{spec.full_name}, unsatisfied by #{@specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }.full_name}" + end + end + + Bundler.ui.warn(warning.join("\n")) + end + def check_for_corrupt_lockfile missing_dependencies = @specs.map do |s| [ diff --git a/bundler/spec/bundler/installer/parallel_installer_spec.rb b/bundler/spec/bundler/installer/parallel_installer_spec.rb index ace5c1a23a9a..e680633862ab 100644 --- a/bundler/spec/bundler/installer/parallel_installer_spec.rb +++ b/bundler/spec/bundler/installer/parallel_installer_spec.rb @@ -44,4 +44,37 @@ end end end + + context "when the spec set is not a valid resolution" do + let(:all_specs) do + [ + build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" }, + build_spec("diff-lcs", "1.4.4"), + ].flatten + end + + it "prints a warning" do + expect(Bundler.ui).to receive(:warn).with(<<-W.strip) +Your lockfile doesn't include a valid resolution. +You can fix this by regenerating your lockfile or trying to manually editing the bad locked gems to a version that satisfies all dependencies. +The unmet dependencies are: +* diff-lcs (< 1.4), depended upon cucumber-4.1.0, unsatisfied by diff-lcs-1.4.4 + W + subject.check_for_unmet_dependencies + end + end + + context "when the spec set is a valid resolution" do + let(:all_specs) do + [ + build_spec("cucumber", "4.1.0") {|s| s.runtime "diff-lcs", "< 1.4" }, + build_spec("diff-lcs", "1.3"), + ].flatten + end + + it "doesn't print a warning" do + expect(Bundler.ui).not_to receive(:warn) + subject.check_for_unmet_dependencies + end + end end diff --git a/bundler/spec/bundler/installer/spec_installation_spec.rb b/bundler/spec/bundler/installer/spec_installation_spec.rb index a9cf09a37296..e63ef26cb316 100644 --- a/bundler/spec/bundler/installer/spec_installation_spec.rb +++ b/bundler/spec/bundler/installer/spec_installation_spec.rb @@ -8,6 +8,10 @@ def a_spec.name "I like tests" end + + def a_spec.full_name + "I really like tests" + end a_spec end diff --git a/dev_gems.rb.lock b/dev_gems.rb.lock index 09c4dee806a8..272adbba14d9 100644 --- a/dev_gems.rb.lock +++ b/dev_gems.rb.lock @@ -3,7 +3,7 @@ GEM specs: addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - ast (2.4.0) + ast (2.4.2) aws-eventstream (1.1.0) aws-partitions (1.411.0) aws-sdk-core (3.110.0)