Re-resolve when lockfile is invalid
Move the check for unmet dependencies in lockfile just in time to be able to re-resolve if unmet dependencies are found.
This commit is contained in:
parent
7e51cadc2e
commit
cbf2e133c1
@ -149,7 +149,7 @@ module Bundler
|
||||
@dependency_changes = converge_dependencies
|
||||
@local_changes = converge_locals
|
||||
|
||||
@missing_lockfile_dep = check_missing_lockfile_dep
|
||||
check_lockfile
|
||||
end
|
||||
|
||||
def gem_version_promoter
|
||||
@ -478,7 +478,7 @@ module Bundler
|
||||
private :sources
|
||||
|
||||
def nothing_changed?
|
||||
!@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@missing_lockfile_dep && !@unlocking_bundler
|
||||
!@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@missing_lockfile_dep && !@unlocking_bundler && !@invalid_lockfile_dep
|
||||
end
|
||||
|
||||
def no_resolve_needed?
|
||||
@ -630,6 +630,7 @@ module Bundler
|
||||
[@local_changes, "the gemspecs for git local gems changed"],
|
||||
[@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
|
||||
[@unlocking_bundler, "an update to the version of Bundler itself was requested"],
|
||||
[@invalid_lockfile_dep, "your lock file has an invalid dependency \"#{@invalid_lockfile_dep}\""],
|
||||
].select(&:first).map(&:last).join(", ")
|
||||
end
|
||||
|
||||
@ -684,26 +685,40 @@ module Bundler
|
||||
!sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
|
||||
end
|
||||
|
||||
def check_missing_lockfile_dep
|
||||
all_locked_specs = @locked_specs.map(&:name) << "bundler"
|
||||
def check_lockfile
|
||||
@invalid_lockfile_dep = nil
|
||||
@missing_lockfile_dep = nil
|
||||
|
||||
missing = @locked_specs.select do |s|
|
||||
s.dependencies.any? {|dep| !all_locked_specs.include?(dep.name) }
|
||||
locked_names = @locked_specs.map(&:name)
|
||||
missing = []
|
||||
invalid = []
|
||||
|
||||
@locked_specs.each do |s|
|
||||
s.dependencies.each do |dep|
|
||||
next if dep.name == "bundler"
|
||||
|
||||
missing << s unless locked_names.include?(dep.name)
|
||||
invalid << s if @locked_specs.none? {|spec| dep.matches_spec?(spec) }
|
||||
end
|
||||
end
|
||||
|
||||
if missing.any?
|
||||
@locked_specs.delete(missing)
|
||||
|
||||
return missing.first.name
|
||||
end
|
||||
|
||||
return if @dependency_changes
|
||||
|
||||
current_dependencies.find do |d|
|
||||
@missing_lockfile_dep = missing.first.name
|
||||
elsif !@dependency_changes
|
||||
@missing_lockfile_dep = current_dependencies.find do |d|
|
||||
@locked_specs[d.name].empty? && d.name != "bundler"
|
||||
end&.name
|
||||
end
|
||||
|
||||
if invalid.any?
|
||||
@locked_specs.delete(invalid)
|
||||
|
||||
@invalid_lockfile_dep = invalid.first.name
|
||||
end
|
||||
end
|
||||
|
||||
def converge_paths
|
||||
sources.path_sources.any? do |source|
|
||||
specs_changed?(source)
|
||||
|
@ -91,38 +91,12 @@ module Bundler
|
||||
install_serially
|
||||
end
|
||||
|
||||
check_for_unmet_dependencies
|
||||
|
||||
handle_error if failed_specs.any?
|
||||
@specs
|
||||
ensure
|
||||
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 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|
|
||||
found = @specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }
|
||||
warning << "* #{unmet_spec_dependency}, dependency of #{spec.full_name}, unsatisfied by #{found.full_name}"
|
||||
end
|
||||
end
|
||||
|
||||
Bundler.ui.warn(warning.join("\n"))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def failed_specs
|
||||
|
@ -1,46 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "bundler/installer/parallel_installer"
|
||||
|
||||
RSpec.describe Bundler::ParallelInstaller do
|
||||
let(:installer) { instance_double("Installer") }
|
||||
let(:all_specs) { [] }
|
||||
let(:size) { 1 }
|
||||
let(:standalone) { false }
|
||||
let(:force) { false }
|
||||
|
||||
subject { described_class.new(installer, all_specs, size, standalone, force) }
|
||||
|
||||
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 manually editing the bad locked gems to a version that satisfies all dependencies.
|
||||
The unmet dependencies are:
|
||||
* diff-lcs (< 1.4), dependency of 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
|
@ -1101,4 +1101,47 @@ RSpec.describe "bundle install with gem sources" do
|
||||
expect(err).to include("Could not find compatible versions")
|
||||
end
|
||||
end
|
||||
|
||||
context "when a lockfile has unmet dependencies, and the Gemfile has no resolution" do
|
||||
before do
|
||||
build_repo4 do
|
||||
build_gem "aaa", "0.2.0" do |s|
|
||||
s.add_dependency "zzz", "< 0.2.0"
|
||||
end
|
||||
|
||||
build_gem "zzz", "0.2.0"
|
||||
end
|
||||
|
||||
gemfile <<~G
|
||||
source "#{file_uri_for(gem_repo4)}"
|
||||
|
||||
gem "aaa"
|
||||
gem "zzz"
|
||||
G
|
||||
|
||||
lockfile <<~L
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo4)}/
|
||||
specs:
|
||||
aaa (0.2.0)
|
||||
zzz (< 0.2.0)
|
||||
zzz (0.2.0)
|
||||
|
||||
PLATFORMS
|
||||
#{lockfile_platforms}
|
||||
|
||||
DEPENDENCIES
|
||||
aaa!
|
||||
zzz!
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
L
|
||||
end
|
||||
|
||||
it "does not install, but raises a resolution error" do
|
||||
bundle "install", :raise_on_error => false
|
||||
expect(err).to include("Could not find compatible versions")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user