@@ -132,7 +132,7 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti
132132 @sources . merged_gem_lockfile_sections! ( locked_gem_sources . first )
133133 end
134134
135- @unlock [ :sources ] ||= [ ]
135+ @sources_to_unlock = @ unlock. delete ( :sources ) || [ ]
136136 @unlock [ :ruby ] ||= if @ruby_version && locked_ruby_version_object
137137 @ruby_version . diff ( locked_ruby_version_object )
138138 end
@@ -144,11 +144,13 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti
144144 @path_changes = converge_paths
145145 @source_changes = converge_sources
146146
147+ @explicit_unlocks = @unlock . delete ( :gems ) || [ ]
148+
147149 if @unlock [ :conservative ]
148- @unlock [ :gems ] ||= @dependencies . map ( &:name )
150+ @gems_to_unlock = @explicit_unlocks . any? ? @explicit_unlocks : @dependencies . map ( &:name )
149151 else
150- eager_unlock = ( @unlock [ :gems ] || [ ] ) . map { |name | Dependency . new ( name , ">= 0" ) }
151- @unlock [ :gems ] = @locked_specs . for ( eager_unlock , false , platforms ) . map ( &:name ) . uniq
152+ eager_unlock = @explicit_unlocks . map { |name | Dependency . new ( name , ">= 0" ) }
153+ @gems_to_unlock = @locked_specs . for ( eager_unlock , false , platforms ) . map ( &:name ) . uniq
152154 end
153155
154156 @dependency_changes = converge_dependencies
@@ -227,7 +229,6 @@ def missing_specs?
227229 @resolver = nil
228230 @resolution_packages = nil
229231 @specs = nil
230- @gem_version_promoter = nil
231232
232233 Bundler . ui . debug "The definition is missing dependencies, failed to resolve & materialize locally (#{ e } )"
233234 true
@@ -568,8 +569,10 @@ def resolution_packages
568569 @resolution_packages ||= begin
569570 last_resolve = converge_locked_specs
570571 remove_invalid_platforms! ( current_dependencies )
571- packages = Resolver ::Base . new ( source_requirements , expanded_dependencies , last_resolve , @platforms , locked_specs : @originally_locked_specs , unlock : @unlock [ :gems ] , prerelease : gem_version_promoter . pre? )
572- additional_base_requirements_for_resolve ( packages , last_resolve )
572+ packages = Resolver ::Base . new ( source_requirements , expanded_dependencies , last_resolve , @platforms , locked_specs : @originally_locked_specs , unlock : @gems_to_unlock , prerelease : gem_version_promoter . pre? )
573+ packages = additional_base_requirements_to_prevent_downgrades ( packages , last_resolve )
574+ packages = additional_base_requirements_to_force_updates ( packages )
575+ packages
573576 end
574577 end
575578
@@ -673,14 +676,18 @@ def add_current_platform
673676
674677 def change_reason
675678 if unlocking?
676- unlock_reason = @unlock . reject { |_k , v | Array ( v ) . empty? } . map do |k , v |
677- if v == true
678- k . to_s
679- else
680- v = Array ( v )
681- "#{ k } : (#{ v . join ( ", " ) } )"
682- end
683- end . join ( ", " )
679+ unlock_targets = if @gems_to_unlock . any?
680+ [ "gems" , @gems_to_unlock ]
681+ elsif @sources_to_unlock . any?
682+ [ "sources" , @sources_to_unlock ]
683+ end
684+
685+ unlock_reason = if unlock_targets
686+ "#{ unlock_targets . first } : (#{ unlock_targets . last . join ( ", " ) } )"
687+ else
688+ @unlock [ :ruby ] ? "ruby" : ""
689+ end
690+
684691 return "bundler is unlocking #{ unlock_reason } "
685692 end
686693 [
@@ -735,15 +742,15 @@ def converge_locals
735742 spec = @dependencies . find { |s | s . name == k }
736743 source = spec &.source
737744 if source &.respond_to? ( :local_override! )
738- source . unlock! if @unlock [ :gems ] . include? ( spec . name )
745+ source . unlock! if @gems_to_unlock . include? ( spec . name )
739746 locals << [ source , source . local_override! ( v ) ]
740747 end
741748 end
742749
743750 sources_with_changes = locals . select do |source , changed |
744751 changed || specs_changed? ( source )
745752 end . map ( &:first )
746- !sources_with_changes . each { |source | @unlock [ :sources ] << source . name } . empty?
753+ !sources_with_changes . each { |source | @sources_to_unlock << source . name } . empty?
747754 end
748755
749756 def check_lockfile
@@ -820,7 +827,7 @@ def converge_sources
820827 # gem), unlock it. For git sources, this means to unlock the revision, which
821828 # will cause the `ref` used to be the most recent for the branch (or master) if
822829 # an explicit `ref` is not used.
823- if source . respond_to? ( :unlock! ) && @unlock [ :sources ] . include? ( source . name )
830+ if source . respond_to? ( :unlock! ) && @sources_to_unlock . include? ( source . name )
824831 source . unlock!
825832 changes = true
826833 end
@@ -864,7 +871,7 @@ def converge_dependencies
864871 def converge_locked_specs
865872 converged = converge_specs ( @locked_specs )
866873
867- resolve = SpecSet . new ( converged . reject { |s | @unlock [ :gems ] . include? ( s . name ) } )
874+ resolve = SpecSet . new ( converged . reject { |s | @gems_to_unlock . include? ( s . name ) } )
868875
869876 diff = nil
870877
@@ -897,7 +904,7 @@ def converge_specs(specs)
897904
898905 @specs_that_changed_sources << s if gemfile_source != lockfile_source
899906 deps << dep if !dep . source || lockfile_source . include? ( dep . source )
900- @unlock [ :gems ] << name if lockfile_source . include? ( dep . source ) && lockfile_source != gemfile_source
907+ @gems_to_unlock << name if lockfile_source . include? ( dep . source ) && lockfile_source != gemfile_source
901908
902909 # Replace the locked dependency's source with the equivalent source from the Gemfile
903910 s . source = gemfile_source
@@ -906,7 +913,7 @@ def converge_specs(specs)
906913 s . source = default_source unless sources . get ( lockfile_source )
907914 end
908915
909- next if @unlock [ :sources ] . include? ( s . source . name )
916+ next if @sources_to_unlock . include? ( s . source . name )
910917
911918 # Path sources have special logic
912919 if s . source . instance_of? ( Source ::Path ) || s . source . instance_of? ( Source ::Gemspec )
@@ -928,12 +935,12 @@ def converge_specs(specs)
928935 else
929936 # If the spec is no longer in the path source, unlock it. This
930937 # commonly happens if the version changed in the gemspec
931- @unlock [ :gems ] << name
938+ @gems_to_unlock << name
932939 end
933940 end
934941
935942 if dep . nil? && requested_dependencies . find { |d | name == d . name }
936- @unlock [ :gems ] << s . name
943+ @gems_to_unlock << s . name
937944 else
938945 converged << s
939946 end
@@ -1010,7 +1017,7 @@ def lockfiles_equal?(current, proposed, preserve_unknown_sections)
10101017 current == proposed
10111018 end
10121019
1013- def additional_base_requirements_for_resolve ( resolution_packages , last_resolve )
1020+ def additional_base_requirements_to_prevent_downgrades ( resolution_packages , last_resolve )
10141021 return resolution_packages unless @locked_gems && !sources . expired_sources? ( @locked_gems . sources )
10151022 converge_specs ( @originally_locked_specs - last_resolve ) . each do |locked_spec |
10161023 next if locked_spec . source . is_a? ( Source ::Path )
@@ -1019,6 +1026,28 @@ def additional_base_requirements_for_resolve(resolution_packages, last_resolve)
10191026 resolution_packages
10201027 end
10211028
1029+ def additional_base_requirements_to_force_updates ( resolution_packages )
1030+ return resolution_packages if @explicit_unlocks . empty?
1031+ full_update = dup_for_full_unlock . resolve
1032+ @explicit_unlocks . each do |name |
1033+ version = full_update [ name ] . first &.version
1034+ resolution_packages . base_requirements [ name ] = Gem ::Requirement . new ( "= #{ version } " ) if version
1035+ end
1036+ resolution_packages
1037+ end
1038+
1039+ def dup_for_full_unlock
1040+ unlocked_definition = self . class . new ( @lockfile , @dependencies , @sources , true , @ruby_version , @optional_groups , @gemfiles )
1041+ unlocked_definition . resolution_mode = { "local" => !@remote }
1042+ unlocked_definition . setup_sources_for_resolve
1043+ unlocked_definition . gem_version_promoter . tap do |gvp |
1044+ gvp . level = gem_version_promoter . level
1045+ gvp . strict = gem_version_promoter . strict
1046+ gvp . pre = gem_version_promoter . pre
1047+ end
1048+ unlocked_definition
1049+ end
1050+
10221051 def remove_invalid_platforms! ( dependencies )
10231052 return if Bundler . frozen_bundle?
10241053
0 commit comments