bundler 2.5.9 → 2.5.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +136 -0
  3. data/lib/bundler/build_metadata.rb +2 -2
  4. data/lib/bundler/cli/check.rb +1 -1
  5. data/lib/bundler/cli/fund.rb +1 -1
  6. data/lib/bundler/cli/gem.rb +8 -15
  7. data/lib/bundler/cli/install.rb +1 -1
  8. data/lib/bundler/cli.rb +31 -48
  9. data/lib/bundler/compact_index_client/cache.rb +47 -72
  10. data/lib/bundler/compact_index_client/parser.rb +84 -0
  11. data/lib/bundler/compact_index_client.rb +51 -80
  12. data/lib/bundler/constants.rb +8 -1
  13. data/lib/bundler/definition.rb +120 -74
  14. data/lib/bundler/dependency.rb +2 -1
  15. data/lib/bundler/endpoint_specification.rb +11 -0
  16. data/lib/bundler/env.rb +1 -1
  17. data/lib/bundler/environment_preserver.rb +2 -20
  18. data/lib/bundler/errors.rb +14 -0
  19. data/lib/bundler/fetcher/compact_index.rb +15 -24
  20. data/lib/bundler/force_platform.rb +0 -2
  21. data/lib/bundler/gem_helper.rb +1 -1
  22. data/lib/bundler/gem_helpers.rb +14 -7
  23. data/lib/bundler/injector.rb +3 -5
  24. data/lib/bundler/installer/gem_installer.rb +0 -1
  25. data/lib/bundler/installer/standalone.rb +0 -3
  26. data/lib/bundler/installer.rb +9 -11
  27. data/lib/bundler/lazy_specification.rb +1 -0
  28. data/lib/bundler/man/bundle-add.1 +1 -1
  29. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  30. data/lib/bundler/man/bundle-cache.1 +1 -1
  31. data/lib/bundler/man/bundle-check.1 +3 -1
  32. data/lib/bundler/man/bundle-check.1.ronn +3 -0
  33. data/lib/bundler/man/bundle-clean.1 +1 -1
  34. data/lib/bundler/man/bundle-config.1 +2 -4
  35. data/lib/bundler/man/bundle-config.1.ronn +1 -4
  36. data/lib/bundler/man/bundle-console.1 +1 -1
  37. data/lib/bundler/man/bundle-doctor.1 +1 -1
  38. data/lib/bundler/man/bundle-exec.1 +1 -1
  39. data/lib/bundler/man/bundle-gem.1 +7 -1
  40. data/lib/bundler/man/bundle-gem.1.ronn +11 -0
  41. data/lib/bundler/man/bundle-help.1 +1 -1
  42. data/lib/bundler/man/bundle-info.1 +1 -1
  43. data/lib/bundler/man/bundle-init.1 +1 -1
  44. data/lib/bundler/man/bundle-inject.1 +1 -1
  45. data/lib/bundler/man/bundle-install.1 +1 -1
  46. data/lib/bundler/man/bundle-list.1 +1 -1
  47. data/lib/bundler/man/bundle-lock.1 +1 -1
  48. data/lib/bundler/man/bundle-open.1 +1 -1
  49. data/lib/bundler/man/bundle-outdated.1 +1 -1
  50. data/lib/bundler/man/bundle-platform.1 +1 -1
  51. data/lib/bundler/man/bundle-plugin.1 +1 -1
  52. data/lib/bundler/man/bundle-pristine.1 +1 -1
  53. data/lib/bundler/man/bundle-remove.1 +1 -1
  54. data/lib/bundler/man/bundle-show.1 +1 -1
  55. data/lib/bundler/man/bundle-update.1 +1 -1
  56. data/lib/bundler/man/bundle-version.1 +1 -1
  57. data/lib/bundler/man/bundle-viz.1 +1 -1
  58. data/lib/bundler/man/bundle.1 +1 -1
  59. data/lib/bundler/man/gemfile.5 +1 -1
  60. data/lib/bundler/plugin/api/source.rb +1 -0
  61. data/lib/bundler/resolver/base.rb +4 -0
  62. data/lib/bundler/resolver/candidate.rb +4 -16
  63. data/lib/bundler/resolver/package.rb +4 -0
  64. data/lib/bundler/resolver/spec_group.rb +20 -2
  65. data/lib/bundler/resolver.rb +18 -9
  66. data/lib/bundler/rubygems_ext.rb +105 -23
  67. data/lib/bundler/rubygems_gem_installer.rb +35 -2
  68. data/lib/bundler/rubygems_integration.rb +16 -2
  69. data/lib/bundler/runtime.rb +1 -6
  70. data/lib/bundler/self_manager.rb +23 -3
  71. data/lib/bundler/settings.rb +12 -9
  72. data/lib/bundler/setup.rb +6 -0
  73. data/lib/bundler/shared_helpers.rb +6 -4
  74. data/lib/bundler/source/git/git_proxy.rb +8 -0
  75. data/lib/bundler/source/git.rb +43 -16
  76. data/lib/bundler/source/metadata.rb +2 -0
  77. data/lib/bundler/source/path.rb +0 -13
  78. data/lib/bundler/source/rubygems.rb +31 -30
  79. data/lib/bundler/source_list.rb +28 -4
  80. data/lib/bundler/spec_set.rb +16 -14
  81. data/lib/bundler/stub_specification.rb +8 -0
  82. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +77 -29
  83. data/lib/bundler/vendored_net_http.rb +17 -6
  84. data/lib/bundler/version.rb +1 -1
  85. data/lib/bundler/yaml_serializer.rb +2 -9
  86. data/lib/bundler.rb +26 -1
  87. metadata +4 -3
@@ -69,7 +69,6 @@ module Bundler
69
69
  @sources = sources
70
70
  @unlock = unlock
71
71
  @optional_groups = optional_groups
72
- @remote = false
73
72
  @prefer_local = false
74
73
  @specs = nil
75
74
  @ruby_version = ruby_version
@@ -82,7 +81,7 @@ module Bundler
82
81
  @resolved_bundler_version = nil
83
82
 
84
83
  @locked_ruby_version = nil
85
- @new_platform = nil
84
+ @new_platforms = []
86
85
  @removed_platform = nil
87
86
 
88
87
  if lockfile_exists?
@@ -92,11 +91,12 @@ module Bundler
92
91
  @platforms = @locked_platforms.dup
93
92
  @locked_bundler_version = @locked_gems.bundler_version
94
93
  @locked_ruby_version = @locked_gems.ruby_version
94
+ @originally_locked_deps = @locked_gems.dependencies
95
95
  @originally_locked_specs = SpecSet.new(@locked_gems.specs)
96
96
  @locked_checksums = @locked_gems.checksums
97
97
 
98
98
  if unlock != true
99
- @locked_deps = @locked_gems.dependencies
99
+ @locked_deps = @originally_locked_deps
100
100
  @locked_specs = @originally_locked_specs
101
101
  @locked_sources = @locked_gems.sources
102
102
  else
@@ -111,10 +111,11 @@ module Bundler
111
111
  @locked_gems = nil
112
112
  @locked_deps = {}
113
113
  @locked_specs = SpecSet.new([])
114
+ @originally_locked_deps = {}
114
115
  @originally_locked_specs = @locked_specs
115
116
  @locked_sources = []
116
117
  @locked_platforms = []
117
- @locked_checksums = nil
118
+ @locked_checksums = Bundler.feature_flag.bundler_3_mode?
118
119
  end
119
120
 
120
121
  locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@@ -130,23 +131,25 @@ module Bundler
130
131
  @sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
131
132
  end
132
133
 
133
- @unlock[:sources] ||= []
134
+ @sources_to_unlock = @unlock.delete(:sources) || []
134
135
  @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
135
136
  @ruby_version.diff(locked_ruby_version_object)
136
137
  end
137
138
  @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
138
139
 
139
- add_current_platform unless Bundler.frozen_bundle?
140
+ @current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
140
141
 
141
142
  converge_path_sources_to_gemspec_sources
142
143
  @path_changes = converge_paths
143
144
  @source_changes = converge_sources
144
145
 
146
+ @explicit_unlocks = @unlock.delete(:gems) || []
147
+
145
148
  if @unlock[:conservative]
146
- @unlock[:gems] ||= @dependencies.map(&:name)
149
+ @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
147
150
  else
148
- eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") }
149
- @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
151
+ eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
152
+ @gems_to_unlock = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
150
153
  end
151
154
 
152
155
  @dependency_changes = converge_dependencies
@@ -160,37 +163,24 @@ module Bundler
160
163
  end
161
164
 
162
165
  def resolve_only_locally!
163
- @remote = false
164
166
  sources.local_only!
165
167
  resolve
166
168
  end
167
169
 
168
170
  def resolve_with_cache!
171
+ sources.local!
169
172
  sources.cached!
170
173
  resolve
171
174
  end
172
175
 
173
176
  def resolve_remotely!
174
- @remote = true
177
+ sources.cached!
175
178
  sources.remote!
176
179
  resolve
177
180
  end
178
181
 
179
- def resolution_mode=(options)
180
- if options["local"]
181
- @remote = false
182
- else
183
- @remote = true
184
- @prefer_local = options["prefer-local"]
185
- end
186
- end
187
-
188
- def setup_sources_for_resolve
189
- if @remote == false
190
- sources.cached!
191
- else
192
- sources.remote!
193
- end
182
+ def prefer_local!
183
+ @prefer_local = true
194
184
  end
195
185
 
196
186
  # For given dependency list returns a SpecSet with Gemspec of all the required
@@ -225,7 +215,6 @@ module Bundler
225
215
  @resolver = nil
226
216
  @resolution_packages = nil
227
217
  @specs = nil
228
- @gem_version_promoter = nil
229
218
 
230
219
  Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
231
220
  true
@@ -307,7 +296,12 @@ module Bundler
307
296
  end
308
297
  end
309
298
  else
310
- Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
299
+ if lockfile_exists?
300
+ Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
301
+ else
302
+ Bundler.ui.debug "Resolving dependencies because there's no lockfile"
303
+ end
304
+
311
305
  start_resolution
312
306
  end
313
307
  end
@@ -373,6 +367,10 @@ module Bundler
373
367
  end
374
368
 
375
369
  def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
370
+ return unless Bundler.frozen_bundle?
371
+
372
+ raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists?
373
+
376
374
  added = []
377
375
  deleted = []
378
376
  changed = []
@@ -401,7 +399,7 @@ module Bundler
401
399
  changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
402
400
  end
403
401
 
404
- reason = change_reason
402
+ reason = nothing_changed? ? "some dependencies were deleted from your gemfile" : change_reason
405
403
  msg = String.new
406
404
  msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set"
407
405
  msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
@@ -459,8 +457,10 @@ module Bundler
459
457
  end
460
458
 
461
459
  def add_platform(platform)
462
- @new_platform ||= !@platforms.include?(platform)
463
- @platforms |= [platform]
460
+ return if @platforms.include?(platform)
461
+
462
+ @new_platforms << platform
463
+ @platforms << platform
464
464
  end
465
465
 
466
466
  def remove_platform(platform)
@@ -480,9 +480,12 @@ module Bundler
480
480
  private :sources
481
481
 
482
482
  def nothing_changed?
483
+ return false unless lockfile_exists?
484
+
483
485
  !@source_changes &&
484
486
  !@dependency_changes &&
485
- !@new_platform &&
487
+ !@current_platform_missing &&
488
+ @new_platforms.empty? &&
486
489
  !@path_changes &&
487
490
  !@local_changes &&
488
491
  !@missing_lockfile_dep &&
@@ -565,9 +568,11 @@ module Bundler
565
568
  def resolution_packages
566
569
  @resolution_packages ||= begin
567
570
  last_resolve = converge_locked_specs
568
- remove_invalid_platforms!(current_dependencies)
569
- packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlock[:gems], prerelease: gem_version_promoter.pre?)
570
- additional_base_requirements_for_resolve(packages, last_resolve)
571
+ remove_invalid_platforms!
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
571
576
  end
572
577
  end
573
578
 
@@ -582,7 +587,7 @@ module Bundler
582
587
  if missing_specs.any?
583
588
  missing_specs.each do |s|
584
589
  locked_gem = @locked_specs[s.name].last
585
- next if locked_gem.nil? || locked_gem.version != s.version || !@remote
590
+ next if locked_gem.nil? || locked_gem.version != s.version || sources.local_mode?
586
591
  raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
587
592
  "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
588
593
  "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
@@ -601,7 +606,7 @@ module Bundler
601
606
  break if incomplete_specs.empty?
602
607
 
603
608
  Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
604
- setup_sources_for_resolve
609
+ sources.remote!
605
610
  resolution_packages.delete(incomplete_specs)
606
611
  @resolve = start_resolution
607
612
  specs = resolve.materialize(dependencies)
@@ -623,12 +628,23 @@ module Bundler
623
628
  end
624
629
 
625
630
  def start_resolution
631
+ local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
632
+ @platforms << local_platform if local_platform_needed_for_resolvability
633
+ add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
634
+
626
635
  result = SpecSet.new(resolver.start)
627
636
 
628
637
  @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
629
- @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
630
638
 
631
- result.complete_platforms!(platforms)
639
+ if @most_specific_non_local_locked_ruby_platform
640
+ if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_ruby_platform)
641
+ @platforms.delete(@most_specific_non_local_locked_ruby_platform)
642
+ elsif local_platform_needed_for_resolvability
643
+ @platforms.delete(local_platform)
644
+ end
645
+ end
646
+
647
+ @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
632
648
 
633
649
  SpecSet.new(result.for(dependencies, false, @platforms))
634
650
  end
@@ -650,13 +666,6 @@ module Bundler
650
666
  end
651
667
  end
652
668
 
653
- def current_ruby_platform_locked?
654
- return false unless generic_local_platform_is_ruby?
655
- return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
656
-
657
- current_platform_locked?
658
- end
659
-
660
669
  def current_platform_locked?
661
670
  @platforms.any? do |bundle_platform|
662
671
  MatchPlatform.platforms_match?(bundle_platform, local_platform)
@@ -664,27 +673,42 @@ module Bundler
664
673
  end
665
674
 
666
675
  def add_current_platform
667
- return if current_ruby_platform_locked?
676
+ return if @platforms.include?(local_platform)
677
+
678
+ @most_specific_non_local_locked_ruby_platform = find_most_specific_locked_ruby_platform
679
+ return if @most_specific_non_local_locked_ruby_platform
680
+
681
+ @platforms << local_platform
682
+ true
683
+ end
668
684
 
669
- add_platform(local_platform)
685
+ def find_most_specific_locked_ruby_platform
686
+ return unless generic_local_platform_is_ruby? && current_platform_locked?
687
+
688
+ most_specific_locked_platform
670
689
  end
671
690
 
672
691
  def change_reason
673
692
  if unlocking?
674
- unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
675
- if v == true
676
- k.to_s
677
- else
678
- v = Array(v)
679
- "#{k}: (#{v.join(", ")})"
680
- end
681
- end.join(", ")
693
+ unlock_targets = if @gems_to_unlock.any?
694
+ ["gems", @gems_to_unlock]
695
+ elsif @sources_to_unlock.any?
696
+ ["sources", @sources_to_unlock]
697
+ end
698
+
699
+ unlock_reason = if unlock_targets
700
+ "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
701
+ else
702
+ @unlock[:ruby] ? "ruby" : ""
703
+ end
704
+
682
705
  return "bundler is unlocking #{unlock_reason}"
683
706
  end
684
707
  [
685
708
  [@source_changes, "the list of sources changed"],
686
709
  [@dependency_changes, "the dependencies in your gemfile changed"],
687
- [@new_platform, "you added a new platform to your gemfile"],
710
+ [@current_platform_missing, "your lockfile does not include the current platform"],
711
+ [@new_platforms.any?, "you added a new platform to your gemfile"],
688
712
  [@path_changes, "the gemspecs for path gems changed"],
689
713
  [@local_changes, "the gemspecs for git local gems changed"],
690
714
  [@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
@@ -733,7 +757,7 @@ module Bundler
733
757
  spec = @dependencies.find {|s| s.name == k }
734
758
  source = spec&.source
735
759
  if source&.respond_to?(:local_override!)
736
- source.unlock! if @unlock[:gems].include?(spec.name)
760
+ source.unlock! if @gems_to_unlock.include?(spec.name)
737
761
  locals << [source, source.local_override!(v)]
738
762
  end
739
763
  end
@@ -741,7 +765,7 @@ module Bundler
741
765
  sources_with_changes = locals.select do |source, changed|
742
766
  changed || specs_changed?(source)
743
767
  end.map(&:first)
744
- !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
768
+ !sources_with_changes.each {|source| @sources_to_unlock << source.name }.empty?
745
769
  end
746
770
 
747
771
  def check_lockfile
@@ -818,7 +842,7 @@ module Bundler
818
842
  # gem), unlock it. For git sources, this means to unlock the revision, which
819
843
  # will cause the `ref` used to be the most recent for the branch (or master) if
820
844
  # an explicit `ref` is not used.
821
- if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
845
+ if source.respond_to?(:unlock!) && @sources_to_unlock.include?(source.name)
822
846
  source.unlock!
823
847
  changes = true
824
848
  end
@@ -835,9 +859,7 @@ module Bundler
835
859
  dep.source = sources.get(dep.source)
836
860
  end
837
861
 
838
- next if unlocking?
839
-
840
- unless locked_dep = @locked_deps[dep.name]
862
+ unless locked_dep = @originally_locked_deps[dep.name]
841
863
  changes = true
842
864
  next
843
865
  end
@@ -864,7 +886,7 @@ module Bundler
864
886
  def converge_locked_specs
865
887
  converged = converge_specs(@locked_specs)
866
888
 
867
- resolve = SpecSet.new(converged.reject {|s| @unlock[:gems].include?(s.name) })
889
+ resolve = SpecSet.new(converged.reject {|s| @gems_to_unlock.include?(s.name) })
868
890
 
869
891
  diff = nil
870
892
 
@@ -897,7 +919,7 @@ module Bundler
897
919
 
898
920
  @specs_that_changed_sources << s if gemfile_source != lockfile_source
899
921
  deps << dep if !dep.source || lockfile_source.include?(dep.source)
900
- @unlock[:gems] << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
922
+ @gems_to_unlock << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
901
923
 
902
924
  # Replace the locked dependency's source with the equivalent source from the Gemfile
903
925
  s.source = gemfile_source
@@ -906,7 +928,7 @@ module Bundler
906
928
  s.source = default_source unless sources.get(lockfile_source)
907
929
  end
908
930
 
909
- next if @unlock[:sources].include?(s.source.name)
931
+ next if @sources_to_unlock.include?(s.source.name)
910
932
 
911
933
  # Path sources have special logic
912
934
  if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
@@ -928,12 +950,12 @@ module Bundler
928
950
  else
929
951
  # If the spec is no longer in the path source, unlock it. This
930
952
  # commonly happens if the version changed in the gemspec
931
- @unlock[:gems] << name
953
+ @gems_to_unlock << name
932
954
  end
933
955
  end
934
956
 
935
957
  if dep.nil? && requested_dependencies.find {|d| name == d.name }
936
- @unlock[:gems] << s.name
958
+ @gems_to_unlock << s.name
937
959
  else
938
960
  converged << s
939
961
  end
@@ -960,7 +982,7 @@ module Bundler
960
982
  else
961
983
  { default: Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
962
984
  end
963
- source_requirements.merge!(source_map.locked_requirements) unless @remote
985
+ source_requirements.merge!(source_map.locked_requirements) if nothing_changed?
964
986
  metadata_dependencies.each do |dep|
965
987
  source_requirements[dep.name] = sources.metadata_source
966
988
  end
@@ -1010,7 +1032,7 @@ module Bundler
1010
1032
  current == proposed
1011
1033
  end
1012
1034
 
1013
- def additional_base_requirements_for_resolve(resolution_packages, last_resolve)
1035
+ def additional_base_requirements_to_prevent_downgrades(resolution_packages, last_resolve)
1014
1036
  return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
1015
1037
  converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec|
1016
1038
  next if locked_spec.source.is_a?(Source::Path)
@@ -1019,21 +1041,45 @@ module Bundler
1019
1041
  resolution_packages
1020
1042
  end
1021
1043
 
1022
- def remove_invalid_platforms!(dependencies)
1044
+ def additional_base_requirements_to_force_updates(resolution_packages)
1045
+ return resolution_packages if @explicit_unlocks.empty?
1046
+ full_update = dup_for_full_unlock.resolve
1047
+ @explicit_unlocks.each do |name|
1048
+ version = full_update[name].first&.version
1049
+ resolution_packages.base_requirements[name] = Gem::Requirement.new("= #{version}") if version
1050
+ end
1051
+ resolution_packages
1052
+ end
1053
+
1054
+ def dup_for_full_unlock
1055
+ unlocked_definition = self.class.new(@lockfile, @dependencies, @sources, true, @ruby_version, @optional_groups, @gemfiles)
1056
+ unlocked_definition.gem_version_promoter.tap do |gvp|
1057
+ gvp.level = gem_version_promoter.level
1058
+ gvp.strict = gem_version_promoter.strict
1059
+ gvp.pre = gem_version_promoter.pre
1060
+ end
1061
+ unlocked_definition
1062
+ end
1063
+
1064
+ def remove_invalid_platforms!
1023
1065
  return if Bundler.frozen_bundle?
1024
1066
 
1025
1067
  platforms.reverse_each do |platform|
1026
1068
  next if local_platform == platform ||
1027
- (@new_platform && platforms.last == platform) ||
1069
+ @new_platforms.include?(platform) ||
1028
1070
  @path_changes ||
1029
1071
  @dependency_changes ||
1030
- !@originally_locked_specs.incomplete_for_platform?(dependencies, platform)
1072
+ @locked_spec_with_invalid_deps ||
1073
+ !spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
1031
1074
 
1032
1075
  remove_platform(platform)
1033
- add_current_platform if platform == Gem::Platform::RUBY
1034
1076
  end
1035
1077
  end
1036
1078
 
1079
+ def spec_set_incomplete_for_platform?(spec_set, platform)
1080
+ spec_set.incomplete_for_platform?(current_dependencies, platform)
1081
+ end
1082
+
1037
1083
  def source_map
1038
1084
  @source_map ||= SourceMap.new(sources, dependencies, @locked_specs)
1039
1085
  end
@@ -7,7 +7,7 @@ require_relative "rubygems_ext"
7
7
  module Bundler
8
8
  class Dependency < Gem::Dependency
9
9
  attr_reader :autorequire
10
- attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref
10
+ attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref, :glob
11
11
 
12
12
  ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..34).to_a).freeze
13
13
  PLATFORM_MAP = {
@@ -39,6 +39,7 @@ module Bundler
39
39
  @github = options["github"]
40
40
  @branch = options["branch"]
41
41
  @ref = options["ref"]
42
+ @glob = options["glob"]
42
43
  @platforms = Array(options["platforms"])
43
44
  @env = options["env"]
44
45
  @should_include = options.fetch("should_include", true)
@@ -92,6 +92,17 @@ module Bundler
92
92
  end
93
93
  end
94
94
 
95
+ # needed for `bundle fund`
96
+ def metadata
97
+ if @remote_specification
98
+ @remote_specification.metadata
99
+ elsif _local_specification
100
+ _local_specification.metadata
101
+ else
102
+ super
103
+ end
104
+ end
105
+
95
106
  def _local_specification
96
107
  return unless @loaded_from && File.exist?(local_specification_path)
97
108
  eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec|
data/lib/bundler/env.rb CHANGED
@@ -120,7 +120,7 @@ module Bundler
120
120
  specs = Bundler.rubygems.find_name(name)
121
121
  out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
122
122
  end
123
- if (exe = caller.last.split(":").first)&.match? %r{(exe|bin)/bundler?\z}
123
+ if (exe = caller_locations.last.absolute_path)&.match? %r{(exe|bin)/bundler?\z}
124
124
  shebang = File.read(exe).lines.first
125
125
  shebang.sub!(/^#!\s*/, "")
126
126
  unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby")
@@ -19,14 +19,7 @@ module Bundler
19
19
  BUNDLER_PREFIX = "BUNDLER_ORIG_"
20
20
 
21
21
  def self.from_env
22
- new(env_to_hash(ENV), BUNDLER_KEYS)
23
- end
24
-
25
- def self.env_to_hash(env)
26
- to_hash = env.to_hash
27
- return to_hash unless Gem.win_platform?
28
-
29
- to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v }
22
+ new(ENV.to_hash, BUNDLER_KEYS)
30
23
  end
31
24
 
32
25
  # @param env [Hash]
@@ -39,18 +32,7 @@ module Bundler
39
32
 
40
33
  # Replaces `ENV` with the bundler environment variables backed up
41
34
  def replace_with_backup
42
- unless Gem.win_platform?
43
- ENV.replace(backup)
44
- return
45
- end
46
-
47
- # Fallback logic for Windows below to workaround
48
- # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all
49
- # supported rubies include the fix for that.
50
-
51
- ENV.clear
52
-
53
- backup.each {|k, v| ENV[k] = v }
35
+ ENV.replace(backup)
54
36
  end
55
37
 
56
38
  # @return [Hash]
@@ -230,4 +230,18 @@ module Bundler
230
230
 
231
231
  status_code(38)
232
232
  end
233
+
234
+ class CorruptBundlerInstallError < BundlerError
235
+ def initialize(loaded_spec)
236
+ @loaded_spec = loaded_spec
237
+ end
238
+
239
+ def message
240
+ "The running version of Bundler (#{Bundler::VERSION}) does not match the version of the specification installed for it (#{@loaded_spec.version}). " \
241
+ "This can be caused by reinstalling Ruby without removing previous installation, leaving around an upgraded default version of Bundler. " \
242
+ "Reinstalling Ruby from scratch should fix the problem."
243
+ end
244
+
245
+ status_code(39)
246
+ end
233
247
  end
@@ -4,8 +4,6 @@ require_relative "base"
4
4
  require_relative "../worker"
5
5
 
6
6
  module Bundler
7
- autoload :CompactIndexClient, File.expand_path("../compact_index_client", __dir__)
8
-
9
7
  class Fetcher
10
8
  class CompactIndex < Base
11
9
  def self.compact_index_request(method_name)
@@ -36,15 +34,8 @@ module Bundler
36
34
 
37
35
  until remaining_gems.empty?
38
36
  log_specs { "Looking up gems #{remaining_gems.inspect}" }
39
-
40
- deps = begin
41
- parallel_compact_index_client.dependencies(remaining_gems)
42
- rescue TooManyRequestsError
43
- @bundle_worker&.stop
44
- @bundle_worker = nil # reset it. Not sure if necessary
45
- serial_compact_index_client.dependencies(remaining_gems)
46
- end
47
- next_gems = deps.flat_map {|d| d[3].flat_map(&:first) }.uniq
37
+ deps = fetch_gem_infos(remaining_gems).flatten(1)
38
+ next_gems = deps.flat_map {|d| d[CompactIndexClient::INFO_DEPS].flat_map(&:first) }.uniq
48
39
  deps.each {|dep| gem_info << dep }
49
40
  complete_gems.concat(deps.map(&:first)).uniq!
50
41
  remaining_gems = next_gems - complete_gems
@@ -61,7 +52,7 @@ module Bundler
61
52
  return nil
62
53
  end
63
54
  # Read info file checksums out of /versions, so we can know if gems are up to date
64
- compact_index_client.update_and_parse_checksums!
55
+ compact_index_client.available?
65
56
  rescue CompactIndexClient::Updater::MismatchedChecksumError => e
66
57
  Bundler.ui.debug(e.message)
67
58
  nil
@@ -81,20 +72,20 @@ module Bundler
81
72
  end
82
73
  end
83
74
 
84
- def parallel_compact_index_client
85
- compact_index_client.execution_mode = lambda do |inputs, &blk|
86
- func = lambda {|object, _index| blk.call(object) }
87
- worker = bundle_worker(func)
88
- inputs.each {|input| worker.enq(input) }
89
- inputs.map { worker.deq }
90
- end
91
-
92
- compact_index_client
75
+ def fetch_gem_infos(names)
76
+ in_parallel(names) {|name| compact_index_client.info(name) }
77
+ rescue TooManyRequestsError # rubygems.org is rate limiting us, slow down.
78
+ @bundle_worker&.stop
79
+ @bundle_worker = nil # reset it. Not sure if necessary
80
+ compact_index_client.reset!
81
+ names.map {|name| compact_index_client.info(name) }
93
82
  end
94
83
 
95
- def serial_compact_index_client
96
- compact_index_client.sequential_execution_mode!
97
- compact_index_client
84
+ def in_parallel(inputs, &blk)
85
+ func = lambda {|object, _index| blk.call(object) }
86
+ worker = bundle_worker(func)
87
+ inputs.each {|input| worker.enq(input) }
88
+ inputs.map { worker.deq }
98
89
  end
99
90
 
100
91
  def bundle_worker(func = nil)
@@ -2,8 +2,6 @@
2
2
 
3
3
  module Bundler
4
4
  module ForcePlatform
5
- private
6
-
7
5
  # The `:force_ruby_platform` value used by dependencies for resolution, and
8
6
  # by locked specifications for materialization is `false` by default, except
9
7
  # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform
@@ -47,7 +47,7 @@ module Bundler
47
47
  built_gem_path = build_gem
48
48
  end
49
49
 
50
- desc "Generate SHA512 checksum if #{name}-#{version}.gem into the checksums directory."
50
+ desc "Generate SHA512 checksum of #{name}-#{version}.gem into the checksums directory."
51
51
  task "build:checksum" => "build" do
52
52
  build_checksum(built_gem_path)
53
53
  end
@@ -46,19 +46,26 @@ module Bundler
46
46
  end
47
47
  module_function :platform_specificity_match
48
48
 
49
- def select_best_platform_match(specs, platform)
50
- matching = specs.select {|spec| spec.match_platform(platform) }
49
+ def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
50
+ matching = if force_ruby
51
+ specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
52
+ else
53
+ specs.select {|spec| spec.match_platform(platform) }
54
+ end
55
+
56
+ if prefer_locked
57
+ locked_originally = matching.select {|spec| spec.is_a?(LazySpecification) }
58
+ return locked_originally if locked_originally.any?
59
+ end
51
60
 
52
61
  sort_best_platform_match(matching, platform)
53
62
  end
54
63
  module_function :select_best_platform_match
55
64
 
56
- def force_ruby_platform(specs)
57
- matching = specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
58
-
59
- sort_best_platform_match(matching, Gem::Platform::RUBY)
65
+ def select_best_local_platform_match(specs, force_ruby: false)
66
+ select_best_platform_match(specs, local_platform, force_ruby: force_ruby).map(&:materialize_for_installation).compact
60
67
  end
61
- module_function :force_ruby_platform
68
+ module_function :select_best_local_platform_match
62
69
 
63
70
  def sort_best_platform_match(matching, platform)
64
71
  exact = matching.select {|spec| spec.platform == platform }