bundler 2.5.16 → 2.6.2

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 (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +194 -0
  3. data/bundler.gemspec +2 -2
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/cli/add.rb +3 -1
  6. data/lib/bundler/cli/check.rb +3 -3
  7. data/lib/bundler/cli/console.rb +0 -4
  8. data/lib/bundler/cli/doctor.rb +4 -4
  9. data/lib/bundler/cli/exec.rb +1 -0
  10. data/lib/bundler/cli/gem.rb +6 -3
  11. data/lib/bundler/cli/info.rb +2 -2
  12. data/lib/bundler/cli/inject.rb +1 -1
  13. data/lib/bundler/cli/install.rb +13 -4
  14. data/lib/bundler/cli/lock.rb +25 -6
  15. data/lib/bundler/cli/outdated.rb +16 -18
  16. data/lib/bundler/cli/pristine.rb +1 -1
  17. data/lib/bundler/cli/show.rb +2 -2
  18. data/lib/bundler/cli.rb +38 -68
  19. data/lib/bundler/compact_index_client/cache_file.rb +0 -5
  20. data/lib/bundler/compact_index_client/updater.rb +0 -11
  21. data/lib/bundler/definition.rb +186 -119
  22. data/lib/bundler/dependency.rb +1 -1
  23. data/lib/bundler/dsl.rb +67 -52
  24. data/lib/bundler/endpoint_specification.rb +10 -1
  25. data/lib/bundler/errors.rb +17 -5
  26. data/lib/bundler/feature_flag.rb +1 -0
  27. data/lib/bundler/fetcher/compact_index.rb +1 -1
  28. data/lib/bundler/fetcher.rb +12 -5
  29. data/lib/bundler/force_platform.rb +0 -2
  30. data/lib/bundler/gem_helpers.rb +21 -5
  31. data/lib/bundler/injector.rb +2 -2
  32. data/lib/bundler/inline.rb +42 -17
  33. data/lib/bundler/installer/gem_installer.rb +4 -2
  34. data/lib/bundler/installer/parallel_installer.rb +3 -2
  35. data/lib/bundler/installer/standalone.rb +2 -2
  36. data/lib/bundler/installer.rb +11 -47
  37. data/lib/bundler/lazy_specification.rb +74 -26
  38. data/lib/bundler/lockfile_generator.rb +1 -1
  39. data/lib/bundler/lockfile_parser.rb +10 -2
  40. data/lib/bundler/man/bundle-add.1 +42 -25
  41. data/lib/bundler/man/bundle-add.1.ronn +52 -23
  42. data/lib/bundler/man/bundle-binstubs.1 +7 -4
  43. data/lib/bundler/man/bundle-binstubs.1.ronn +6 -3
  44. data/lib/bundler/man/bundle-cache.1 +30 -2
  45. data/lib/bundler/man/bundle-cache.1.ronn +31 -2
  46. data/lib/bundler/man/bundle-check.1 +3 -3
  47. data/lib/bundler/man/bundle-check.1.ronn +4 -2
  48. data/lib/bundler/man/bundle-clean.1 +1 -1
  49. data/lib/bundler/man/bundle-config.1 +3 -5
  50. data/lib/bundler/man/bundle-config.1.ronn +2 -7
  51. data/lib/bundler/man/bundle-console.1 +2 -4
  52. data/lib/bundler/man/bundle-console.1.ronn +2 -7
  53. data/lib/bundler/man/bundle-doctor.1 +2 -2
  54. data/lib/bundler/man/bundle-doctor.1.ronn +1 -1
  55. data/lib/bundler/man/bundle-env.1 +9 -0
  56. data/lib/bundler/man/bundle-env.1.ronn +10 -0
  57. data/lib/bundler/man/bundle-exec.1 +5 -2
  58. data/lib/bundler/man/bundle-exec.1.ronn +4 -1
  59. data/lib/bundler/man/bundle-fund.1 +22 -0
  60. data/lib/bundler/man/bundle-fund.1.ronn +25 -0
  61. data/lib/bundler/man/bundle-gem.1 +17 -5
  62. data/lib/bundler/man/bundle-gem.1.ronn +27 -6
  63. data/lib/bundler/man/bundle-help.1 +1 -1
  64. data/lib/bundler/man/bundle-info.1 +5 -2
  65. data/lib/bundler/man/bundle-info.1.ronn +6 -2
  66. data/lib/bundler/man/bundle-init.1 +3 -3
  67. data/lib/bundler/man/bundle-init.1.ronn +3 -2
  68. data/lib/bundler/man/bundle-inject.1 +10 -2
  69. data/lib/bundler/man/bundle-inject.1.ronn +9 -1
  70. data/lib/bundler/man/bundle-install.1 +15 -12
  71. data/lib/bundler/man/bundle-install.1.ronn +22 -18
  72. data/lib/bundler/man/bundle-issue.1 +45 -0
  73. data/lib/bundler/man/bundle-issue.1.ronn +37 -0
  74. data/lib/bundler/man/bundle-licenses.1 +9 -0
  75. data/lib/bundler/man/bundle-licenses.1.ronn +10 -0
  76. data/lib/bundler/man/bundle-list.1 +1 -1
  77. data/lib/bundler/man/bundle-list.1.ronn +4 -1
  78. data/lib/bundler/man/bundle-lock.1 +21 -6
  79. data/lib/bundler/man/bundle-lock.1.ronn +25 -4
  80. data/lib/bundler/man/bundle-open.1 +2 -2
  81. data/lib/bundler/man/bundle-open.1.ronn +2 -1
  82. data/lib/bundler/man/bundle-outdated.1 +8 -5
  83. data/lib/bundler/man/bundle-outdated.1.ronn +8 -4
  84. data/lib/bundler/man/bundle-platform.1 +1 -1
  85. data/lib/bundler/man/bundle-plugin.1 +1 -1
  86. data/lib/bundler/man/bundle-pristine.1 +1 -1
  87. data/lib/bundler/man/bundle-pristine.1.ronn +1 -1
  88. data/lib/bundler/man/bundle-remove.1 +1 -1
  89. data/lib/bundler/man/bundle-remove.1.ronn +1 -1
  90. data/lib/bundler/man/bundle-show.1 +5 -2
  91. data/lib/bundler/man/bundle-show.1.ronn +4 -0
  92. data/lib/bundler/man/bundle-update.1 +13 -7
  93. data/lib/bundler/man/bundle-update.1.ronn +14 -6
  94. data/lib/bundler/man/bundle-version.1 +1 -1
  95. data/lib/bundler/man/bundle-viz.1 +4 -4
  96. data/lib/bundler/man/bundle-viz.1.ronn +7 -3
  97. data/lib/bundler/man/bundle.1 +1 -1
  98. data/lib/bundler/man/gemfile.5 +3 -1
  99. data/lib/bundler/man/gemfile.5.ronn +6 -0
  100. data/lib/bundler/man/index.txt +4 -0
  101. data/lib/bundler/materialization.rb +59 -0
  102. data/lib/bundler/plugin/api/source.rb +2 -1
  103. data/lib/bundler/plugin/events.rb +24 -0
  104. data/lib/bundler/plugin/installer.rb +1 -1
  105. data/lib/bundler/plugin.rb +20 -1
  106. data/lib/bundler/process_lock.rb +10 -14
  107. data/lib/bundler/remote_specification.rb +6 -1
  108. data/lib/bundler/resolver/base.rb +12 -6
  109. data/lib/bundler/resolver/candidate.rb +2 -2
  110. data/lib/bundler/resolver/package.rb +10 -1
  111. data/lib/bundler/resolver/spec_group.rb +4 -3
  112. data/lib/bundler/resolver.rb +36 -14
  113. data/lib/bundler/retry.rb +1 -1
  114. data/lib/bundler/ruby_version.rb +7 -1
  115. data/lib/bundler/rubygems_ext.rb +104 -51
  116. data/lib/bundler/rubygems_gem_installer.rb +7 -5
  117. data/lib/bundler/rubygems_integration.rb +23 -62
  118. data/lib/bundler/runtime.rb +22 -7
  119. data/lib/bundler/self_manager.rb +7 -7
  120. data/lib/bundler/settings.rb +6 -1
  121. data/lib/bundler/shared_helpers.rb +29 -17
  122. data/lib/bundler/source/git/git_proxy.rb +0 -2
  123. data/lib/bundler/source/git.rb +93 -40
  124. data/lib/bundler/source/metadata.rb +2 -3
  125. data/lib/bundler/source/path.rb +5 -3
  126. data/lib/bundler/source/rubygems.rb +6 -16
  127. data/lib/bundler/source_list.rb +1 -1
  128. data/lib/bundler/spec_set.rb +82 -57
  129. data/lib/bundler/stub_specification.rb +21 -2
  130. data/lib/bundler/templates/newgem/Gemfile.tt +0 -3
  131. data/lib/bundler/templates/newgem/README.md.tt +7 -3
  132. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +15 -15
  133. data/lib/bundler/templates/newgem/newgem.gemspec.tt +4 -4
  134. data/lib/bundler/ui/shell.rb +24 -2
  135. data/lib/bundler/ui/silent.rb +12 -1
  136. data/lib/bundler/uri_credentials_filter.rb +1 -1
  137. data/lib/bundler/vendor/fileutils/COPYING +56 -0
  138. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +15 -13
  139. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +46 -8
  140. data/lib/bundler/vendor/securerandom/.document +1 -0
  141. data/lib/bundler/vendor/securerandom/COPYING +56 -0
  142. data/lib/bundler/vendor/securerandom/lib/securerandom.rb +102 -0
  143. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +3 -5
  144. data/lib/bundler/vendor/thor/lib/thor/group.rb +11 -0
  145. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +1 -4
  146. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +2 -2
  147. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +2 -1
  148. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +9 -9
  149. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +1 -1
  150. data/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb +5 -21
  151. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  152. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  153. data/lib/bundler/vendor/thor/lib/thor.rb +11 -0
  154. data/lib/bundler/vendor/uri/COPYING +56 -0
  155. data/lib/bundler/vendor/uri/lib/uri/common.rb +37 -14
  156. data/lib/bundler/vendor/uri/lib/uri/file.rb +3 -3
  157. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +1 -1
  158. data/lib/bundler/vendor/uri/lib/uri/generic.rb +16 -26
  159. data/lib/bundler/vendor/uri/lib/uri/http.rb +2 -2
  160. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +10 -3
  161. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +26 -3
  162. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  163. data/lib/bundler/vendor/uri/lib/uri.rb +9 -9
  164. data/lib/bundler/vendored_securerandom.rb +12 -0
  165. data/lib/bundler/version.rb +1 -1
  166. data/lib/bundler/yaml_serializer.rb +1 -1
  167. data/lib/bundler.rb +68 -36
  168. metadata +20 -10
  169. data/lib/bundler/vendor/fileutils/LICENSE.txt +0 -22
  170. data/lib/bundler/vendor/uri/LICENSE.txt +0 -22
@@ -13,13 +13,14 @@ module Bundler
13
13
 
14
14
  attr_reader(
15
15
  :dependencies,
16
+ :locked_checksums,
16
17
  :locked_deps,
17
18
  :locked_gems,
18
19
  :platforms,
19
20
  :ruby_version,
20
21
  :lockfile,
21
22
  :gemfiles,
22
- :locked_checksums
23
+ :sources
23
24
  )
24
25
 
25
26
  # Given a gemfile and lockfile creates a Bundler definition
@@ -88,6 +89,7 @@ module Bundler
88
89
  @lockfile_contents = Bundler.read_file(lockfile)
89
90
  @locked_gems = LockfileParser.new(@lockfile_contents)
90
91
  @locked_platforms = @locked_gems.platforms
92
+ @most_specific_locked_platform = @locked_gems.most_specific_locked_platform
91
93
  @platforms = @locked_platforms.dup
92
94
  @locked_bundler_version = @locked_gems.bundler_version
93
95
  @locked_ruby_version = @locked_gems.ruby_version
@@ -107,15 +109,16 @@ module Bundler
107
109
  end
108
110
  else
109
111
  @unlock = {}
110
- @platforms = []
111
112
  @locked_gems = nil
113
+ @locked_platforms = []
114
+ @most_specific_locked_platform = nil
115
+ @platforms = []
112
116
  @locked_deps = {}
113
117
  @locked_specs = SpecSet.new([])
114
118
  @originally_locked_deps = {}
115
119
  @originally_locked_specs = @locked_specs
116
120
  @locked_sources = []
117
- @locked_platforms = []
118
- @locked_checksums = nil
121
+ @locked_checksums = Bundler.feature_flag.lockfile_checksums?
119
122
  end
120
123
 
121
124
  locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@@ -137,7 +140,7 @@ module Bundler
137
140
  end
138
141
  @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
139
142
 
140
- add_current_platform unless Bundler.frozen_bundle?
143
+ @current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
141
144
 
142
145
  converge_path_sources_to_gemspec_sources
143
146
  @path_changes = converge_paths
@@ -149,7 +152,7 @@ module Bundler
149
152
  @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
150
153
  else
151
154
  eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
152
- @gems_to_unlock = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
155
+ @gems_to_unlock = @locked_specs.for(eager_unlock, platforms).map(&:name).uniq
153
156
  end
154
157
 
155
158
  @dependency_changes = converge_dependencies
@@ -162,21 +165,57 @@ module Bundler
162
165
  @gem_version_promoter ||= GemVersionPromoter.new
163
166
  end
164
167
 
165
- def resolve_only_locally!
168
+ def check!
169
+ # If dependencies have changed, we need to resolve remotely. Otherwise,
170
+ # since we'll be resolving with a single local source, we may end up
171
+ # locking gems under the wrong source in the lockfile, and missing lockfile
172
+ # checksums
173
+ resolve_remotely! if @dependency_changes
174
+
175
+ # Now do a local only resolve, to verify if any gems are missing locally
166
176
  sources.local_only!
167
177
  resolve
168
178
  end
169
179
 
180
+ #
181
+ # Setup sources according to the given options and the state of the
182
+ # definition.
183
+ #
184
+ # @return [Boolean] Whether fetching remote information will be necessary or not
185
+ #
186
+ def setup_domain!(options = {})
187
+ prefer_local! if options[:"prefer-local"]
188
+
189
+ if options[:add_checksums] || (!options[:local] && install_needed?)
190
+ remotely!
191
+ true
192
+ else
193
+ Bundler.settings.set_command_option(:jobs, 1) unless install_needed? # to avoid the overhead of Bundler::Worker
194
+ with_cache!
195
+ false
196
+ end
197
+ end
198
+
170
199
  def resolve_with_cache!
200
+ with_cache!
201
+
202
+ resolve
203
+ end
204
+
205
+ def with_cache!
171
206
  sources.local!
172
207
  sources.cached!
173
- resolve
174
208
  end
175
209
 
176
210
  def resolve_remotely!
211
+ remotely!
212
+
213
+ resolve
214
+ end
215
+
216
+ def remotely!
177
217
  sources.cached!
178
218
  sources.remote!
179
- resolve
180
219
  end
181
220
 
182
221
  def prefer_local!
@@ -202,7 +241,7 @@ module Bundler
202
241
  end
203
242
 
204
243
  def missing_specs
205
- resolve.materialize(requested_dependencies).missing_specs
244
+ resolve.missing_specs_for(requested_dependencies)
206
245
  end
207
246
 
208
247
  def missing_specs?
@@ -214,6 +253,7 @@ module Bundler
214
253
  @resolve = nil
215
254
  @resolver = nil
216
255
  @resolution_packages = nil
256
+ @source_requirements = nil
217
257
  @specs = nil
218
258
 
219
259
  Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
@@ -265,11 +305,7 @@ module Bundler
265
305
  groups.map!(&:to_sym)
266
306
  deps = current_dependencies # always returns a new array
267
307
  deps.select! do |d|
268
- if RUBY_VERSION >= "3.1"
269
- d.groups.intersect?(groups)
270
- else
271
- !(d.groups & groups).empty?
272
- end
308
+ d.groups.intersect?(groups)
273
309
  end
274
310
  deps
275
311
  end
@@ -307,16 +343,16 @@ module Bundler
307
343
  end
308
344
 
309
345
  def spec_git_paths
310
- sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact
346
+ sources.git_sources.filter_map {|s| File.realpath(s.path) if File.exist?(s.path) }
311
347
  end
312
348
 
313
349
  def groups
314
- dependencies.map(&:groups).flatten.uniq
350
+ dependencies.flat_map(&:groups).uniq
315
351
  end
316
352
 
317
353
  def lock(file_or_preserve_unknown_sections = false, preserve_unknown_sections_or_unused = false)
318
354
  if [true, false, nil].include?(file_or_preserve_unknown_sections)
319
- target_lockfile = lockfile || Bundler.default_lockfile
355
+ target_lockfile = lockfile
320
356
  preserve_unknown_sections = file_or_preserve_unknown_sections
321
357
  else
322
358
  target_lockfile = file_or_preserve_unknown_sections
@@ -456,6 +492,12 @@ module Bundler
456
492
  "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again."
457
493
  end
458
494
 
495
+ def normalize_platforms
496
+ @platforms = resolve.normalize_platforms!(current_dependencies, platforms)
497
+
498
+ @resolve = SpecSet.new(resolve.for(current_dependencies, @platforms))
499
+ end
500
+
459
501
  def add_platform(platform)
460
502
  return if @platforms.include?(platform)
461
503
 
@@ -470,53 +512,63 @@ module Bundler
470
512
  raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
471
513
  end
472
514
 
473
- def most_specific_locked_platform
474
- @platforms.min_by do |bundle_platform|
475
- platform_specificity_match(bundle_platform, local_platform)
476
- end
477
- end
478
-
479
- attr_reader :sources
480
- private :sources
481
-
482
515
  def nothing_changed?
483
- return false unless lockfile_exists?
484
-
485
- !@source_changes &&
486
- !@dependency_changes &&
487
- @new_platforms.empty? &&
488
- !@path_changes &&
489
- !@local_changes &&
490
- !@missing_lockfile_dep &&
491
- !@unlocking_bundler &&
492
- !@locked_spec_with_missing_deps &&
493
- !@locked_spec_with_invalid_deps
516
+ !something_changed?
494
517
  end
495
518
 
496
519
  def no_resolve_needed?
497
- !unlocking? && nothing_changed?
520
+ !resolve_needed?
498
521
  end
499
522
 
500
523
  def unlocking?
501
524
  @unlocking
502
525
  end
503
526
 
527
+ attr_writer :source_requirements
528
+
529
+ def add_checksums
530
+ @locked_checksums = true
531
+
532
+ setup_domain!(add_checksums: true)
533
+
534
+ specs # force materialization to real specifications, so that checksums are fetched
535
+ end
536
+
504
537
  private
505
538
 
539
+ def install_needed?
540
+ resolve_needed? || missing_specs?
541
+ end
542
+
543
+ def something_changed?
544
+ return true unless lockfile_exists?
545
+
546
+ @source_changes ||
547
+ @dependency_changes ||
548
+ @current_platform_missing ||
549
+ @new_platforms.any? ||
550
+ @path_changes ||
551
+ @local_changes ||
552
+ @missing_lockfile_dep ||
553
+ @unlocking_bundler ||
554
+ @locked_spec_with_missing_deps ||
555
+ @locked_spec_with_invalid_deps
556
+ end
557
+
558
+ def resolve_needed?
559
+ unlocking? || something_changed?
560
+ end
561
+
506
562
  def should_add_extra_platforms?
507
563
  !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
508
564
  end
509
565
 
510
566
  def lockfile_exists?
511
- file_exists?(lockfile)
512
- end
513
-
514
- def file_exists?(file)
515
- file && File.exist?(file)
567
+ lockfile && File.exist?(lockfile)
516
568
  end
517
569
 
518
570
  def write_lock(file, preserve_unknown_sections)
519
- return if Definition.no_lock
571
+ return if Definition.no_lock || file.nil?
520
572
 
521
573
  contents = to_lock
522
574
 
@@ -533,7 +585,7 @@ module Bundler
533
585
 
534
586
  preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
535
587
 
536
- if file_exists?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
588
+ if File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
537
589
  return if Bundler.frozen_bundle?
538
590
  SharedHelpers.filesystem_access(file) { FileUtils.touch(file) }
539
591
  return
@@ -550,7 +602,7 @@ module Bundler
550
602
  end
551
603
 
552
604
  def resolver
553
- @resolver ||= Resolver.new(resolution_packages, gem_version_promoter)
605
+ @resolver ||= Resolver.new(resolution_packages, gem_version_promoter, @most_specific_locked_platform)
554
606
  end
555
607
 
556
608
  def expanded_dependencies
@@ -559,7 +611,7 @@ module Bundler
559
611
 
560
612
  def dependencies_with_bundler
561
613
  return dependencies unless @unlocking_bundler
562
- return dependencies if dependencies.map(&:name).include?("bundler")
614
+ return dependencies if dependencies.any? {|d| d.name == "bundler" }
563
615
 
564
616
  [Dependency.new("bundler", @unlocking_bundler)] + dependencies
565
617
  end
@@ -568,29 +620,53 @@ module Bundler
568
620
  @resolution_packages ||= begin
569
621
  last_resolve = converge_locked_specs
570
622
  remove_invalid_platforms!
571
- 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?)
623
+ 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?, prefer_local: @prefer_local)
572
624
  packages = additional_base_requirements_to_prevent_downgrades(packages, last_resolve)
573
625
  packages = additional_base_requirements_to_force_updates(packages)
574
626
  packages
575
627
  end
576
628
  end
577
629
 
578
- def filter_specs(specs, deps)
579
- SpecSet.new(specs).for(deps, false, platforms)
630
+ def filter_specs(specs, deps, skips: [])
631
+ SpecSet.new(specs).for(deps, platforms, skips: skips)
580
632
  end
581
633
 
582
634
  def materialize(dependencies)
583
- specs = resolve.materialize(dependencies)
584
- missing_specs = specs.missing_specs
635
+ # Tracks potential endless loops trying to re-resolve.
636
+ # TODO: Remove as dead code if not reports are received in a while
637
+ incorrect_spec = nil
638
+
639
+ specs = begin
640
+ resolve.materialize(dependencies)
641
+ rescue IncorrectLockfileDependencies => e
642
+ spec = e.spec
643
+ raise "Infinite loop while fixing lockfile dependencies" if incorrect_spec == spec
644
+
645
+ incorrect_spec = spec
646
+ reresolve_without([spec])
647
+ retry
648
+ end
649
+
650
+ missing_specs = resolve.missing_specs
585
651
 
586
652
  if missing_specs.any?
587
653
  missing_specs.each do |s|
588
654
  locked_gem = @locked_specs[s.name].last
589
655
  next if locked_gem.nil? || locked_gem.version != s.version || sources.local_mode?
590
- raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
591
- "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
592
- "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
593
- "removed in order to install."
656
+
657
+ message = if sources.implicit_global_source?
658
+ "Because your Gemfile specifies no global remote source, your bundle is locked to " \
659
+ "#{locked_gem} from #{locked_gem.source}. However, #{locked_gem} is not installed. You'll " \
660
+ "need to either add a global remote source to your Gemfile or make sure #{locked_gem} is " \
661
+ "available locally before rerunning Bundler."
662
+ else
663
+ "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
664
+ "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
665
+ "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
666
+ "removed in order to install."
667
+ end
668
+
669
+ raise GemNotFound, message
594
670
  end
595
671
 
596
672
  missing_specs_list = missing_specs.group_by(&:source).map do |source, missing_specs_for_source|
@@ -600,17 +676,24 @@ module Bundler
600
676
  raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}"
601
677
  end
602
678
 
603
- incomplete_specs = specs.incomplete_specs
679
+ partially_missing_specs = resolve.partially_missing_specs
680
+
681
+ if partially_missing_specs.any? && !sources.local_mode?
682
+ Bundler.ui.warn "Some locked specs have possibly been yanked (#{partially_missing_specs.map(&:full_name).join(", ")}). Ignoring them..."
683
+
684
+ resolve.delete(partially_missing_specs)
685
+ end
686
+
687
+ incomplete_specs = resolve.incomplete_specs
604
688
  loop do
605
689
  break if incomplete_specs.empty?
606
690
 
607
691
  Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
608
692
  sources.remote!
609
- resolution_packages.delete(incomplete_specs)
610
- @resolve = start_resolution
693
+ reresolve_without(incomplete_specs)
611
694
  specs = resolve.materialize(dependencies)
612
695
 
613
- still_incomplete_specs = specs.incomplete_specs
696
+ still_incomplete_specs = resolve.incomplete_specs
614
697
 
615
698
  if still_incomplete_specs == incomplete_specs
616
699
  package = resolution_packages.get_package(incomplete_specs.first.name)
@@ -620,15 +703,30 @@ module Bundler
620
703
  incomplete_specs = still_incomplete_specs
621
704
  end
622
705
 
706
+ insecurely_materialized_specs = resolve.insecurely_materialized_specs
707
+
708
+ if insecurely_materialized_specs.any?
709
+ Bundler.ui.warn "The following platform specific gems are getting installed, yet the lockfile includes only their generic ruby version:\n" \
710
+ " * #{insecurely_materialized_specs.map(&:full_name).join("\n * ")}\n" \
711
+ "Please run `bundle lock --normalize-platforms` and commit the resulting lockfile.\n" \
712
+ "Alternatively, you may run `bundle lock --add-platform <list-of-platforms-that-you-want-to-support>`"
713
+ end
714
+
623
715
  bundler = sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last
624
716
  specs["bundler"] = bundler
625
717
 
626
718
  specs
627
719
  end
628
720
 
721
+ def reresolve_without(incomplete_specs)
722
+ resolution_packages.delete(incomplete_specs)
723
+ @resolve = start_resolution
724
+ end
725
+
629
726
  def start_resolution
630
727
  local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
631
728
  @platforms << local_platform if local_platform_needed_for_resolvability
729
+ add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
632
730
 
633
731
  result = SpecSet.new(resolver.start)
634
732
 
@@ -644,26 +742,13 @@ module Bundler
644
742
 
645
743
  @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
646
744
 
647
- SpecSet.new(result.for(dependencies, false, @platforms))
745
+ SpecSet.new(result.for(dependencies, @platforms))
648
746
  end
649
747
 
650
748
  def precompute_source_requirements_for_indirect_dependencies?
651
749
  sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
652
750
  end
653
751
 
654
- def pin_locally_available_names(source_requirements)
655
- source_requirements.each_with_object({}) do |(name, original_source), new_source_requirements|
656
- local_source = original_source.dup
657
- local_source.local_only!
658
-
659
- new_source_requirements[name] = if local_source.specs.search(name).any?
660
- local_source
661
- else
662
- original_source
663
- end
664
- end
665
- end
666
-
667
752
  def current_platform_locked?
668
753
  @platforms.any? do |bundle_platform|
669
754
  MatchPlatform.platforms_match?(bundle_platform, local_platform)
@@ -671,19 +756,19 @@ module Bundler
671
756
  end
672
757
 
673
758
  def add_current_platform
674
- @most_specific_non_local_locked_ruby_platform = find_most_specific_non_local_locked_ruby_platform
759
+ return if @platforms.include?(local_platform)
760
+
761
+ @most_specific_non_local_locked_ruby_platform = find_most_specific_locked_ruby_platform
675
762
  return if @most_specific_non_local_locked_ruby_platform
676
763
 
677
- add_platform(local_platform)
764
+ @platforms << local_platform
765
+ true
678
766
  end
679
767
 
680
- def find_most_specific_non_local_locked_ruby_platform
768
+ def find_most_specific_locked_ruby_platform
681
769
  return unless generic_local_platform_is_ruby? && current_platform_locked?
682
770
 
683
- most_specific_locked_ruby_platform = most_specific_locked_platform
684
- return unless most_specific_locked_ruby_platform != local_platform
685
-
686
- most_specific_locked_ruby_platform
771
+ @most_specific_locked_platform
687
772
  end
688
773
 
689
774
  def change_reason
@@ -705,6 +790,7 @@ module Bundler
705
790
  [
706
791
  [@source_changes, "the list of sources changed"],
707
792
  [@dependency_changes, "the dependencies in your gemfile changed"],
793
+ [@current_platform_missing, "your lockfile does not include the current platform"],
708
794
  [@new_platforms.any?, "you added a new platform to your gemfile"],
709
795
  [@path_changes, "the gemspecs for path gems changed"],
710
796
  [@local_changes, "the gemspecs for git local gems changed"],
@@ -883,7 +969,7 @@ module Bundler
883
969
  def converge_locked_specs
884
970
  converged = converge_specs(@locked_specs)
885
971
 
886
- resolve = SpecSet.new(converged.reject {|s| @gems_to_unlock.include?(s.name) })
972
+ resolve = SpecSet.new(converged)
887
973
 
888
974
  diff = nil
889
975
 
@@ -904,8 +990,6 @@ module Bundler
904
990
  converged = []
905
991
  deps = []
906
992
 
907
- @specs_that_changed_sources = []
908
-
909
993
  specs.each do |s|
910
994
  name = s.name
911
995
  dep = @dependencies.find {|d| s.satisfies?(d) }
@@ -914,9 +998,7 @@ module Bundler
914
998
  if dep
915
999
  gemfile_source = dep.source || default_source
916
1000
 
917
- @specs_that_changed_sources << s if gemfile_source != lockfile_source
918
- deps << dep if !dep.source || lockfile_source.include?(dep.source)
919
- @gems_to_unlock << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
1001
+ deps << dep if !dep.source || lockfile_source.include?(dep.source) || new_deps.include?(dep)
920
1002
 
921
1003
  # Replace the locked dependency's source with the equivalent source from the Gemfile
922
1004
  s.source = gemfile_source
@@ -925,25 +1007,14 @@ module Bundler
925
1007
  s.source = default_source unless sources.get(lockfile_source)
926
1008
  end
927
1009
 
928
- next if @sources_to_unlock.include?(s.source.name)
1010
+ source = s.source
1011
+ next if @sources_to_unlock.include?(source.name)
929
1012
 
930
1013
  # Path sources have special logic
931
- if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
932
- new_specs = begin
933
- s.source.specs
934
- rescue PathError
935
- # if we won't need the source (according to the lockfile),
936
- # don't error if the path source isn't available
937
- next if specs.
938
- for(requested_dependencies, false).
939
- none? {|locked_spec| locked_spec.source == s.source }
940
-
941
- raise
942
- end
943
-
944
- new_spec = new_specs[s].first
1014
+ if source.instance_of?(Source::Path) || source.instance_of?(Source::Gemspec) || (source.instance_of?(Source::Git) && !@gems_to_unlock.include?(name) && deps.include?(dep))
1015
+ new_spec = source.specs[s].first
945
1016
  if new_spec
946
- s.dependencies.replace(new_spec.dependencies)
1017
+ s.runtime_dependencies.replace(new_spec.runtime_dependencies)
947
1018
  else
948
1019
  # If the spec is no longer in the path source, unlock it. This
949
1020
  # commonly happens if the version changed in the gemspec
@@ -951,14 +1022,15 @@ module Bundler
951
1022
  end
952
1023
  end
953
1024
 
954
- if dep.nil? && requested_dependencies.find {|d| name == d.name }
955
- @gems_to_unlock << s.name
956
- else
957
- converged << s
1025
+ if dep.nil? && requested_dep = requested_dependencies.find {|d| name == d.name }
1026
+ @gems_to_unlock << name
1027
+ deps << requested_dep
958
1028
  end
1029
+
1030
+ converged << s
959
1031
  end
960
1032
 
961
- filter_specs(converged, deps)
1033
+ filter_specs(converged, deps, skips: @gems_to_unlock)
962
1034
  end
963
1035
 
964
1036
  def metadata_dependencies
@@ -969,12 +1041,15 @@ module Bundler
969
1041
  end
970
1042
 
971
1043
  def source_requirements
1044
+ @source_requirements ||= find_source_requirements
1045
+ end
1046
+
1047
+ def find_source_requirements
972
1048
  # Record the specs available in each gem's source, so that those
973
1049
  # specs will be available later when the resolver knows where to
974
1050
  # look for that gemspec (or its dependencies)
975
1051
  source_requirements = if precompute_source_requirements_for_indirect_dependencies?
976
1052
  all_requirements = source_map.all_requirements
977
- all_requirements = pin_locally_available_names(all_requirements) if @prefer_local
978
1053
  { default: default_source }.merge(all_requirements)
979
1054
  else
980
1055
  { default: Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
@@ -993,7 +1068,6 @@ module Bundler
993
1068
  source_requirements["bundler"] = sources.metadata_source # needs to come last to override
994
1069
  end
995
1070
 
996
- verify_changed_sources!
997
1071
  source_requirements
998
1072
  end
999
1073
 
@@ -1001,14 +1075,6 @@ module Bundler
1001
1075
  sources.default_source
1002
1076
  end
1003
1077
 
1004
- def verify_changed_sources!
1005
- @specs_that_changed_sources.each do |s|
1006
- if s.source.specs.search(s.name).empty?
1007
- raise GemNotFound, "Could not find gem '#{s.name}' in #{s.source}"
1008
- end
1009
- end
1010
- end
1011
-
1012
1078
  def requested_groups
1013
1079
  values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
1014
1080
  values &= Bundler.settings[:only] unless Bundler.settings[:only].empty?
@@ -1050,6 +1116,7 @@ module Bundler
1050
1116
 
1051
1117
  def dup_for_full_unlock
1052
1118
  unlocked_definition = self.class.new(@lockfile, @dependencies, @sources, true, @ruby_version, @optional_groups, @gemfiles)
1119
+ unlocked_definition.source_requirements = source_requirements
1053
1120
  unlocked_definition.gem_version_promoter.tap do |gvp|
1054
1121
  gvp.level = gem_version_promoter.level
1055
1122
  gvp.strict = gem_version_promoter.strict
@@ -62,7 +62,7 @@ module Bundler
62
62
  end
63
63
 
64
64
  def expanded_platforms
65
- @expanded_platforms ||= @platforms.map {|pl| PLATFORM_MAP[pl] }.compact.flatten.uniq
65
+ @expanded_platforms ||= @platforms.filter_map {|pl| PLATFORM_MAP[pl] }.flatten.uniq
66
66
  end
67
67
 
68
68
  def should_include?