diff --git a/lib/bundler/multilock.rb b/lib/bundler/multilock.rb index 53660e7..b76cdff 100644 --- a/lib/bundler/multilock.rb +++ b/lib/bundler/multilock.rb @@ -260,6 +260,9 @@ def after_install_all(install: true) spec_precedences[spec.name] = precedence || :parent end + lockfile.sources.map! do |source| + parent_lockfile.sources.find { |s| s == source } || source + end # replace any duplicate specs with what's in the parent lockfile lockfile.specs.map! do |spec| parent_spec = cache.find_matching_spec(parent_specs, spec) @@ -268,9 +271,7 @@ def after_install_all(install: true) dependency_changes ||= spec != parent_spec - new_spec = parent_spec.dup - new_spec.source = spec.source - new_spec + parent_spec end lockfile.platforms.replace(parent_lockfile.platforms).uniq! @@ -483,6 +484,13 @@ def write_lockfile(lockfile_definition, # from someone else if current_lockfile.exist? && install Bundler.settings.temporary(frozen: true) do + # it keeps the same sources as the builder, which now shares with + # `definition` above; give it its own copy to avoid stomping on it + builder.instance_variable_set( + :@sources, + builder.instance_variable_get(:@sources).dup + ) + current_definition = builder.to_definition(current_lockfile, {}) # if something has changed, we skip this step; it's unlocking anyway next unless current_definition.no_resolve_needed? @@ -504,6 +512,14 @@ def write_lockfile(lockfile_definition, previous_ui_level = Bundler.ui.level Bundler.ui.level = "warn" begin + # force a remote resolution if intermediate gems are missing + if definition.instance_variable_get(:@locked_spec_with_missing_deps) || + definition.instance_variable_get(:@locked_spec_with_invalid_deps) || + definition.instance_variable_get(:@missing_lockfile_dep) || + definition.instance_variable_get(:@invalid_lockfile_dep) + raise SolveFailure + end + # this is a horrible hack, to fix what I consider to be a Bundler bug. # basically, if you have multiple platform specific gems in your # lockfile, and that gem gets unlocked, Bundler will only search diff --git a/spec/bundler/multilock_spec.rb b/spec/bundler/multilock_spec.rb index be2c413..9ec3dba 100644 --- a/spec/bundler/multilock_spec.rb +++ b/spec/bundler/multilock_spec.rb @@ -827,7 +827,12 @@ end RUBY - with_gemfile(orig_gemfile) do + with_gemfile("") do + # install once with nothing so that it doesn't try to lock every single + # platform available for FFI + invoke_bundler("install") + + write_gemfile(orig_gemfile) invoke_bundler("install") write_gemfile(<<~RUBY) @@ -969,6 +974,24 @@ end end + it "syncs git sources that have updated" do + with_gemfile(<<~RUBY) do + gem "rspecq", github: "instructure/rspecq" + + lockfile "alt" do + end + RUBY + invoke_bundler("install") + replace_lockfile_git_pin("d7fa5536da01cccb5109ba05c9e236d6660da593") + invoke_bundler("install") + + expect(invoke_bundler("info rspecq")).to include("d7fa553") + + invoke_bundler("update rspecq") + expect(invoke_bundler("info rspecq")).not_to include("d7fa553") + end + end + private def create_local_gem(name, content = "", subdirectory: true) @@ -1065,6 +1088,12 @@ def replace_lockfile_pin(lockfile, gem, version) File.write(lockfile, new_contents) end + def replace_lockfile_git_pin(revision) + new_contents = File.read("Gemfile.lock").gsub(/revision: [0-9a-f]+/, "revision: #{revision}") + + File.write("Gemfile.lock", new_contents) + end + def update_lockfile_bundler(lockfile, version) new_contents = File.read(lockfile).gsub(/BUNDLED WITH\n [0-9.]+/, "BUNDLED WITH\n #{version}")