bundler 2.2.24 → 2.3.7

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 (154) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +246 -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/cache.rb +1 -1
  8. data/lib/bundler/cli/config.rb +10 -1
  9. data/lib/bundler/cli/doctor.rb +13 -4
  10. data/lib/bundler/cli/exec.rb +1 -6
  11. data/lib/bundler/cli/gem.rb +101 -11
  12. data/lib/bundler/cli/info.rb +26 -5
  13. data/lib/bundler/cli/install.rb +12 -45
  14. data/lib/bundler/cli/issue.rb +4 -3
  15. data/lib/bundler/cli/list.rb +7 -1
  16. data/lib/bundler/cli/open.rb +1 -2
  17. data/lib/bundler/cli/platform.rb +1 -1
  18. data/lib/bundler/cli/remove.rb +1 -2
  19. data/lib/bundler/cli/update.rb +9 -5
  20. data/lib/bundler/cli.rb +24 -20
  21. data/lib/bundler/compact_index_client/cache.rb +0 -9
  22. data/lib/bundler/compact_index_client/updater.rb +0 -5
  23. data/lib/bundler/compact_index_client.rb +2 -8
  24. data/lib/bundler/definition.rb +97 -161
  25. data/lib/bundler/dependency.rb +5 -7
  26. data/lib/bundler/digest.rb +71 -0
  27. data/lib/bundler/dsl.rb +32 -31
  28. data/lib/bundler/endpoint_specification.rb +21 -11
  29. data/lib/bundler/env.rb +1 -1
  30. data/lib/bundler/environment_preserver.rb +4 -1
  31. data/lib/bundler/errors.rb +19 -3
  32. data/lib/bundler/fetcher/compact_index.rb +9 -14
  33. data/lib/bundler/fetcher/index.rb +0 -26
  34. data/lib/bundler/fetcher.rb +13 -20
  35. data/lib/bundler/friendly_errors.rb +5 -30
  36. data/lib/bundler/gem_helper.rb +7 -18
  37. data/lib/bundler/injector.rb +10 -1
  38. data/lib/bundler/installer/gem_installer.rb +4 -22
  39. data/lib/bundler/installer/standalone.rb +13 -8
  40. data/lib/bundler/installer.rb +1 -5
  41. data/lib/bundler/lazy_specification.rb +19 -3
  42. data/lib/bundler/lockfile_generator.rb +1 -1
  43. data/lib/bundler/lockfile_parser.rb +11 -12
  44. data/lib/bundler/man/bundle-add.1 +10 -2
  45. data/lib/bundler/man/bundle-add.1.ronn +7 -1
  46. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  47. data/lib/bundler/man/bundle-cache.1 +1 -1
  48. data/lib/bundler/man/bundle-check.1 +1 -1
  49. data/lib/bundler/man/bundle-clean.1 +1 -1
  50. data/lib/bundler/man/bundle-config.1 +5 -5
  51. data/lib/bundler/man/bundle-config.1.ronn +5 -5
  52. data/lib/bundler/man/bundle-doctor.1 +1 -1
  53. data/lib/bundler/man/bundle-exec.1 +1 -1
  54. data/lib/bundler/man/bundle-gem.1 +14 -1
  55. data/lib/bundler/man/bundle-gem.1.ronn +16 -0
  56. data/lib/bundler/man/bundle-info.1 +1 -1
  57. data/lib/bundler/man/bundle-init.1 +1 -1
  58. data/lib/bundler/man/bundle-inject.1 +1 -1
  59. data/lib/bundler/man/bundle-install.1 +2 -2
  60. data/lib/bundler/man/bundle-install.1.ronn +2 -2
  61. data/lib/bundler/man/bundle-list.1 +1 -1
  62. data/lib/bundler/man/bundle-lock.1 +1 -1
  63. data/lib/bundler/man/bundle-open.1 +1 -1
  64. data/lib/bundler/man/bundle-outdated.1 +1 -1
  65. data/lib/bundler/man/bundle-platform.1 +1 -1
  66. data/lib/bundler/man/bundle-pristine.1 +1 -1
  67. data/lib/bundler/man/bundle-remove.1 +1 -1
  68. data/lib/bundler/man/bundle-show.1 +1 -1
  69. data/lib/bundler/man/bundle-update.1 +2 -2
  70. data/lib/bundler/man/bundle-update.1.ronn +2 -1
  71. data/lib/bundler/man/bundle-viz.1 +1 -1
  72. data/lib/bundler/man/bundle.1 +1 -1
  73. data/lib/bundler/man/gemfile.5 +28 -2
  74. data/lib/bundler/man/gemfile.5.ronn +9 -1
  75. data/lib/bundler/plugin/api/source.rb +1 -0
  76. data/lib/bundler/plugin/installer.rb +3 -1
  77. data/lib/bundler/plugin.rb +23 -6
  78. data/lib/bundler/process_lock.rb +1 -1
  79. data/lib/bundler/remote_specification.rb +7 -0
  80. data/lib/bundler/resolver/spec_group.rb +1 -1
  81. data/lib/bundler/resolver.rb +38 -47
  82. data/lib/bundler/ruby_version.rb +1 -1
  83. data/lib/bundler/rubygems_ext.rb +19 -10
  84. data/lib/bundler/rubygems_gem_installer.rb +25 -5
  85. data/lib/bundler/rubygems_integration.rb +40 -70
  86. data/lib/bundler/runtime.rb +17 -8
  87. data/lib/bundler/self_manager.rb +168 -0
  88. data/lib/bundler/settings.rb +15 -2
  89. data/lib/bundler/setup.rb +2 -2
  90. data/lib/bundler/shared_helpers.rb +4 -19
  91. data/lib/bundler/source/git/git_proxy.rb +8 -6
  92. data/lib/bundler/source/git.rb +22 -4
  93. data/lib/bundler/source/metadata.rb +1 -1
  94. data/lib/bundler/source/rubygems.rb +70 -81
  95. data/lib/bundler/source/rubygems_aggregate.rb +4 -0
  96. data/lib/bundler/source.rb +4 -0
  97. data/lib/bundler/source_list.rb +22 -31
  98. data/lib/bundler/spec_set.rb +14 -36
  99. data/lib/bundler/templates/Executable.bundler +7 -7
  100. data/lib/bundler/templates/Gemfile +0 -2
  101. data/lib/bundler/templates/gems.rb +0 -3
  102. data/lib/bundler/templates/newgem/Gemfile.tt +5 -2
  103. data/lib/bundler/templates/newgem/Rakefile.tt +15 -2
  104. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +13 -2
  105. data/lib/bundler/templates/newgem/newgem.gemspec.tt +17 -15
  106. data/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  107. data/lib/bundler/templates/newgem/standard.yml.tt +3 -0
  108. data/lib/bundler/templates/newgem/test/minitest/{newgem_test.rb.tt → test_newgem.rb.tt} +1 -1
  109. data/lib/bundler/ui/shell.rb +1 -1
  110. data/lib/bundler/vendor/.document +1 -0
  111. data/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  112. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +19 -21
  113. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  114. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +57 -0
  115. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +39 -74
  116. data/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  117. data/lib/bundler/vendor/molinillo/LICENSE +9 -0
  118. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +2 -2
  119. data/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  120. data/lib/bundler/vendor/thor/LICENSE.md +20 -0
  121. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +6 -6
  122. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +1 -2
  123. data/lib/bundler/vendor/thor/lib/thor/actions.rb +6 -2
  124. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +6 -0
  125. data/lib/bundler/vendor/thor/lib/thor/error.rb +9 -4
  126. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +19 -1
  127. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +22 -4
  128. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  129. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  130. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  131. data/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  132. data/lib/bundler/vendor/tsort/lib/tsort.rb +453 -0
  133. data/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  134. data/lib/bundler/vendor/uri/lib/uri/common.rb +17 -80
  135. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +0 -1
  136. data/lib/bundler/vendor/uri/lib/uri/generic.rb +5 -6
  137. data/lib/bundler/vendor/uri/lib/uri/http.rb +0 -1
  138. data/lib/bundler/vendor/uri/lib/uri/https.rb +0 -1
  139. data/lib/bundler/vendor/uri/lib/uri/ldap.rb +1 -1
  140. data/lib/bundler/vendor/uri/lib/uri/mailto.rb +0 -1
  141. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +1 -14
  142. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -12
  143. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  144. data/lib/bundler/vendor/uri/lib/uri/ws.rb +84 -0
  145. data/lib/bundler/vendor/uri/lib/uri/wss.rb +22 -0
  146. data/lib/bundler/vendor/uri/lib/uri.rb +0 -1
  147. data/lib/bundler/vendored_tsort.rb +4 -0
  148. data/lib/bundler/version.rb +1 -1
  149. data/lib/bundler/worker.rb +19 -4
  150. data/lib/bundler.rb +23 -26
  151. metadata +25 -10
  152. data/lib/bundler/gemdeps.rb +0 -29
  153. data/lib/bundler/psyched_yaml.rb +0 -22
  154. 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)
@@ -133,12 +137,14 @@ module Bundler
133
137
  @unlock[:gems] ||= @dependencies.map(&:name)
134
138
  else
135
139
  eager_unlock = expand_dependencies(@unlock[:gems] || [], true)
136
- @unlock[:gems] = @locked_specs.for(eager_unlock, false, false, false).map(&:name)
140
+ @unlock[:gems] = @locked_specs.for(eager_unlock, false, false).map(&:name)
137
141
  end
138
142
 
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,10 +163,6 @@ module Bundler
157
163
  end
158
164
  end
159
165
 
160
- def multisource_allowed?
161
- @multisource_allowed
162
- end
163
-
164
166
  def resolve_only_locally!
165
167
  @remote = false
166
168
  sources.local_only!
@@ -185,15 +187,7 @@ module Bundler
185
187
  #
186
188
  # @return [Bundler::SpecSet]
187
189
  def specs
188
- @specs ||= add_bundler_to(resolve.materialize(requested_dependencies))
189
- rescue GemNotFound => e # Handle yanked gem
190
- gem_name, gem_version = extract_gem_info(e)
191
- locked_gem = @locked_specs[gem_name].last
192
- raise if locked_gem.nil? || locked_gem.version.to_s != gem_version || !@remote
193
- raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
194
- "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
195
- "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
196
- "removed in order to install."
190
+ @specs ||= materialize(requested_dependencies)
197
191
  end
198
192
 
199
193
  def new_specs
@@ -205,9 +199,7 @@ module Bundler
205
199
  end
206
200
 
207
201
  def missing_specs
208
- missing = []
209
- resolve.materialize(requested_dependencies, missing)
210
- missing
202
+ resolve.materialize(requested_dependencies).missing_specs
211
203
  end
212
204
 
213
205
  def missing_specs?
@@ -238,17 +230,22 @@ module Bundler
238
230
  end
239
231
  end
240
232
 
233
+ def locked_dependencies
234
+ @locked_deps.values
235
+ end
236
+
241
237
  def specs_for(groups)
242
- groups = requested_groups if groups.empty?
238
+ return specs if groups.empty?
243
239
  deps = dependencies_for(groups)
244
- add_bundler_to(resolve.materialize(expand_dependencies(deps)))
240
+ materialize(deps)
245
241
  end
246
242
 
247
243
  def dependencies_for(groups)
248
244
  groups.map!(&:to_sym)
249
- current_dependencies.reject do |d|
245
+ deps = current_dependencies.reject do |d|
250
246
  (d.groups & groups).empty?
251
247
  end
248
+ expand_dependencies(deps)
252
249
  end
253
250
 
254
251
  # Resolve all the dependencies specified in Gemfile. It ensures that
@@ -268,16 +265,12 @@ module Bundler
268
265
  else
269
266
  # Run a resolve against the locally available gems
270
267
  Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
271
- expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote)
268
+ expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, true)
272
269
  Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
273
270
  end
274
271
  end
275
272
  end
276
273
 
277
- def has_rubygems_remotes?
278
- sources.rubygems_sources.any? {|s| s.remotes.any? }
279
- end
280
-
281
274
  def spec_git_paths
282
275
  sources.git_sources.map {|s| File.realpath(s.path) if File.exist?(s.path) }.compact
283
276
  end
@@ -287,6 +280,8 @@ module Bundler
287
280
  end
288
281
 
289
282
  def lock(file, preserve_unknown_sections = false)
283
+ return if Definition.no_lock
284
+
290
285
  contents = to_lock
291
286
 
292
287
  # Convert to \r\n if the existing lock has them
@@ -297,10 +292,7 @@ module Bundler
297
292
  locked_major = @locked_bundler_version.segments.first
298
293
  current_major = Gem::Version.create(Bundler::VERSION).segments.first
299
294
 
300
- if updating_major = locked_major < current_major
301
- Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \
302
- "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}."
303
- end
295
+ updating_major = locked_major < current_major
304
296
  end
305
297
 
306
298
  preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
@@ -317,14 +309,6 @@ module Bundler
317
309
  end
318
310
  end
319
311
 
320
- def locked_bundler_version
321
- if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION)
322
- new_version = Bundler::VERSION
323
- end
324
-
325
- new_version || @locked_bundler_version || Bundler::VERSION
326
- end
327
-
328
312
  def locked_ruby_version
329
313
  return unless ruby_version
330
314
  if @unlock[:ruby] || !@locked_ruby_version
@@ -376,44 +360,31 @@ module Bundler
376
360
  added.concat new_platforms.map {|p| "* platform: #{p}" }
377
361
  deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
378
362
 
379
- gemfile_sources = sources.lock_sources
363
+ new_deps = @dependencies - locked_dependencies
364
+ deleted_deps = locked_dependencies - @dependencies
380
365
 
381
- new_sources = gemfile_sources - @locked_sources
382
- deleted_sources = @locked_sources - gemfile_sources
366
+ added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
367
+ deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any?
383
368
 
384
- new_deps = @dependencies - @locked_deps.values
385
- deleted_deps = @locked_deps.values - @dependencies
369
+ both_sources = Hash.new {|h, k| h[k] = [] }
370
+ @dependencies.each {|d| both_sources[d.name][0] = d }
386
371
 
387
- # Check if it is possible that the source is only changed thing
388
- if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
389
- new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
390
- deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
391
- end
372
+ locked_dependencies.each do |d|
373
+ next if !Bundler.feature_flag.bundler_3_mode? && @locked_specs[d.name].empty?
392
374
 
393
- if @locked_sources != gemfile_sources
394
- if new_sources.any?
395
- added.concat new_sources.map {|source| "* source: #{source}" }
396
- end
397
-
398
- if deleted_sources.any?
399
- deleted.concat deleted_sources.map {|source| "* source: #{source}" }
400
- end
375
+ both_sources[d.name][1] = d
401
376
  end
402
377
 
403
- added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
404
- if deleted_deps.any?
405
- deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" }
406
- end
378
+ both_sources.each do |name, (dep, lock_dep)|
379
+ next if dep.nil? || lock_dep.nil?
407
380
 
408
- both_sources = Hash.new {|h, k| h[k] = [] }
409
- @dependencies.each {|d| both_sources[d.name][0] = d }
410
- @locked_deps.each {|name, d| both_sources[name][1] = d.source }
381
+ gemfile_source = dep.source || sources.default_source
382
+ lock_source = lock_dep.source || sources.default_source
383
+ next if lock_source.include?(gemfile_source)
411
384
 
412
- both_sources.each do |name, (dep, lock_source)|
413
- next if lock_source.nil? || (dep && lock_source.can_lock?(dep))
414
- gemfile_source_name = (dep && dep.source) || "no specified source"
415
- lockfile_source_name = lock_source
416
- changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`"
385
+ gemfile_source_name = dep.source ? gemfile_source.identifier : "no specified source"
386
+ lockfile_source_name = lock_dep.source ? lock_source.identifier : "no specified source"
387
+ changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
417
388
  end
418
389
 
419
390
  reason = change_reason
@@ -493,7 +464,23 @@ module Bundler
493
464
 
494
465
  private
495
466
 
496
- def add_bundler_to(specs)
467
+ def materialize(dependencies)
468
+ specs = resolve.materialize(dependencies)
469
+ missing_specs = specs.missing_specs
470
+
471
+ if missing_specs.any?
472
+ missing_specs.each do |s|
473
+ locked_gem = @locked_specs[s.name].last
474
+ next if locked_gem.nil? || locked_gem.version != s.version || !@remote
475
+ raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
476
+ "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
477
+ "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
478
+ "removed in order to install."
479
+ end
480
+
481
+ raise GemNotFound, "Could not find #{missing_specs.map(&:full_name).join(", ")} in any of the sources"
482
+ end
483
+
497
484
  unless specs["bundler"].any?
498
485
  bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
499
486
  specs["bundler"] = bundler
@@ -503,11 +490,12 @@ module Bundler
503
490
  end
504
491
 
505
492
  def precompute_source_requirements_for_indirect_dependencies?
506
- sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
493
+ @remote && sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
507
494
  end
508
495
 
509
496
  def current_ruby_platform_locked?
510
497
  return false unless generic_local_platform == Gem::Platform::RUBY
498
+ return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
511
499
 
512
500
  current_platform_locked?
513
501
  end
@@ -558,7 +546,7 @@ module Bundler
558
546
 
559
547
  def dependencies_for_source_changed?(source, locked_source = source)
560
548
  deps_for_source = @dependencies.select {|s| s.source == source }
561
- locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }
549
+ locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source }
562
550
 
563
551
  deps_for_source.uniq.sort != locked_deps_for_source.sort
564
552
  end
@@ -641,25 +629,14 @@ module Bundler
641
629
  end
642
630
 
643
631
  def converge_dependencies
644
- frozen = Bundler.frozen_bundle?
645
- (@dependencies + @locked_deps.values).each do |dep|
646
- locked_source = @locked_deps[dep.name]
647
- # This is to make sure that if bundler is installing in deployment mode and
648
- # after locked_source and sources don't match, we still use locked_source.
649
- if frozen && !locked_source.nil? &&
650
- locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
651
- dep.source = locked_source.source
652
- elsif dep.source
632
+ changes = false
633
+
634
+ @dependencies.each do |dep|
635
+ if dep.source
653
636
  dep.source = sources.get(dep.source)
654
637
  end
655
- end
656
638
 
657
- changes = false
658
- # We want to know if all match, but don't want to check all entries
659
- # This means we need to return false if any dependency doesn't match
660
- # the lock or doesn't exist in the lock.
661
- @dependencies.each do |dependency|
662
- unless locked_dep = @locked_deps[dependency.name]
639
+ unless locked_dep = @locked_deps[dep.name]
663
640
  changes = true
664
641
  next
665
642
  end
@@ -670,11 +647,11 @@ module Bundler
670
647
  # directive, the lockfile dependencies and resolved dependencies end up
671
648
  # with a mismatch on #type. Work around that by setting the type on the
672
649
  # dep from the lockfile.
673
- locked_dep.instance_variable_set(:@type, dependency.type)
650
+ locked_dep.instance_variable_set(:@type, dep.type)
674
651
 
675
652
  # We already know the name matches from the hash lookup
676
653
  # so we only need to check the requirement now
677
- changes ||= dependency.requirement != locked_dep.requirement
654
+ changes ||= dep.requirement != locked_dep.requirement
678
655
  end
679
656
 
680
657
  changes
@@ -684,39 +661,36 @@ module Bundler
684
661
  # commonly happen if the Gemfile has changed since the lockfile was last
685
662
  # generated
686
663
  def converge_locked_specs
687
- deps = []
688
-
689
- # Build a list of dependencies that are the same in the Gemfile
690
- # and Gemfile.lock. If the Gemfile modified a dependency, but
691
- # the gem in the Gemfile.lock still satisfies it, this is fine
692
- # too.
693
- @dependencies.each do |dep|
694
- locked_dep = @locked_deps[dep.name]
664
+ resolve = converge_specs(@locked_specs)
695
665
 
696
- # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep
697
- locked_dep = nil unless locked_dep == dep
666
+ diff = nil
698
667
 
699
- if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
700
- deps << dep
701
- elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
702
- @locked_specs.each do |s|
703
- @unlock[:gems] << s.name if s.source == dep.source
704
- end
668
+ # Now, we unlock any sources that do not have anymore gems pinned to it
669
+ sources.all_sources.each do |source|
670
+ next unless source.respond_to?(:unlock!)
705
671
 
706
- dep.source.unlock! if dep.source.respond_to?(:unlock!)
707
- dep.source.specs.each {|s| @unlock[:gems] << s.name }
672
+ unless resolve.any? {|s| s.source == source }
673
+ diff ||= @locked_specs.to_a - resolve.to_a
674
+ source.unlock! if diff.any? {|s| s.source == source }
708
675
  end
709
676
  end
710
677
 
678
+ resolve
679
+ end
680
+
681
+ def converge_specs(specs)
682
+ deps = []
711
683
  converged = []
712
- @locked_specs.each do |s|
684
+ specs.each do |s|
713
685
  # Replace the locked dependency's source with the equivalent source from the Gemfile
714
686
  dep = @dependencies.find {|d| s.satisfies?(d) }
715
- s.source = (dep && dep.source) || sources.get(s.source)
716
687
 
717
- # Don't add a spec to the list if its source is expired. For example,
718
- # if you change a Git gem to RubyGems.
719
- next if s.source.nil?
688
+ if dep && (!dep.source || s.source.include?(dep.source))
689
+ deps << dep
690
+ end
691
+
692
+ s.source = (dep && dep.source) || sources.get(s.source) || sources.default_source unless Bundler.frozen_bundle?
693
+
720
694
  next if @unlock[:sources].include?(s.source.name)
721
695
 
722
696
  # If the spec is from a path source and it doesn't exist anymore
@@ -729,8 +703,8 @@ module Bundler
729
703
  rescue PathError, GitError
730
704
  # if we won't need the source (according to the lockfile),
731
705
  # don't error if the path/git source isn't available
732
- next if @locked_specs.
733
- for(requested_dependencies, false, true, false).
706
+ next if specs.
707
+ for(requested_dependencies, false, true).
734
708
  none? {|locked_spec| locked_spec.source == s.source }
735
709
 
736
710
  raise
@@ -745,36 +719,15 @@ module Bundler
745
719
  s.dependencies.replace(new_spec.dependencies)
746
720
  end
747
721
 
748
- converged << s
749
- end
750
-
751
- resolve = SpecSet.new(converged)
752
- @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), true, true)
753
- resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false, false).reject{|s| @unlock[:gems].include?(s.name) })
754
- diff = nil
755
-
756
- # Now, we unlock any sources that do not have anymore gems pinned to it
757
- sources.all_sources.each do |source|
758
- next unless source.respond_to?(:unlock!)
759
-
760
- unless resolve.any? {|s| s.source == source }
761
- diff ||= @locked_specs.to_a - resolve.to_a
762
- source.unlock! if diff.any? {|s| s.source == source }
722
+ if dep.nil? && requested_dependencies.find {|d| s.name == d.name }
723
+ @unlock[:gems] << s.name
724
+ else
725
+ converged << s
763
726
  end
764
727
  end
765
728
 
766
- resolve
767
- end
768
-
769
- def in_locked_deps?(dep, locked_dep)
770
- # Because the lockfile can't link a dep to a specific remote, we need to
771
- # treat sources as equivalent anytime the locked dep has all the remotes
772
- # that the Gemfile dep does.
773
- locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source)
774
- end
775
-
776
- def satisfies_locked_spec?(dep)
777
- @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
729
+ resolve = SpecSet.new(converged)
730
+ SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false).reject{|s| @unlock[:gems].include?(s.name) })
778
731
  end
779
732
 
780
733
  def metadata_dependencies
@@ -854,12 +807,6 @@ module Bundler
854
807
  current == proposed
855
808
  end
856
809
 
857
- def extract_gem_info(error)
858
- # This method will extract the error message like "Could not find foo-1.2.3 in any of the sources"
859
- # to an array. The first element will be the gem name (e.g. foo), the second will be the version number.
860
- error.message.scan(/Could not find (\w+)-(\d+(?:\.\d+)+)/).flatten
861
- end
862
-
863
810
  def compute_requires
864
811
  dependencies.reduce({}) do |requires, dep|
865
812
  next requires unless dep.should_include?
@@ -873,22 +820,11 @@ module Bundler
873
820
 
874
821
  def additional_base_requirements_for_resolve
875
822
  return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources)
876
- dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) }
877
- @locked_gems.specs.reduce({}) do |requirements, locked_spec|
823
+ converge_specs(@locked_gems.specs).map do |locked_spec|
878
824
  name = locked_spec.name
879
- dependency = dependencies_by_name[name]
880
- next requirements if @locked_gems.dependencies[name] != dependency
881
- next requirements if dependency && dependency.source.is_a?(Source::Path)
882
825
  dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
883
- requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform)
884
- requirements
885
- end.values
886
- end
887
-
888
- def equivalent_rubygems_remotes?(source)
889
- return false unless source.is_a?(Source::Rubygems)
890
-
891
- Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
826
+ DepProxy.get_proxy(dep, locked_spec.platform)
827
+ end
892
828
  end
893
829
 
894
830
  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|
@@ -447,8 +451,21 @@ repo_name ||= user_name
447
451
  end
448
452
 
449
453
  def check_rubygems_source_safety
450
- return unless @sources.aggregate_global_source?
454
+ if @sources.implicit_global_source?
455
+ implicit_global_source_warning
456
+ elsif @sources.aggregate_global_source?
457
+ multiple_global_source_warning
458
+ end
459
+ end
451
460
 
461
+ def implicit_global_source_warning
462
+ Bundler::SharedHelpers.major_deprecation 2, "This Gemfile does not include an explicit global source. " \
463
+ "Not using an explicit global source may result in a different lockfile being generated depending on " \
464
+ "the gems you have installed locally before bundler is run. " \
465
+ "Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\"."
466
+ end
467
+
468
+ def multiple_global_source_warning
452
469
  if Bundler.feature_flag.bundler_3_mode?
453
470
  msg = "This Gemfile contains multiple primary sources. " \
454
471
  "Each source after the first must include a block to indicate which gems " \
@@ -462,22 +479,6 @@ repo_name ||= user_name
462
479
  end
463
480
  end
464
481
 
465
- def warn_deprecated_git_source(name, replacement, additional_message = nil)
466
- additional_message &&= " #{additional_message}"
467
- replacement = if replacement.count("\n").zero?
468
- "{|repo_name| #{replacement} }"
469
- else
470
- "do |repo_name|\n#{replacement.to_s.gsub(/^/, " ")}\n end"
471
- end
472
-
473
- Bundler::SharedHelpers.major_deprecation 3, <<-EOS
474
- 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:
475
-
476
- git_source(:#{name}) #{replacement}
477
-
478
- EOS
479
- end
480
-
481
482
  class DSLError < GemfileError
482
483
  # @return [String] the description that should be presented to the user.
483
484
  #