bundler 2.2.26 → 2.3.4

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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +166 -1
  3. data/README.md +1 -1
  4. data/exe/bundle +7 -8
  5. data/lib/bundler/.document +1 -0
  6. data/lib/bundler/build_metadata.rb +2 -2
  7. data/lib/bundler/cli/check.rb +1 -1
  8. data/lib/bundler/cli/doctor.rb +3 -2
  9. data/lib/bundler/cli/gem.rb +88 -9
  10. data/lib/bundler/cli/info.rb +16 -4
  11. data/lib/bundler/cli/install.rb +2 -3
  12. data/lib/bundler/cli/issue.rb +4 -3
  13. data/lib/bundler/cli/remove.rb +1 -2
  14. data/lib/bundler/cli/update.rb +2 -2
  15. data/lib/bundler/cli.rb +10 -1
  16. data/lib/bundler/compact_index_client/updater.rb +0 -5
  17. data/lib/bundler/compact_index_client.rb +2 -2
  18. data/lib/bundler/definition.rb +77 -124
  19. data/lib/bundler/dependency.rb +5 -7
  20. data/lib/bundler/digest.rb +71 -0
  21. data/lib/bundler/dsl.rb +18 -30
  22. data/lib/bundler/endpoint_specification.rb +0 -8
  23. data/lib/bundler/environment_preserver.rb +4 -1
  24. data/lib/bundler/errors.rb +18 -2
  25. data/lib/bundler/fetcher/compact_index.rb +9 -4
  26. data/lib/bundler/fetcher.rb +4 -6
  27. data/lib/bundler/friendly_errors.rb +5 -30
  28. data/lib/bundler/gem_helper.rb +6 -17
  29. data/lib/bundler/injector.rb +10 -1
  30. data/lib/bundler/installer/gem_installer.rb +1 -6
  31. data/lib/bundler/installer.rb +1 -5
  32. data/lib/bundler/lazy_specification.rb +17 -1
  33. data/lib/bundler/lockfile_parser.rb +10 -12
  34. data/lib/bundler/man/bundle-add.1 +10 -2
  35. data/lib/bundler/man/bundle-add.1.ronn +7 -1
  36. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  37. data/lib/bundler/man/bundle-cache.1 +1 -1
  38. data/lib/bundler/man/bundle-check.1 +1 -1
  39. data/lib/bundler/man/bundle-clean.1 +1 -1
  40. data/lib/bundler/man/bundle-config.1 +5 -5
  41. data/lib/bundler/man/bundle-config.1.ronn +5 -5
  42. data/lib/bundler/man/bundle-doctor.1 +1 -1
  43. data/lib/bundler/man/bundle-exec.1 +1 -1
  44. data/lib/bundler/man/bundle-gem.1 +14 -1
  45. data/lib/bundler/man/bundle-gem.1.ronn +16 -0
  46. data/lib/bundler/man/bundle-info.1 +1 -1
  47. data/lib/bundler/man/bundle-init.1 +1 -1
  48. data/lib/bundler/man/bundle-inject.1 +1 -1
  49. data/lib/bundler/man/bundle-install.1 +2 -2
  50. data/lib/bundler/man/bundle-install.1.ronn +2 -2
  51. data/lib/bundler/man/bundle-list.1 +1 -1
  52. data/lib/bundler/man/bundle-lock.1 +1 -1
  53. data/lib/bundler/man/bundle-open.1 +1 -1
  54. data/lib/bundler/man/bundle-outdated.1 +1 -1
  55. data/lib/bundler/man/bundle-platform.1 +1 -1
  56. data/lib/bundler/man/bundle-pristine.1 +1 -1
  57. data/lib/bundler/man/bundle-remove.1 +1 -1
  58. data/lib/bundler/man/bundle-show.1 +1 -1
  59. data/lib/bundler/man/bundle-update.1 +2 -2
  60. data/lib/bundler/man/bundle-update.1.ronn +2 -1
  61. data/lib/bundler/man/bundle-viz.1 +1 -1
  62. data/lib/bundler/man/bundle.1 +1 -1
  63. data/lib/bundler/man/gemfile.5 +28 -2
  64. data/lib/bundler/man/gemfile.5.ronn +9 -1
  65. data/lib/bundler/plugin/api/source.rb +1 -0
  66. data/lib/bundler/plugin/installer.rb +3 -1
  67. data/lib/bundler/plugin.rb +23 -6
  68. data/lib/bundler/process_lock.rb +1 -1
  69. data/lib/bundler/psyched_yaml.rb +1 -13
  70. data/lib/bundler/resolver.rb +34 -31
  71. data/lib/bundler/ruby_version.rb +1 -1
  72. data/lib/bundler/rubygems_ext.rb +6 -0
  73. data/lib/bundler/rubygems_gem_installer.rb +21 -5
  74. data/lib/bundler/rubygems_integration.rb +39 -57
  75. data/lib/bundler/runtime.rb +2 -2
  76. data/lib/bundler/self_manager.rb +94 -0
  77. data/lib/bundler/settings.rb +10 -1
  78. data/lib/bundler/shared_helpers.rb +4 -12
  79. data/lib/bundler/source/git/git_proxy.rb +7 -4
  80. data/lib/bundler/source/git.rb +22 -4
  81. data/lib/bundler/source/metadata.rb +1 -1
  82. data/lib/bundler/source/rubygems.rb +60 -85
  83. data/lib/bundler/source/rubygems_aggregate.rb +1 -1
  84. data/lib/bundler/source.rb +3 -1
  85. data/lib/bundler/source_list.rb +11 -29
  86. data/lib/bundler/spec_set.rb +2 -2
  87. data/lib/bundler/templates/Executable.bundler +1 -1
  88. data/lib/bundler/templates/Gemfile +0 -2
  89. data/lib/bundler/templates/gems.rb +0 -3
  90. data/lib/bundler/templates/newgem/Gemfile.tt +5 -2
  91. data/lib/bundler/templates/newgem/Rakefile.tt +15 -2
  92. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +4 -3
  93. data/lib/bundler/templates/newgem/newgem.gemspec.tt +14 -14
  94. data/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  95. data/lib/bundler/templates/newgem/standard.yml.tt +2 -0
  96. data/lib/bundler/templates/newgem/test/minitest/{newgem_test.rb.tt → test_newgem.rb.tt} +1 -1
  97. data/lib/bundler/ui/shell.rb +1 -1
  98. data/lib/bundler/vendor/.document +1 -0
  99. data/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  100. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +19 -21
  101. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  102. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +57 -0
  103. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +39 -74
  104. data/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  105. data/lib/bundler/vendor/molinillo/LICENSE +9 -0
  106. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +2 -2
  107. data/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  108. data/lib/bundler/vendor/thor/LICENSE.md +20 -0
  109. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +6 -6
  110. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +5 -3
  111. data/lib/bundler/vendor/thor/lib/thor/actions.rb +6 -2
  112. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +6 -0
  113. data/lib/bundler/vendor/thor/lib/thor/error.rb +9 -4
  114. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +19 -1
  115. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +22 -4
  116. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  117. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  118. data/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  119. data/lib/bundler/vendor/tsort/lib/tsort.rb +453 -0
  120. data/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  121. data/lib/bundler/vendor/uri/lib/uri/common.rb +17 -80
  122. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +0 -1
  123. data/lib/bundler/vendor/uri/lib/uri/generic.rb +5 -6
  124. data/lib/bundler/vendor/uri/lib/uri/http.rb +0 -1
  125. data/lib/bundler/vendor/uri/lib/uri/https.rb +0 -1
  126. data/lib/bundler/vendor/uri/lib/uri/ldap.rb +1 -1
  127. data/lib/bundler/vendor/uri/lib/uri/mailto.rb +0 -1
  128. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +1 -14
  129. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -12
  130. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  131. data/lib/bundler/vendor/uri/lib/uri/ws.rb +84 -0
  132. data/lib/bundler/vendor/uri/lib/uri/wss.rb +22 -0
  133. data/lib/bundler/vendor/uri/lib/uri.rb +0 -1
  134. data/lib/bundler/vendored_tsort.rb +4 -0
  135. data/lib/bundler/version.rb +1 -1
  136. data/lib/bundler/worker.rb +2 -2
  137. data/lib/bundler.rb +22 -21
  138. metadata +25 -9
  139. data/lib/bundler/gemdeps.rb +0 -29
  140. data/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb +0 -66
@@ -6,6 +6,11 @@ module Bundler
6
6
  class Definition
7
7
  include GemHelpers
8
8
 
9
+ class << self
10
+ # Do not create or modify a lockfile (Makes #lock a noop)
11
+ attr_accessor :no_lock
12
+ end
13
+
9
14
  attr_reader(
10
15
  :dependencies,
11
16
  :locked_deps,
@@ -73,7 +78,6 @@ module Bundler
73
78
  @lockfile_contents = String.new
74
79
  @locked_bundler_version = nil
75
80
  @locked_ruby_version = nil
76
- @locked_specs_incomplete_for_platform = false
77
81
  @new_platform = nil
78
82
 
79
83
  if lockfile && File.exist?(lockfile)
@@ -139,6 +143,8 @@ module Bundler
139
143
  @dependency_changes = converge_dependencies
140
144
  @local_changes = converge_locals
141
145
 
146
+ @locked_specs_incomplete_for_platform = !@locked_specs.for(requested_dependencies & expand_dependencies(locked_dependencies), true, true)
147
+
142
148
  @requires = compute_requires
143
149
  end
144
150
 
@@ -157,8 +163,10 @@ module Bundler
157
163
  end
158
164
  end
159
165
 
160
- def multisource_allowed?
161
- @multisource_allowed
166
+ def resolve_only_locally!
167
+ @remote = false
168
+ sources.local_only!
169
+ resolve
162
170
  end
163
171
 
164
172
  def resolve_with_cache!
@@ -222,17 +230,22 @@ module Bundler
222
230
  end
223
231
  end
224
232
 
233
+ def locked_dependencies
234
+ @locked_deps.values
235
+ end
236
+
225
237
  def specs_for(groups)
226
- groups = requested_groups if groups.empty?
238
+ return specs if groups.empty?
227
239
  deps = dependencies_for(groups)
228
- materialize(expand_dependencies(deps))
240
+ materialize(deps)
229
241
  end
230
242
 
231
243
  def dependencies_for(groups)
232
244
  groups.map!(&:to_sym)
233
- current_dependencies.reject do |d|
245
+ deps = current_dependencies.reject do |d|
234
246
  (d.groups & groups).empty?
235
247
  end
248
+ expand_dependencies(deps)
236
249
  end
237
250
 
238
251
  # Resolve all the dependencies specified in Gemfile. It ensures that
@@ -267,6 +280,8 @@ module Bundler
267
280
  end
268
281
 
269
282
  def lock(file, preserve_unknown_sections = false)
283
+ return if Definition.no_lock
284
+
270
285
  contents = to_lock
271
286
 
272
287
  # Convert to \r\n if the existing lock has them
@@ -277,10 +292,7 @@ module Bundler
277
292
  locked_major = @locked_bundler_version.segments.first
278
293
  current_major = Gem::Version.create(Bundler::VERSION).segments.first
279
294
 
280
- if updating_major = locked_major < current_major
281
- Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \
282
- "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}."
283
- end
295
+ updating_major = locked_major < current_major
284
296
  end
285
297
 
286
298
  preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
@@ -356,44 +368,31 @@ module Bundler
356
368
  added.concat new_platforms.map {|p| "* platform: #{p}" }
357
369
  deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
358
370
 
359
- gemfile_sources = sources.lock_sources
360
-
361
- new_sources = gemfile_sources - @locked_sources
362
- deleted_sources = @locked_sources - gemfile_sources
371
+ new_deps = @dependencies - locked_dependencies
372
+ deleted_deps = locked_dependencies - @dependencies
363
373
 
364
- new_deps = @dependencies - @locked_deps.values
365
- deleted_deps = @locked_deps.values - @dependencies
374
+ added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
375
+ deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any?
366
376
 
367
- # Check if it is possible that the source is only changed thing
368
- if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
369
- new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
370
- deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
371
- end
377
+ both_sources = Hash.new {|h, k| h[k] = [] }
378
+ @dependencies.each {|d| both_sources[d.name][0] = d }
372
379
 
373
- if @locked_sources != gemfile_sources
374
- if new_sources.any?
375
- added.concat new_sources.map {|source| "* source: #{source}" }
376
- end
380
+ locked_dependencies.each do |d|
381
+ next if !Bundler.feature_flag.bundler_3_mode? && @locked_specs[d.name].empty?
377
382
 
378
- if deleted_sources.any?
379
- deleted.concat deleted_sources.map {|source| "* source: #{source}" }
380
- end
383
+ both_sources[d.name][1] = d
381
384
  end
382
385
 
383
- added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
384
- if deleted_deps.any?
385
- deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" }
386
- end
386
+ both_sources.each do |name, (dep, lock_dep)|
387
+ next if dep.nil? || lock_dep.nil?
387
388
 
388
- both_sources = Hash.new {|h, k| h[k] = [] }
389
- @dependencies.each {|d| both_sources[d.name][0] = d }
390
- @locked_deps.each {|name, d| both_sources[name][1] = d.source }
389
+ gemfile_source = dep.source || sources.default_source
390
+ lock_source = lock_dep.source || sources.default_source
391
+ next if lock_source.include?(gemfile_source)
391
392
 
392
- both_sources.each do |name, (dep, lock_source)|
393
- next if lock_source.nil? || (dep && lock_source.can_lock?(dep))
394
- gemfile_source_name = (dep && dep.source) || "no specified source"
395
- lockfile_source_name = lock_source
396
- changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`"
393
+ gemfile_source_name = dep.source ? gemfile_source.identifier : "no specified source"
394
+ lockfile_source_name = lock_dep.source ? lock_source.identifier : "no specified source"
395
+ changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
397
396
  end
398
397
 
399
398
  reason = change_reason
@@ -554,7 +553,7 @@ module Bundler
554
553
 
555
554
  def dependencies_for_source_changed?(source, locked_source = source)
556
555
  deps_for_source = @dependencies.select {|s| s.source == source }
557
- locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }
556
+ locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source }
558
557
 
559
558
  deps_for_source.uniq.sort != locked_deps_for_source.sort
560
559
  end
@@ -637,25 +636,14 @@ module Bundler
637
636
  end
638
637
 
639
638
  def converge_dependencies
640
- frozen = Bundler.frozen_bundle?
641
- (@dependencies + @locked_deps.values).each do |dep|
642
- locked_source = @locked_deps[dep.name]
643
- # This is to make sure that if bundler is installing in deployment mode and
644
- # after locked_source and sources don't match, we still use locked_source.
645
- if frozen && !locked_source.nil? &&
646
- locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
647
- dep.source = locked_source.source
648
- elsif dep.source
639
+ changes = false
640
+
641
+ @dependencies.each do |dep|
642
+ if dep.source
649
643
  dep.source = sources.get(dep.source)
650
644
  end
651
- end
652
645
 
653
- changes = false
654
- # We want to know if all match, but don't want to check all entries
655
- # This means we need to return false if any dependency doesn't match
656
- # the lock or doesn't exist in the lock.
657
- @dependencies.each do |dependency|
658
- unless locked_dep = @locked_deps[dependency.name]
646
+ unless locked_dep = @locked_deps[dep.name]
659
647
  changes = true
660
648
  next
661
649
  end
@@ -666,11 +654,11 @@ module Bundler
666
654
  # directive, the lockfile dependencies and resolved dependencies end up
667
655
  # with a mismatch on #type. Work around that by setting the type on the
668
656
  # dep from the lockfile.
669
- locked_dep.instance_variable_set(:@type, dependency.type)
657
+ locked_dep.instance_variable_set(:@type, dep.type)
670
658
 
671
659
  # We already know the name matches from the hash lookup
672
660
  # so we only need to check the requirement now
673
- changes ||= dependency.requirement != locked_dep.requirement
661
+ changes ||= dep.requirement != locked_dep.requirement
674
662
  end
675
663
 
676
664
  changes
@@ -680,39 +668,36 @@ module Bundler
680
668
  # commonly happen if the Gemfile has changed since the lockfile was last
681
669
  # generated
682
670
  def converge_locked_specs
683
- deps = []
671
+ resolve = converge_specs(@locked_specs)
684
672
 
685
- # Build a list of dependencies that are the same in the Gemfile
686
- # and Gemfile.lock. If the Gemfile modified a dependency, but
687
- # the gem in the Gemfile.lock still satisfies it, this is fine
688
- # too.
689
- @dependencies.each do |dep|
690
- locked_dep = @locked_deps[dep.name]
691
-
692
- # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep
693
- locked_dep = nil unless locked_dep == dep
673
+ diff = nil
694
674
 
695
- if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
696
- deps << dep
697
- elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
698
- @locked_specs.each do |s|
699
- @unlock[:gems] << s.name if s.source == dep.source
700
- end
675
+ # Now, we unlock any sources that do not have anymore gems pinned to it
676
+ sources.all_sources.each do |source|
677
+ next unless source.respond_to?(:unlock!)
701
678
 
702
- dep.source.unlock! if dep.source.respond_to?(:unlock!)
703
- dep.source.specs.each {|s| @unlock[:gems] << s.name }
679
+ unless resolve.any? {|s| s.source == source }
680
+ diff ||= @locked_specs.to_a - resolve.to_a
681
+ source.unlock! if diff.any? {|s| s.source == source }
704
682
  end
705
683
  end
706
684
 
685
+ resolve
686
+ end
687
+
688
+ def converge_specs(specs)
689
+ deps = []
707
690
  converged = []
708
- @locked_specs.each do |s|
691
+ specs.each do |s|
709
692
  # Replace the locked dependency's source with the equivalent source from the Gemfile
710
693
  dep = @dependencies.find {|d| s.satisfies?(d) }
711
- s.source = (dep && dep.source) || sources.get(s.source) unless multisource_allowed?
712
694
 
713
- # Don't add a spec to the list if its source is expired. For example,
714
- # if you change a Git gem to RubyGems.
715
- next if s.source.nil?
695
+ if dep && (!dep.source || s.source.include?(dep.source))
696
+ deps << dep
697
+ end
698
+
699
+ s.source = (dep && dep.source) || sources.get(s.source) || sources.default_source unless Bundler.frozen_bundle?
700
+
716
701
  next if @unlock[:sources].include?(s.source.name)
717
702
 
718
703
  # If the spec is from a path source and it doesn't exist anymore
@@ -725,7 +710,7 @@ module Bundler
725
710
  rescue PathError, GitError
726
711
  # if we won't need the source (according to the lockfile),
727
712
  # don't error if the path/git source isn't available
728
- next if @locked_specs.
713
+ next if specs.
729
714
  for(requested_dependencies, false, true).
730
715
  none? {|locked_spec| locked_spec.source == s.source }
731
716
 
@@ -741,36 +726,15 @@ module Bundler
741
726
  s.dependencies.replace(new_spec.dependencies)
742
727
  end
743
728
 
744
- converged << s
745
- end
746
-
747
- resolve = SpecSet.new(converged)
748
- @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), true, true)
749
- resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false).reject{|s| @unlock[:gems].include?(s.name) })
750
- diff = nil
751
-
752
- # Now, we unlock any sources that do not have anymore gems pinned to it
753
- sources.all_sources.each do |source|
754
- next unless source.respond_to?(:unlock!)
755
-
756
- unless resolve.any? {|s| s.source == source }
757
- diff ||= @locked_specs.to_a - resolve.to_a
758
- source.unlock! if diff.any? {|s| s.source == source }
729
+ if dep.nil? && requested_dependencies.find {|d| s.name == d.name }
730
+ @unlock[:gems] << s.name
731
+ else
732
+ converged << s
759
733
  end
760
734
  end
761
735
 
762
- resolve
763
- end
764
-
765
- def in_locked_deps?(dep, locked_dep)
766
- # Because the lockfile can't link a dep to a specific remote, we need to
767
- # treat sources as equivalent anytime the locked dep has all the remotes
768
- # that the Gemfile dep does.
769
- locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source)
770
- end
771
-
772
- def satisfies_locked_spec?(dep)
773
- @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
736
+ resolve = SpecSet.new(converged)
737
+ SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false).reject{|s| @unlock[:gems].include?(s.name) })
774
738
  end
775
739
 
776
740
  def metadata_dependencies
@@ -863,22 +827,11 @@ module Bundler
863
827
 
864
828
  def additional_base_requirements_for_resolve
865
829
  return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources)
866
- dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) }
867
- @locked_gems.specs.reduce({}) do |requirements, locked_spec|
830
+ converge_specs(@locked_gems.specs).map do |locked_spec|
868
831
  name = locked_spec.name
869
- dependency = dependencies_by_name[name]
870
- next requirements if @locked_gems.dependencies[name] != dependency
871
- next requirements if dependency && dependency.source.is_a?(Source::Path)
872
832
  dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
873
- requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform)
874
- requirements
875
- end.values
876
- end
877
-
878
- def equivalent_rubygems_remotes?(source)
879
- return false unless source.is_a?(Source::Rubygems)
880
-
881
- Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
833
+ DepProxy.get_proxy(dep, locked_spec.platform)
834
+ end
882
835
  end
883
836
 
884
837
  def source_map
@@ -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, :git, :branch
10
+ attr_reader :groups, :platforms, :gemfile, :git, :github, :branch, :ref
11
11
 
12
12
  PLATFORM_MAP = {
13
13
  :ruby => Gem::Platform::RUBY,
@@ -82,7 +82,9 @@ module Bundler
82
82
  @groups = Array(options["group"] || :default).map(&:to_sym)
83
83
  @source = options["source"]
84
84
  @git = options["git"]
85
+ @github = options["github"]
85
86
  @branch = options["branch"]
87
+ @ref = options["ref"]
86
88
  @platforms = Array(options["platforms"])
87
89
  @env = options["env"]
88
90
  @should_include = options.fetch("should_include", true)
@@ -96,15 +98,11 @@ module Bundler
96
98
  def gem_platforms(valid_platforms)
97
99
  return valid_platforms if @platforms.empty?
98
100
 
99
- valid_generic_platforms = valid_platforms.map {|p| [p, GemHelpers.generic(p)] }.to_h
100
- @gem_platforms ||= expanded_platforms.compact.uniq
101
-
102
- filtered_generic_platforms = valid_generic_platforms.values & @gem_platforms
103
- valid_generic_platforms.select {|_, v| filtered_generic_platforms.include?(v) }.keys
101
+ valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) }
104
102
  end
105
103
 
106
104
  def expanded_platforms
107
- @platforms.map {|pl| PLATFORM_MAP[pl] }
105
+ @expanded_platforms ||= @platforms.map {|pl| PLATFORM_MAP[pl] }.compact.uniq
108
106
  end
109
107
 
110
108
  def should_include?
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This code was extracted from https://github.com/Solistra/ruby-digest which is under public domain
4
+ module Bundler
5
+ module Digest
6
+ # The initial constant values for the 32-bit constant words A, B, C, D, and
7
+ # E, respectively.
8
+ SHA1_WORDS = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0].freeze
9
+
10
+ # The 8-bit field used for bitwise `AND` masking. Defaults to `0xFFFFFFFF`.
11
+ SHA1_MASK = 0xFFFFFFFF
12
+
13
+ class << self
14
+ def sha1(string)
15
+ unless string.is_a?(String)
16
+ raise TypeError, "can't convert #{string.class.inspect} into String"
17
+ end
18
+
19
+ buffer = string.b
20
+
21
+ words = SHA1_WORDS.dup
22
+ generate_split_buffer(buffer) do |chunk|
23
+ w = []
24
+ chunk.each_slice(4) do |a, b, c, d|
25
+ w << (((a << 8 | b) << 8 | c) << 8 | d)
26
+ end
27
+ a, b, c, d, e = *words
28
+ (16..79).each do |i|
29
+ w[i] = SHA1_MASK & rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1)
30
+ end
31
+ 0.upto(79) do |i|
32
+ case i
33
+ when 0..19
34
+ f = ((b & c) | (~b & d))
35
+ k = 0x5A827999
36
+ when 20..39
37
+ f = (b ^ c ^ d)
38
+ k = 0x6ED9EBA1
39
+ when 40..59
40
+ f = ((b & c) | (b & d) | (c & d))
41
+ k = 0x8F1BBCDC
42
+ when 60..79
43
+ f = (b ^ c ^ d)
44
+ k = 0xCA62C1D6
45
+ end
46
+ t = SHA1_MASK & (SHA1_MASK & rotate(a, 5) + f + e + k + w[i])
47
+ a, b, c, d, e = t, a, SHA1_MASK & rotate(b, 30), c, d # rubocop:disable Style/ParallelAssignment
48
+ end
49
+ mutated = [a, b, c, d, e]
50
+ words.map!.with_index {|word, index| SHA1_MASK & (word + mutated[index]) }
51
+ end
52
+
53
+ words.pack("N*").unpack("H*").first
54
+ end
55
+
56
+ private
57
+
58
+ def generate_split_buffer(string, &block)
59
+ size = string.bytesize * 8
60
+ buffer = string.bytes << 128
61
+ buffer << 0 while buffer.size % 64 != 56
62
+ buffer.concat([size].pack("Q>").bytes)
63
+ buffer.each_slice(64, &block)
64
+ end
65
+
66
+ def rotate(value, spaces)
67
+ value << spaces | value >> (32 - spaces)
68
+ end
69
+ end
70
+ end
71
+ end
data/lib/bundler/dsl.rb CHANGED
@@ -18,6 +18,8 @@ module Bundler
18
18
  VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules
19
19
  platform platforms type source install_if gemfile].freeze
20
20
 
21
+ GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z}.freeze
22
+
21
23
  attr_reader :gemspecs
22
24
  attr_accessor :dependencies
23
25
 
@@ -275,26 +277,24 @@ module Bundler
275
277
 
276
278
  def add_git_sources
277
279
  git_source(:github) do |repo_name|
278
- warn_deprecated_git_source(:github, <<-'RUBY'.strip, 'Change any "reponame" :github sources to "username/reponame".')
279
- "https://github.com/#{repo_name}.git"
280
- RUBY
281
- repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
282
- "https://github.com/#{repo_name}.git"
280
+ if repo_name =~ GITHUB_PULL_REQUEST_URL
281
+ {
282
+ "git" => "https://github.com/#{$1}.git",
283
+ "branch" => "refs/pull/#{$2}/head",
284
+ "ref" => nil,
285
+ "tag" => nil,
286
+ }
287
+ else
288
+ repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
289
+ "https://github.com/#{repo_name}.git"
290
+ end
283
291
  end
284
292
 
285
293
  git_source(:gist) do |repo_name|
286
- warn_deprecated_git_source(:gist, '"https://gist.github.com/#{repo_name}.git"')
287
-
288
294
  "https://gist.github.com/#{repo_name}.git"
289
295
  end
290
296
 
291
297
  git_source(:bitbucket) do |repo_name|
292
- warn_deprecated_git_source(:bitbucket, <<-'RUBY'.strip)
293
- user_name, repo_name = repo_name.split("/")
294
- repo_name ||= user_name
295
- "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
296
- RUBY
297
-
298
298
  user_name, repo_name = repo_name.split("/")
299
299
  repo_name ||= user_name
300
300
  "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
@@ -365,7 +365,11 @@ repo_name ||= user_name
365
365
 
366
366
  git_name = (git_names & opts.keys).last
367
367
  if @git_sources[git_name]
368
- opts["git"] = @git_sources[git_name].call(opts[git_name])
368
+ git_opts = @git_sources[git_name].call(opts[git_name])
369
+ git_opts = { "git" => git_opts } if git_opts.is_a?(String)
370
+ opts.merge!(git_opts) do |key, _gemfile_value, _git_source_value|
371
+ raise GemfileError, %(The :#{key} option can't be used with `#{git_name}: #{opts[git_name].inspect}`)
372
+ end
369
373
  end
370
374
 
371
375
  %w[git path].each do |type|
@@ -475,22 +479,6 @@ repo_name ||= user_name
475
479
  end
476
480
  end
477
481
 
478
- def warn_deprecated_git_source(name, replacement, additional_message = nil)
479
- additional_message &&= " #{additional_message}"
480
- replacement = if replacement.count("\n").zero?
481
- "{|repo_name| #{replacement} }"
482
- else
483
- "do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end"
484
- end
485
-
486
- Bundler::SharedHelpers.major_deprecation 3, <<-EOS
487
- The :#{name} git source is deprecated, and will be removed in the future.#{additional_message} Add this code to the top of your Gemfile to ensure it continues to work:
488
-
489
- git_source(:#{name}) #{replacement}
490
-
491
- EOS
492
- end
493
-
494
482
  class DSLError < GemfileError
495
483
  # @return [String] the description that should be presented to the user.
496
484
  #
@@ -3,7 +3,6 @@
3
3
  module Bundler
4
4
  # used for Creating Specifications from the Gemcutter Endpoint
5
5
  class EndpointSpecification < Gem::Specification
6
- ILLFORMED_MESSAGE = 'Ill-formed requirement ["#<YAML::Syck::DefaultKey'.freeze
7
6
  include MatchPlatform
8
7
 
9
8
  attr_reader :name, :version, :platform, :required_rubygems_version, :required_ruby_version, :checksum
@@ -129,13 +128,6 @@ module Bundler
129
128
 
130
129
  def build_dependency(name, requirements)
131
130
  Gem::Dependency.new(name, requirements)
132
- rescue ArgumentError => e
133
- raise unless e.message.include?(ILLFORMED_MESSAGE)
134
- puts # we shouldn't print the error message on the "fetching info" status line
135
- raise GemspecError,
136
- "Unfortunately, the gem #{name} (#{version}) has an invalid " \
137
- "gemspec.\nPlease ask the gem author to yank the bad version to fix " \
138
- "this issue. For more information, see http://bit.ly/syck-defaultkey."
139
131
  end
140
132
  end
141
133
  end
@@ -38,7 +38,10 @@ module Bundler
38
38
 
39
39
  # Replaces `ENV` with the bundler environment variables backed up
40
40
  def replace_with_backup
41
- ENV.replace(backup) unless Gem.win_platform?
41
+ unless Gem.win_platform?
42
+ ENV.replace(backup)
43
+ return
44
+ end
42
45
 
43
46
  # Fallback logic for Windows below to workaround
44
47
  # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all
@@ -75,10 +75,26 @@ module Bundler
75
75
  end
76
76
  end
77
77
 
78
+ def permission_type
79
+ case @permission_type
80
+ when :create
81
+ "executable permissions for all parent directories and write permissions for `#{parent_folder}`"
82
+ when :delete
83
+ permissions = "executable permissions for all parent directories and write permissions for `#{parent_folder}`"
84
+ permissions += ", and the same thing for all subdirectories inside #{@path}" if File.directory?(@path)
85
+ permissions
86
+ else
87
+ "#{@permission_type} permissions for that path"
88
+ end
89
+ end
90
+
91
+ def parent_folder
92
+ File.dirname(@path)
93
+ end
94
+
78
95
  def message
79
96
  "There was an error while trying to #{action} `#{@path}`. " \
80
- "It is likely that you need to grant #{@permission_type} permissions " \
81
- "for that path."
97
+ "It is likely that you need to grant #{permission_type}."
82
98
  end
83
99
 
84
100
  status_code(23)
@@ -68,11 +68,16 @@ module Bundler
68
68
  compact_index_request :fetch_spec
69
69
 
70
70
  def available?
71
- return nil unless SharedHelpers.md5_available?
72
- user_home = Bundler.user_home
73
- return nil unless user_home.directory? && user_home.writable?
71
+ unless SharedHelpers.md5_available?
72
+ Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API")
73
+ return nil
74
+ end
75
+ if fetch_uri.scheme == "file"
76
+ Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
77
+ return false
78
+ end
74
79
  # Read info file checksums out of /versions, so we can know if gems are up to date
75
- fetch_uri.scheme != "file" && compact_index_client.update_and_parse_checksums!
80
+ compact_index_client.update_and_parse_checksums!
76
81
  rescue CompactIndexClient::Updater::MisMatchedChecksumError => e
77
82
  Bundler.ui.debug(e.message)
78
83
  nil
@@ -28,7 +28,8 @@ module Bundler
28
28
  " is a chance you are experiencing a man-in-the-middle attack, but" \
29
29
  " most likely your system doesn't have the CA certificates needed" \
30
30
  " for verification. For information about OpenSSL certificates, see" \
31
- " http://bit.ly/ruby-ssl. To connect without using SSL, edit your Gemfile" \
31
+ " https://railsapps.github.io/openssl-certificate-verify-failed.html." \
32
+ " To connect without using SSL, edit your Gemfile" \
32
33
  " sources and change 'https' to 'http'."
33
34
  end
34
35
  end
@@ -70,8 +71,8 @@ module Bundler
70
71
  :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
71
72
  FAIL_ERRORS = begin
72
73
  fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError]
73
- fail_errors << Gem::Requirement::BadRequirementError if defined?(Gem::Requirement::BadRequirementError)
74
- fail_errors.concat(NET_ERRORS.map {|e| SharedHelpers.const_get_safely(e, Net) }.compact)
74
+ fail_errors << Gem::Requirement::BadRequirementError
75
+ fail_errors.concat(NET_ERRORS.map {|e| Net.const_get(e) })
75
76
  end.freeze
76
77
 
77
78
  class << self
@@ -121,7 +122,6 @@ module Bundler
121
122
 
122
123
  # return the specs in the bundler format as an index
123
124
  def specs(gem_names, source)
124
- old = Bundler.rubygems.sources
125
125
  index = Bundler::Index.new
126
126
 
127
127
  if Bundler::Fetcher.disable_endpoint
@@ -152,8 +152,6 @@ module Bundler
152
152
  rescue CertificateFailureError
153
153
  Bundler.ui.info "" if gem_names && use_api # newline after dots
154
154
  raise
155
- ensure
156
- Bundler.rubygems.sources = old
157
155
  end
158
156
 
159
157
  def use_api