bundler 2.5.9 → 2.5.17

Sign up to get free protection for your applications and to get access to all the features.
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 }