bundler 2.5.23 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -0
  3. data/bundler.gemspec +2 -2
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/cli/console.rb +0 -4
  6. data/lib/bundler/cli/doctor.rb +4 -4
  7. data/lib/bundler/cli/exec.rb +1 -0
  8. data/lib/bundler/cli/gem.rb +1 -1
  9. data/lib/bundler/cli/info.rb +2 -2
  10. data/lib/bundler/cli/inject.rb +1 -1
  11. data/lib/bundler/cli/install.rb +4 -0
  12. data/lib/bundler/cli/lock.rb +20 -1
  13. data/lib/bundler/cli/pristine.rb +1 -1
  14. data/lib/bundler/cli/show.rb +2 -2
  15. data/lib/bundler/cli.rb +22 -53
  16. data/lib/bundler/compact_index_client/cache_file.rb +0 -5
  17. data/lib/bundler/compact_index_client/updater.rb +0 -11
  18. data/lib/bundler/definition.rb +155 -74
  19. data/lib/bundler/dependency.rb +1 -1
  20. data/lib/bundler/dsl.rb +2 -13
  21. data/lib/bundler/endpoint_specification.rb +10 -1
  22. data/lib/bundler/errors.rb +10 -0
  23. data/lib/bundler/feature_flag.rb +1 -0
  24. data/lib/bundler/fetcher/compact_index.rb +1 -1
  25. data/lib/bundler/fetcher.rb +10 -3
  26. data/lib/bundler/gem_helpers.rb +21 -5
  27. data/lib/bundler/injector.rb +2 -2
  28. data/lib/bundler/installer/standalone.rb +2 -2
  29. data/lib/bundler/installer.rb +4 -38
  30. data/lib/bundler/lazy_specification.rb +65 -24
  31. data/lib/bundler/lockfile_parser.rb +9 -1
  32. data/lib/bundler/man/bundle-add.1 +13 -10
  33. data/lib/bundler/man/bundle-add.1.ronn +12 -9
  34. data/lib/bundler/man/bundle-binstubs.1 +7 -4
  35. data/lib/bundler/man/bundle-binstubs.1.ronn +6 -3
  36. data/lib/bundler/man/bundle-cache.1 +30 -2
  37. data/lib/bundler/man/bundle-cache.1.ronn +31 -2
  38. data/lib/bundler/man/bundle-check.1 +3 -3
  39. data/lib/bundler/man/bundle-check.1.ronn +4 -2
  40. data/lib/bundler/man/bundle-clean.1 +1 -1
  41. data/lib/bundler/man/bundle-config.1 +3 -1
  42. data/lib/bundler/man/bundle-config.1.ronn +2 -0
  43. data/lib/bundler/man/bundle-console.1 +2 -4
  44. data/lib/bundler/man/bundle-console.1.ronn +2 -7
  45. data/lib/bundler/man/bundle-doctor.1 +2 -2
  46. data/lib/bundler/man/bundle-doctor.1.ronn +1 -1
  47. data/lib/bundler/man/bundle-env.1 +9 -0
  48. data/lib/bundler/man/bundle-env.1.ronn +10 -0
  49. data/lib/bundler/man/bundle-exec.1 +5 -2
  50. data/lib/bundler/man/bundle-exec.1.ronn +4 -1
  51. data/lib/bundler/man/bundle-fund.1 +22 -0
  52. data/lib/bundler/man/bundle-fund.1.ronn +25 -0
  53. data/lib/bundler/man/bundle-gem.1 +17 -5
  54. data/lib/bundler/man/bundle-gem.1.ronn +27 -6
  55. data/lib/bundler/man/bundle-help.1 +1 -1
  56. data/lib/bundler/man/bundle-info.1 +5 -2
  57. data/lib/bundler/man/bundle-info.1.ronn +6 -2
  58. data/lib/bundler/man/bundle-init.1 +3 -3
  59. data/lib/bundler/man/bundle-init.1.ronn +3 -2
  60. data/lib/bundler/man/bundle-inject.1 +10 -2
  61. data/lib/bundler/man/bundle-inject.1.ronn +9 -1
  62. data/lib/bundler/man/bundle-install.1 +14 -11
  63. data/lib/bundler/man/bundle-install.1.ronn +21 -16
  64. data/lib/bundler/man/bundle-issue.1 +45 -0
  65. data/lib/bundler/man/bundle-issue.1.ronn +37 -0
  66. data/lib/bundler/man/bundle-licenses.1 +9 -0
  67. data/lib/bundler/man/bundle-licenses.1.ronn +10 -0
  68. data/lib/bundler/man/bundle-list.1 +1 -1
  69. data/lib/bundler/man/bundle-list.1.ronn +4 -1
  70. data/lib/bundler/man/bundle-lock.1 +21 -6
  71. data/lib/bundler/man/bundle-lock.1.ronn +25 -4
  72. data/lib/bundler/man/bundle-open.1 +2 -2
  73. data/lib/bundler/man/bundle-open.1.ronn +2 -1
  74. data/lib/bundler/man/bundle-outdated.1 +8 -5
  75. data/lib/bundler/man/bundle-outdated.1.ronn +8 -4
  76. data/lib/bundler/man/bundle-platform.1 +1 -1
  77. data/lib/bundler/man/bundle-plugin.1 +1 -1
  78. data/lib/bundler/man/bundle-pristine.1 +1 -1
  79. data/lib/bundler/man/bundle-pristine.1.ronn +1 -1
  80. data/lib/bundler/man/bundle-remove.1 +1 -1
  81. data/lib/bundler/man/bundle-remove.1.ronn +1 -1
  82. data/lib/bundler/man/bundle-show.1 +5 -2
  83. data/lib/bundler/man/bundle-show.1.ronn +4 -0
  84. data/lib/bundler/man/bundle-update.1 +13 -7
  85. data/lib/bundler/man/bundle-update.1.ronn +14 -6
  86. data/lib/bundler/man/bundle-version.1 +1 -1
  87. data/lib/bundler/man/bundle-viz.1 +4 -4
  88. data/lib/bundler/man/bundle-viz.1.ronn +7 -3
  89. data/lib/bundler/man/bundle.1 +1 -1
  90. data/lib/bundler/man/gemfile.5 +1 -1
  91. data/lib/bundler/man/index.txt +4 -0
  92. data/lib/bundler/materialization.rb +59 -0
  93. data/lib/bundler/plugin/events.rb +24 -0
  94. data/lib/bundler/plugin/installer.rb +1 -1
  95. data/lib/bundler/process_lock.rb +1 -1
  96. data/lib/bundler/remote_specification.rb +6 -1
  97. data/lib/bundler/resolver/base.rb +2 -6
  98. data/lib/bundler/resolver/candidate.rb +2 -2
  99. data/lib/bundler/resolver/spec_group.rb +4 -3
  100. data/lib/bundler/resolver.rb +5 -5
  101. data/lib/bundler/rubygems_ext.rb +28 -28
  102. data/lib/bundler/rubygems_gem_installer.rb +0 -1
  103. data/lib/bundler/rubygems_integration.rb +21 -11
  104. data/lib/bundler/runtime.rb +27 -7
  105. data/lib/bundler/self_manager.rb +2 -3
  106. data/lib/bundler/settings.rb +1 -0
  107. data/lib/bundler/shared_helpers.rb +2 -2
  108. data/lib/bundler/source/git/git_proxy.rb +0 -6
  109. data/lib/bundler/source/git.rb +56 -31
  110. data/lib/bundler/source/path.rb +2 -2
  111. data/lib/bundler/source_list.rb +1 -1
  112. data/lib/bundler/spec_set.rb +81 -56
  113. data/lib/bundler/stub_specification.rb +8 -0
  114. data/lib/bundler/templates/newgem/README.md.tt +1 -1
  115. data/lib/bundler/uri_credentials_filter.rb +1 -1
  116. data/lib/bundler/vendor/fileutils/COPYING +56 -0
  117. data/lib/bundler/vendor/fileutils/lib/fileutils.rb +15 -13
  118. data/lib/bundler/vendor/securerandom/COPYING +56 -0
  119. data/lib/bundler/vendor/securerandom/lib/securerandom.rb +11 -5
  120. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +3 -5
  121. data/lib/bundler/vendor/thor/lib/thor/group.rb +11 -0
  122. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +1 -4
  123. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +2 -2
  124. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +2 -1
  125. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +9 -9
  126. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +1 -1
  127. data/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb +5 -21
  128. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  129. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  130. data/lib/bundler/vendor/thor/lib/thor.rb +11 -0
  131. data/lib/bundler/vendor/uri/COPYING +56 -0
  132. data/lib/bundler/vendor/uri/lib/uri/common.rb +37 -16
  133. data/lib/bundler/vendor/uri/lib/uri/file.rb +3 -3
  134. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +1 -1
  135. data/lib/bundler/vendor/uri/lib/uri/generic.rb +16 -26
  136. data/lib/bundler/vendor/uri/lib/uri/http.rb +2 -2
  137. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +10 -3
  138. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +26 -3
  139. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  140. data/lib/bundler/vendor/uri/lib/uri.rb +9 -9
  141. data/lib/bundler/vendored_securerandom.rb +0 -2
  142. data/lib/bundler/version.rb +1 -1
  143. data/lib/bundler.rb +37 -13
  144. metadata +18 -12
  145. data/lib/bundler/vendor/fileutils/LICENSE.txt +0 -22
  146. data/lib/bundler/vendor/securerandom/LICENSE.txt +0 -22
  147. data/lib/bundler/vendor/securerandom/lib/random/formatter.rb +0 -373
  148. data/lib/bundler/vendor/uri/LICENSE.txt +0 -22
@@ -13,13 +13,13 @@ 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
23
  :sources
24
24
  )
25
25
 
@@ -89,6 +89,7 @@ module Bundler
89
89
  @lockfile_contents = Bundler.read_file(lockfile)
90
90
  @locked_gems = LockfileParser.new(@lockfile_contents)
91
91
  @locked_platforms = @locked_gems.platforms
92
+ @most_specific_locked_platform = @locked_gems.most_specific_locked_platform
92
93
  @platforms = @locked_platforms.dup
93
94
  @locked_bundler_version = @locked_gems.bundler_version
94
95
  @locked_ruby_version = @locked_gems.ruby_version
@@ -108,15 +109,16 @@ module Bundler
108
109
  end
109
110
  else
110
111
  @unlock = {}
111
- @platforms = []
112
112
  @locked_gems = nil
113
+ @locked_platforms = []
114
+ @most_specific_locked_platform = nil
115
+ @platforms = []
113
116
  @locked_deps = {}
114
117
  @locked_specs = SpecSet.new([])
115
118
  @originally_locked_deps = {}
116
119
  @originally_locked_specs = @locked_specs
117
120
  @locked_sources = []
118
- @locked_platforms = []
119
- @locked_checksums = Bundler.feature_flag.bundler_3_mode?
121
+ @locked_checksums = Bundler.feature_flag.lockfile_checksums?
120
122
  end
121
123
 
122
124
  locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@@ -150,7 +152,7 @@ module Bundler
150
152
  @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
151
153
  else
152
154
  eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
153
- @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
154
156
  end
155
157
 
156
158
  @dependency_changes = converge_dependencies
@@ -175,16 +177,45 @@ module Bundler
175
177
  resolve
176
178
  end
177
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
+
178
199
  def resolve_with_cache!
200
+ with_cache!
201
+
202
+ resolve
203
+ end
204
+
205
+ def with_cache!
179
206
  sources.local!
180
207
  sources.cached!
181
- resolve
182
208
  end
183
209
 
184
210
  def resolve_remotely!
211
+ remotely!
212
+
213
+ resolve
214
+ end
215
+
216
+ def remotely!
185
217
  sources.cached!
186
218
  sources.remote!
187
- resolve
188
219
  end
189
220
 
190
221
  def prefer_local!
@@ -210,7 +241,7 @@ module Bundler
210
241
  end
211
242
 
212
243
  def missing_specs
213
- resolve.materialize(requested_dependencies).missing_specs
244
+ resolve.missing_specs_for(requested_dependencies)
214
245
  end
215
246
 
216
247
  def missing_specs?
@@ -274,11 +305,7 @@ module Bundler
274
305
  groups.map!(&:to_sym)
275
306
  deps = current_dependencies # always returns a new array
276
307
  deps.select! do |d|
277
- if RUBY_VERSION >= "3.1"
278
- d.groups.intersect?(groups)
279
- else
280
- !(d.groups & groups).empty?
281
- end
308
+ d.groups.intersect?(groups)
282
309
  end
283
310
  deps
284
311
  end
@@ -316,11 +343,11 @@ module Bundler
316
343
  end
317
344
 
318
345
  def spec_git_paths
319
- 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) }
320
347
  end
321
348
 
322
349
  def groups
323
- dependencies.map(&:groups).flatten.uniq
350
+ dependencies.flat_map(&:groups).uniq
324
351
  end
325
352
 
326
353
  def lock(file_or_preserve_unknown_sections = false, preserve_unknown_sections_or_unused = false)
@@ -465,6 +492,12 @@ module Bundler
465
492
  "Add the current platform to the lockfile with\n`bundle lock --add-platform #{local_platform}` and try again."
466
493
  end
467
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
+
468
501
  def add_platform(platform)
469
502
  return if @platforms.include?(platform)
470
503
 
@@ -479,29 +512,12 @@ module Bundler
479
512
  raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
480
513
  end
481
514
 
482
- def most_specific_locked_platform
483
- @platforms.min_by do |bundle_platform|
484
- platform_specificity_match(bundle_platform, local_platform)
485
- end
486
- end
487
-
488
515
  def nothing_changed?
489
- return false unless lockfile_exists?
490
-
491
- !@source_changes &&
492
- !@dependency_changes &&
493
- !@current_platform_missing &&
494
- @new_platforms.empty? &&
495
- !@path_changes &&
496
- !@local_changes &&
497
- !@missing_lockfile_dep &&
498
- !@unlocking_bundler &&
499
- !@locked_spec_with_missing_deps &&
500
- !@locked_spec_with_invalid_deps
516
+ !something_changed?
501
517
  end
502
518
 
503
519
  def no_resolve_needed?
504
- !unlocking? && nothing_changed?
520
+ !resolve_needed?
505
521
  end
506
522
 
507
523
  def unlocking?
@@ -510,8 +526,39 @@ module Bundler
510
526
 
511
527
  attr_writer :source_requirements
512
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
+
513
537
  private
514
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
+
515
562
  def should_add_extra_platforms?
516
563
  !lockfile_exists? && generic_local_platform_is_ruby? && !Bundler.settings[:force_ruby_platform]
517
564
  end
@@ -555,7 +602,7 @@ module Bundler
555
602
  end
556
603
 
557
604
  def resolver
558
- @resolver ||= Resolver.new(resolution_packages, gem_version_promoter)
605
+ @resolver ||= Resolver.new(resolution_packages, gem_version_promoter, @most_specific_locked_platform)
559
606
  end
560
607
 
561
608
  def expanded_dependencies
@@ -564,7 +611,7 @@ module Bundler
564
611
 
565
612
  def dependencies_with_bundler
566
613
  return dependencies unless @unlocking_bundler
567
- return dependencies if dependencies.map(&:name).include?("bundler")
614
+ return dependencies if dependencies.any? {|d| d.name == "bundler" }
568
615
 
569
616
  [Dependency.new("bundler", @unlocking_bundler)] + dependencies
570
617
  end
@@ -580,22 +627,46 @@ module Bundler
580
627
  end
581
628
  end
582
629
 
583
- def filter_specs(specs, deps)
584
- SpecSet.new(specs).for(deps, false, platforms)
630
+ def filter_specs(specs, deps, skips: [])
631
+ SpecSet.new(specs).for(deps, platforms, skips: skips)
585
632
  end
586
633
 
587
634
  def materialize(dependencies)
588
- specs = resolve.materialize(dependencies)
589
- 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
590
651
 
591
652
  if missing_specs.any?
592
653
  missing_specs.each do |s|
593
654
  locked_gem = @locked_specs[s.name].last
594
655
  next if locked_gem.nil? || locked_gem.version != s.version || sources.local_mode?
595
- raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
596
- "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
597
- "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
598
- "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
599
670
  end
600
671
 
601
672
  missing_specs_list = missing_specs.group_by(&:source).map do |source, missing_specs_for_source|
@@ -605,17 +676,24 @@ module Bundler
605
676
  raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}"
606
677
  end
607
678
 
608
- 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
609
688
  loop do
610
689
  break if incomplete_specs.empty?
611
690
 
612
691
  Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
613
692
  sources.remote!
614
- resolution_packages.delete(incomplete_specs)
615
- @resolve = start_resolution
693
+ reresolve_without(incomplete_specs)
616
694
  specs = resolve.materialize(dependencies)
617
695
 
618
- still_incomplete_specs = specs.incomplete_specs
696
+ still_incomplete_specs = resolve.incomplete_specs
619
697
 
620
698
  if still_incomplete_specs == incomplete_specs
621
699
  package = resolution_packages.get_package(incomplete_specs.first.name)
@@ -625,12 +703,26 @@ module Bundler
625
703
  incomplete_specs = still_incomplete_specs
626
704
  end
627
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
+
628
715
  bundler = sources.metadata_source.specs.search(["bundler", Bundler.gem_version]).last
629
716
  specs["bundler"] = bundler
630
717
 
631
718
  specs
632
719
  end
633
720
 
721
+ def reresolve_without(incomplete_specs)
722
+ resolution_packages.delete(incomplete_specs)
723
+ @resolve = start_resolution
724
+ end
725
+
634
726
  def start_resolution
635
727
  local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
636
728
  @platforms << local_platform if local_platform_needed_for_resolvability
@@ -650,7 +742,7 @@ module Bundler
650
742
 
651
743
  @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
652
744
 
653
- SpecSet.new(result.for(dependencies, false, @platforms))
745
+ SpecSet.new(result.for(dependencies, @platforms))
654
746
  end
655
747
 
656
748
  def precompute_source_requirements_for_indirect_dependencies?
@@ -676,7 +768,7 @@ module Bundler
676
768
  def find_most_specific_locked_ruby_platform
677
769
  return unless generic_local_platform_is_ruby? && current_platform_locked?
678
770
 
679
- most_specific_locked_platform
771
+ @most_specific_locked_platform
680
772
  end
681
773
 
682
774
  def change_reason
@@ -877,7 +969,7 @@ module Bundler
877
969
  def converge_locked_specs
878
970
  converged = converge_specs(@locked_specs)
879
971
 
880
- resolve = SpecSet.new(converged.reject {|s| @gems_to_unlock.include?(s.name) })
972
+ resolve = SpecSet.new(converged)
881
973
 
882
974
  diff = nil
883
975
 
@@ -906,8 +998,7 @@ module Bundler
906
998
  if dep
907
999
  gemfile_source = dep.source || default_source
908
1000
 
909
- deps << dep if !dep.source || lockfile_source.include?(dep.source)
910
- @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)
911
1002
 
912
1003
  # Replace the locked dependency's source with the equivalent source from the Gemfile
913
1004
  s.source = gemfile_source
@@ -916,25 +1007,14 @@ module Bundler
916
1007
  s.source = default_source unless sources.get(lockfile_source)
917
1008
  end
918
1009
 
919
- next if @sources_to_unlock.include?(s.source.name)
1010
+ source = s.source
1011
+ next if @sources_to_unlock.include?(source.name)
920
1012
 
921
1013
  # Path sources have special logic
922
- if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
923
- new_specs = begin
924
- s.source.specs
925
- rescue PathError
926
- # if we won't need the source (according to the lockfile),
927
- # don't error if the path source isn't available
928
- next if specs.
929
- for(requested_dependencies, false).
930
- none? {|locked_spec| locked_spec.source == s.source }
931
-
932
- raise
933
- end
934
-
935
- 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
936
1016
  if new_spec
937
- s.dependencies.replace(new_spec.dependencies)
1017
+ s.runtime_dependencies.replace(new_spec.runtime_dependencies)
938
1018
  else
939
1019
  # If the spec is no longer in the path source, unlock it. This
940
1020
  # commonly happens if the version changed in the gemspec
@@ -942,14 +1022,15 @@ module Bundler
942
1022
  end
943
1023
  end
944
1024
 
945
- if dep.nil? && requested_dependencies.find {|d| name == d.name }
946
- @gems_to_unlock << s.name
947
- else
948
- converged << s
1025
+ if dep.nil? && requested_dep = requested_dependencies.find {|d| name == d.name }
1026
+ @gems_to_unlock << name
1027
+ deps << requested_dep
949
1028
  end
1029
+
1030
+ converged << s
950
1031
  end
951
1032
 
952
- filter_specs(converged, deps)
1033
+ filter_specs(converged, deps, skips: @gems_to_unlock)
953
1034
  end
954
1035
 
955
1036
  def metadata_dependencies
@@ -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?
data/lib/bundler/dsl.rb CHANGED
@@ -66,7 +66,7 @@ module Bundler
66
66
  development_group = opts[:development_group] || :development
67
67
  expanded_path = gemfile_root.join(path)
68
68
 
69
- gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).map {|g| Bundler.load_gemspec(g) }.compact
69
+ gemspecs = Gem::Util.glob_files_in_dir("{,*}.gemspec", expanded_path).filter_map {|g| Bundler.load_gemspec(g) }
70
70
  gemspecs.reject! {|s| s.name != name } if name
71
71
  specs_by_name_and_version = gemspecs.group_by {|s| [s.name, s.version] }
72
72
 
@@ -503,18 +503,7 @@ module Bundler
503
503
  end
504
504
 
505
505
  def check_rubygems_source_safety
506
- if @sources.implicit_global_source?
507
- implicit_global_source_warning
508
- elsif @sources.aggregate_global_source?
509
- multiple_global_source_warning
510
- end
511
- end
512
-
513
- def implicit_global_source_warning
514
- Bundler::SharedHelpers.major_deprecation 2, "This Gemfile does not include an explicit global source. " \
515
- "Not using an explicit global source may result in a different lockfile being generated depending on " \
516
- "the gems you have installed locally before bundler is run. " \
517
- "Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\"."
506
+ multiple_global_source_warning if @sources.aggregate_global_source?
518
507
  end
519
508
 
520
509
  def multiple_global_source_warning
@@ -6,7 +6,7 @@ module Bundler
6
6
  include MatchRemoteMetadata
7
7
 
8
8
  attr_reader :name, :version, :platform, :checksum
9
- attr_accessor :source, :remote, :dependencies
9
+ attr_accessor :remote, :dependencies, :locked_platform
10
10
 
11
11
  def initialize(name, version, platform, spec_fetcher, dependencies, metadata = nil)
12
12
  super()
@@ -18,10 +18,15 @@ module Bundler
18
18
 
19
19
  @loaded_from = nil
20
20
  @remote_specification = nil
21
+ @locked_platform = nil
21
22
 
22
23
  parse_metadata(metadata)
23
24
  end
24
25
 
26
+ def insecurely_materialized?
27
+ @locked_platform.to_s != @platform.to_s
28
+ end
29
+
25
30
  def fetch_platform
26
31
  @platform
27
32
  end
@@ -115,6 +120,10 @@ module Bundler
115
120
  @remote_specification = spec
116
121
  end
117
122
 
123
+ def inspect
124
+ "#<#{self.class} @name=\"#{name}\" (#{full_name.delete_prefix("#{name}-")})>"
125
+ end
126
+
118
127
  private
119
128
 
120
129
  def _remote_specification
@@ -246,4 +246,14 @@ module Bundler
246
246
  end
247
247
 
248
248
  class InvalidArgumentError < BundlerError; status_code(40); end
249
+
250
+ class IncorrectLockfileDependencies < BundlerError
251
+ attr_reader :spec
252
+
253
+ def initialize(spec)
254
+ @spec = spec
255
+ end
256
+
257
+ status_code(41)
258
+ end
249
259
  end
@@ -33,6 +33,7 @@ module Bundler
33
33
  settings_flag(:default_install_uses_path) { bundler_3_mode? }
34
34
  settings_flag(:forget_cli_options) { bundler_3_mode? }
35
35
  settings_flag(:global_gem_cache) { bundler_3_mode? }
36
+ settings_flag(:lockfile_checksums) { bundler_3_mode? }
36
37
  settings_flag(:path_relative_to_cwd) { bundler_3_mode? }
37
38
  settings_flag(:plugins) { @bundler_version >= Gem::Version.new("1.14") }
38
39
  settings_flag(:print_only_version_number) { bundler_3_mode? }
@@ -10,7 +10,7 @@ module Bundler
10
10
  method = instance_method(method_name)
11
11
  undef_method(method_name)
12
12
  define_method(method_name) do |*args, &blk|
13
- method.bind(self).call(*args, &blk)
13
+ method.bind_call(self, *args, &blk)
14
14
  rescue NetworkDownError, CompactIndexClient::Updater::MismatchedChecksumError => e
15
15
  raise HTTPError, e.message
16
16
  rescue AuthenticationRequiredError, BadAuthenticationError
@@ -37,8 +37,9 @@ module Bundler
37
37
  # This is the error raised when a source is HTTPS and OpenSSL didn't load
38
38
  class SSLError < HTTPError
39
39
  def initialize(msg = nil)
40
- super msg || "Could not load OpenSSL.\n" \
41
- "You must recompile Ruby with OpenSSL support."
40
+ super "Could not load OpenSSL.\n" \
41
+ "You must recompile Ruby with OpenSSL support.\n" \
42
+ "original error: #{msg}\n"
42
43
  end
43
44
  end
44
45
 
@@ -251,7 +252,13 @@ module Bundler
251
252
  needs_ssl = remote_uri.scheme == "https" ||
252
253
  Bundler.settings[:ssl_verify_mode] ||
253
254
  Bundler.settings[:ssl_client_cert]
254
- raise SSLError if needs_ssl && !defined?(OpenSSL::SSL)
255
+ if needs_ssl
256
+ begin
257
+ require "openssl"
258
+ rescue StandardError, LoadError => e
259
+ raise SSLError.new(e.message)
260
+ end
261
+ end
255
262
 
256
263
  con = Gem::Net::HTTP::Persistent.new name: "bundler", proxy: :ENV
257
264
  if gem_proxy = Gem.configuration[:http_proxy]
@@ -46,7 +46,7 @@ module Bundler
46
46
  end
47
47
  module_function :platform_specificity_match
48
48
 
49
- def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
49
+ def select_all_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
50
50
  matching = if force_ruby
51
51
  specs.select {|spec| spec.match_platform(Gem::Platform::RUBY) && spec.force_ruby_platform! }
52
52
  else
@@ -58,24 +58,40 @@ module Bundler
58
58
  return locked_originally if locked_originally.any?
59
59
  end
60
60
 
61
- sort_best_platform_match(matching, platform)
61
+ matching
62
+ end
63
+ module_function :select_all_platform_match
64
+
65
+ def select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
66
+ matching = select_all_platform_match(specs, platform, force_ruby: force_ruby, prefer_locked: prefer_locked)
67
+
68
+ sort_and_filter_best_platform_match(matching, platform)
62
69
  end
63
70
  module_function :select_best_platform_match
64
71
 
65
72
  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
73
+ matching = select_all_platform_match(specs, local_platform, force_ruby: force_ruby).filter_map(&:materialized_for_installation)
74
+
75
+ sort_best_platform_match(matching, local_platform)
67
76
  end
68
77
  module_function :select_best_local_platform_match
69
78
 
70
- def sort_best_platform_match(matching, platform)
79
+ def sort_and_filter_best_platform_match(matching, platform)
80
+ return matching if matching.one?
81
+
71
82
  exact = matching.select {|spec| spec.platform == platform }
72
83
  return exact if exact.any?
73
84
 
74
- sorted_matching = matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) }
85
+ sorted_matching = sort_best_platform_match(matching, platform)
75
86
  exemplary_spec = sorted_matching.first
76
87
 
77
88
  sorted_matching.take_while {|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) }
78
89
  end
90
+ module_function :sort_and_filter_best_platform_match
91
+
92
+ def sort_best_platform_match(matching, platform)
93
+ matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) }
94
+ end
79
95
  module_function :sort_best_platform_match
80
96
 
81
97
  class PlatformMatch
@@ -41,7 +41,7 @@ module Bundler
41
41
 
42
42
  # resolve to see if the new deps broke anything
43
43
  @definition = builder.to_definition(lockfile_path, {})
44
- @definition.resolve_remotely!
44
+ @definition.remotely!
45
45
 
46
46
  # since nothing broke, we can add those gems to the gemfile
47
47
  append_to(gemfile_path, build_gem_lines(@options[:conservative_versioning])) if @deps.any?
@@ -184,7 +184,7 @@ module Bundler
184
184
  # @param [Array] gems Array of names of gems to be removed.
185
185
  # @param [Pathname] gemfile_path The Gemfile from which to remove dependencies.
186
186
  def remove_gems_from_gemfile(gems, gemfile_path)
187
- patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2\)/
187
+ patterns = /gem\s+(['"])#{Regexp.union(gems)}\1|gem\s*\((['"])#{Regexp.union(gems)}\2.*\)/
188
188
  new_gemfile = []
189
189
  multiline_removal = false
190
190
  File.readlines(gemfile_path).each do |line|
@@ -28,7 +28,7 @@ module Bundler
28
28
  private
29
29
 
30
30
  def paths
31
- @specs.map do |spec|
31
+ @specs.flat_map do |spec|
32
32
  next if spec.name == "bundler"
33
33
  Array(spec.require_paths).map do |path|
34
34
  gem_path(path, spec).
@@ -36,7 +36,7 @@ module Bundler
36
36
  sub(extensions_dir, 'extensions/\k<platform>/#{Gem.extension_api_version}')
37
37
  # This is a static string intentionally. It's interpolated at a later time.
38
38
  end
39
- end.flatten.compact
39
+ end.compact
40
40
  end
41
41
 
42
42
  def version_dir