bundler 2.5.5 → 2.5.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +171 -0
  3. data/lib/bundler/build_metadata.rb +2 -2
  4. data/lib/bundler/cli/binstubs.rb +1 -1
  5. data/lib/bundler/cli/fund.rb +1 -1
  6. data/lib/bundler/cli/gem.rb +8 -15
  7. data/lib/bundler/cli/install.rb +1 -1
  8. data/lib/bundler/cli/lock.rb +5 -4
  9. data/lib/bundler/cli/plugin.rb +3 -2
  10. data/lib/bundler/cli.rb +14 -31
  11. data/lib/bundler/compact_index_client/cache.rb +47 -72
  12. data/lib/bundler/compact_index_client/parser.rb +84 -0
  13. data/lib/bundler/compact_index_client.rb +51 -80
  14. data/lib/bundler/constants.rb +8 -1
  15. data/lib/bundler/definition.rb +168 -99
  16. data/lib/bundler/dependency.rb +2 -1
  17. data/lib/bundler/dsl.rb +16 -1
  18. data/lib/bundler/endpoint_specification.rb +11 -0
  19. data/lib/bundler/env.rb +1 -1
  20. data/lib/bundler/environment_preserver.rb +5 -23
  21. data/lib/bundler/errors.rb +14 -0
  22. data/lib/bundler/fetcher/compact_index.rb +15 -24
  23. data/lib/bundler/fetcher/downloader.rb +1 -1
  24. data/lib/bundler/fetcher.rb +2 -2
  25. data/lib/bundler/gem_helper.rb +1 -1
  26. data/lib/bundler/gem_helpers.rb +14 -7
  27. data/lib/bundler/gem_version_promoter.rb +42 -38
  28. data/lib/bundler/injector.rb +4 -6
  29. data/lib/bundler/installer/gem_installer.rb +0 -1
  30. data/lib/bundler/installer/standalone.rb +0 -3
  31. data/lib/bundler/installer.rb +11 -13
  32. data/lib/bundler/lazy_specification.rb +1 -0
  33. data/lib/bundler/man/bundle-add.1 +1 -1
  34. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  35. data/lib/bundler/man/bundle-cache.1 +1 -1
  36. data/lib/bundler/man/bundle-check.1 +3 -1
  37. data/lib/bundler/man/bundle-check.1.ronn +3 -0
  38. data/lib/bundler/man/bundle-clean.1 +1 -1
  39. data/lib/bundler/man/bundle-config.1 +2 -4
  40. data/lib/bundler/man/bundle-config.1.ronn +1 -4
  41. data/lib/bundler/man/bundle-console.1 +1 -1
  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 +7 -1
  45. data/lib/bundler/man/bundle-gem.1.ronn +11 -0
  46. data/lib/bundler/man/bundle-help.1 +1 -1
  47. data/lib/bundler/man/bundle-info.1 +1 -1
  48. data/lib/bundler/man/bundle-init.1 +1 -1
  49. data/lib/bundler/man/bundle-inject.1 +1 -1
  50. data/lib/bundler/man/bundle-install.1 +3 -3
  51. data/lib/bundler/man/bundle-install.1.ronn +2 -2
  52. data/lib/bundler/man/bundle-list.1 +1 -1
  53. data/lib/bundler/man/bundle-lock.1 +1 -1
  54. data/lib/bundler/man/bundle-open.1 +1 -1
  55. data/lib/bundler/man/bundle-outdated.1 +1 -1
  56. data/lib/bundler/man/bundle-platform.1 +1 -1
  57. data/lib/bundler/man/bundle-plugin.1 +7 -4
  58. data/lib/bundler/man/bundle-plugin.1.ronn +7 -3
  59. data/lib/bundler/man/bundle-pristine.1 +1 -1
  60. data/lib/bundler/man/bundle-remove.1 +1 -1
  61. data/lib/bundler/man/bundle-show.1 +1 -1
  62. data/lib/bundler/man/bundle-update.1 +1 -1
  63. data/lib/bundler/man/bundle-version.1 +1 -1
  64. data/lib/bundler/man/bundle-viz.1 +1 -1
  65. data/lib/bundler/man/bundle.1 +1 -1
  66. data/lib/bundler/man/gemfile.5 +3 -3
  67. data/lib/bundler/man/gemfile.5.ronn +2 -2
  68. data/lib/bundler/mirror.rb +3 -3
  69. data/lib/bundler/plugin/api/source.rb +2 -2
  70. data/lib/bundler/plugin/installer/path.rb +18 -0
  71. data/lib/bundler/plugin/installer.rb +36 -16
  72. data/lib/bundler/plugin/source_list.rb +4 -4
  73. data/lib/bundler/resolver/base.rb +4 -0
  74. data/lib/bundler/resolver/candidate.rb +5 -17
  75. data/lib/bundler/resolver/package.rb +4 -0
  76. data/lib/bundler/resolver/spec_group.rb +20 -2
  77. data/lib/bundler/resolver.rb +72 -33
  78. data/lib/bundler/rubygems_ext.rb +98 -10
  79. data/lib/bundler/rubygems_gem_installer.rb +35 -2
  80. data/lib/bundler/rubygems_integration.rb +16 -2
  81. data/lib/bundler/runtime.rb +2 -2
  82. data/lib/bundler/self_manager.rb +22 -2
  83. data/lib/bundler/settings.rb +26 -20
  84. data/lib/bundler/setup.rb +6 -0
  85. data/lib/bundler/shared_helpers.rb +6 -4
  86. data/lib/bundler/source/git/git_proxy.rb +9 -1
  87. data/lib/bundler/source/git.rb +15 -1
  88. data/lib/bundler/source/metadata.rb +2 -0
  89. data/lib/bundler/source/path.rb +0 -13
  90. data/lib/bundler/source/rubygems/remote.rb +1 -1
  91. data/lib/bundler/source/rubygems.rb +33 -32
  92. data/lib/bundler/source_list.rb +26 -2
  93. data/lib/bundler/spec_set.rb +15 -13
  94. data/lib/bundler/stub_specification.rb +8 -0
  95. data/lib/bundler/templates/newgem/CODE_OF_CONDUCT.md.tt +77 -29
  96. data/lib/bundler/templates/newgem/newgem.gemspec.tt +4 -3
  97. data/lib/bundler/templates/newgem/rubocop.yml.tt +0 -5
  98. data/lib/bundler/uri_credentials_filter.rb +2 -2
  99. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +22 -22
  100. data/lib/bundler/vendor/pub_grub/lib/pub_grub/static_package_source.rb +1 -0
  101. data/lib/bundler/vendored_net_http.rb +20 -5
  102. data/lib/bundler/vendored_timeout.rb +7 -3
  103. data/lib/bundler/vendored_uri.rb +18 -1
  104. data/lib/bundler/version.rb +1 -1
  105. data/lib/bundler/yaml_serializer.rb +11 -6
  106. data/lib/bundler.rb +29 -3
  107. metadata +5 -3
@@ -69,7 +69,6 @@ module Bundler
69
69
  @sources = sources
70
70
  @unlock = unlock
71
71
  @optional_groups = optional_groups
72
- @remote = false
73
72
  @prefer_local = false
74
73
  @specs = nil
75
74
  @ruby_version = ruby_version
@@ -82,7 +81,7 @@ module Bundler
82
81
  @resolved_bundler_version = nil
83
82
 
84
83
  @locked_ruby_version = nil
85
- @new_platform = nil
84
+ @new_platforms = []
86
85
  @removed_platform = nil
87
86
 
88
87
  if lockfile_exists?
@@ -92,11 +91,12 @@ module Bundler
92
91
  @platforms = @locked_platforms.dup
93
92
  @locked_bundler_version = @locked_gems.bundler_version
94
93
  @locked_ruby_version = @locked_gems.ruby_version
94
+ @originally_locked_deps = @locked_gems.dependencies
95
95
  @originally_locked_specs = SpecSet.new(@locked_gems.specs)
96
96
  @locked_checksums = @locked_gems.checksums
97
97
 
98
98
  if unlock != true
99
- @locked_deps = @locked_gems.dependencies
99
+ @locked_deps = @originally_locked_deps
100
100
  @locked_specs = @originally_locked_specs
101
101
  @locked_sources = @locked_gems.sources
102
102
  else
@@ -111,6 +111,7 @@ module Bundler
111
111
  @locked_gems = nil
112
112
  @locked_deps = {}
113
113
  @locked_specs = SpecSet.new([])
114
+ @originally_locked_deps = {}
114
115
  @originally_locked_specs = @locked_specs
115
116
  @locked_sources = []
116
117
  @locked_platforms = []
@@ -130,7 +131,7 @@ module Bundler
130
131
  @sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
131
132
  end
132
133
 
133
- @unlock[:sources] ||= []
134
+ @sources_to_unlock = @unlock.delete(:sources) || []
134
135
  @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
135
136
  @ruby_version.diff(locked_ruby_version_object)
136
137
  end
@@ -142,11 +143,13 @@ module Bundler
142
143
  @path_changes = converge_paths
143
144
  @source_changes = converge_sources
144
145
 
146
+ @explicit_unlocks = @unlock.delete(:gems) || []
147
+
145
148
  if @unlock[:conservative]
146
- @unlock[:gems] ||= @dependencies.map(&:name)
149
+ @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
147
150
  else
148
- eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") }
149
- @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
151
+ eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
152
+ @gems_to_unlock = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
150
153
  end
151
154
 
152
155
  @dependency_changes = converge_dependencies
@@ -160,37 +163,24 @@ module Bundler
160
163
  end
161
164
 
162
165
  def resolve_only_locally!
163
- @remote = false
164
166
  sources.local_only!
165
167
  resolve
166
168
  end
167
169
 
168
170
  def resolve_with_cache!
171
+ sources.local!
169
172
  sources.cached!
170
173
  resolve
171
174
  end
172
175
 
173
176
  def resolve_remotely!
174
- @remote = true
177
+ sources.cached!
175
178
  sources.remote!
176
179
  resolve
177
180
  end
178
181
 
179
- def resolution_mode=(options)
180
- if options["local"]
181
- @remote = false
182
- else
183
- @remote = true
184
- @prefer_local = options["prefer-local"]
185
- end
186
- end
187
-
188
- def setup_sources_for_resolve
189
- if @remote == false
190
- sources.cached!
191
- else
192
- sources.remote!
193
- end
182
+ def prefer_local!
183
+ @prefer_local = true
194
184
  end
195
185
 
196
186
  # For given dependency list returns a SpecSet with Gemspec of all the required
@@ -225,7 +215,6 @@ module Bundler
225
215
  @resolver = nil
226
216
  @resolution_packages = nil
227
217
  @specs = nil
228
- @gem_version_promoter = nil
229
218
 
230
219
  Bundler.ui.debug "The definition is missing dependencies, failed to resolve & materialize locally (#{e})"
231
220
  true
@@ -307,7 +296,12 @@ module Bundler
307
296
  end
308
297
  end
309
298
  else
310
- Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
299
+ if lockfile_exists?
300
+ Bundler.ui.debug "Found changes from the lockfile, re-resolving dependencies because #{change_reason}"
301
+ else
302
+ Bundler.ui.debug "Resolving dependencies because there's no lockfile"
303
+ end
304
+
311
305
  start_resolution
312
306
  end
313
307
  end
@@ -320,38 +314,26 @@ module Bundler
320
314
  dependencies.map(&:groups).flatten.uniq
321
315
  end
322
316
 
323
- def lock(file, preserve_unknown_sections = false)
324
- return if Definition.no_lock
325
-
326
- contents = to_lock
327
-
328
- # Convert to \r\n if the existing lock has them
329
- # i.e., Windows with `git config core.autocrlf=true`
330
- contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n")
331
-
332
- if @locked_bundler_version
333
- locked_major = @locked_bundler_version.segments.first
334
- current_major = bundler_version_to_lock.segments.first
335
-
336
- updating_major = locked_major < current_major
337
- end
317
+ def lock(file_or_preserve_unknown_sections = false, preserve_unknown_sections_or_unused = false)
318
+ if [true, false, nil].include?(file_or_preserve_unknown_sections)
319
+ target_lockfile = lockfile || Bundler.default_lockfile
320
+ preserve_unknown_sections = file_or_preserve_unknown_sections
321
+ else
322
+ target_lockfile = file_or_preserve_unknown_sections
323
+ preserve_unknown_sections = preserve_unknown_sections_or_unused
338
324
 
339
- preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
325
+ suggestion = if target_lockfile == lockfile
326
+ "To fix this warning, remove it from the `Definition#lock` call."
327
+ else
328
+ "Instead, instantiate a new definition passing `#{target_lockfile}`, and call `lock` without a file argument on that definition"
329
+ end
340
330
 
341
- if file && File.exist?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
342
- return if Bundler.frozen_bundle?
343
- SharedHelpers.filesystem_access(file) { FileUtils.touch(file) }
344
- return
345
- end
331
+ msg = "`Definition#lock` was passed a target file argument. #{suggestion}"
346
332
 
347
- if Bundler.frozen_bundle?
348
- Bundler.ui.error "Cannot write a changed lockfile while frozen."
349
- return
333
+ Bundler::SharedHelpers.major_deprecation 2, msg
350
334
  end
351
335
 
352
- SharedHelpers.filesystem_access(file) do |p|
353
- File.open(p, "wb") {|f| f.puts(contents) }
354
- end
336
+ write_lock(target_lockfile, preserve_unknown_sections)
355
337
  end
356
338
 
357
339
  def locked_ruby_version
@@ -385,6 +367,10 @@ module Bundler
385
367
  end
386
368
 
387
369
  def ensure_equivalent_gemfile_and_lockfile(explicit_flag = false)
370
+ return unless Bundler.frozen_bundle?
371
+
372
+ raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists?
373
+
388
374
  added = []
389
375
  deleted = []
390
376
  changed = []
@@ -413,7 +399,7 @@ module Bundler
413
399
  changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
414
400
  end
415
401
 
416
- reason = change_reason
402
+ reason = nothing_changed? ? "some dependencies were deleted from your gemfile" : change_reason
417
403
  msg = String.new
418
404
  msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set"
419
405
  msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
@@ -471,8 +457,10 @@ module Bundler
471
457
  end
472
458
 
473
459
  def add_platform(platform)
474
- @new_platform ||= !@platforms.include?(platform)
475
- @platforms |= [platform]
460
+ return if @platforms.include?(platform)
461
+
462
+ @new_platforms << platform
463
+ @platforms << platform
476
464
  end
477
465
 
478
466
  def remove_platform(platform)
@@ -492,9 +480,11 @@ module Bundler
492
480
  private :sources
493
481
 
494
482
  def nothing_changed?
483
+ return false unless lockfile_exists?
484
+
495
485
  !@source_changes &&
496
486
  !@dependency_changes &&
497
- !@new_platform &&
487
+ @new_platforms.empty? &&
498
488
  !@path_changes &&
499
489
  !@local_changes &&
500
490
  !@missing_lockfile_dep &&
@@ -518,7 +508,45 @@ module Bundler
518
508
  end
519
509
 
520
510
  def lockfile_exists?
521
- lockfile && File.exist?(lockfile)
511
+ file_exists?(lockfile)
512
+ end
513
+
514
+ def file_exists?(file)
515
+ file && File.exist?(file)
516
+ end
517
+
518
+ def write_lock(file, preserve_unknown_sections)
519
+ return if Definition.no_lock
520
+
521
+ contents = to_lock
522
+
523
+ # Convert to \r\n if the existing lock has them
524
+ # i.e., Windows with `git config core.autocrlf=true`
525
+ contents.gsub!(/\n/, "\r\n") if @lockfile_contents.match?("\r\n")
526
+
527
+ if @locked_bundler_version
528
+ locked_major = @locked_bundler_version.segments.first
529
+ current_major = bundler_version_to_lock.segments.first
530
+
531
+ updating_major = locked_major < current_major
532
+ end
533
+
534
+ preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
535
+
536
+ if file_exists?(file) && lockfiles_equal?(@lockfile_contents, contents, preserve_unknown_sections)
537
+ return if Bundler.frozen_bundle?
538
+ SharedHelpers.filesystem_access(file) { FileUtils.touch(file) }
539
+ return
540
+ end
541
+
542
+ if Bundler.frozen_bundle?
543
+ Bundler.ui.error "Cannot write a changed lockfile while frozen."
544
+ return
545
+ end
546
+
547
+ SharedHelpers.filesystem_access(file) do |p|
548
+ File.open(p, "wb") {|f| f.puts(contents) }
549
+ end
522
550
  end
523
551
 
524
552
  def resolver
@@ -539,9 +567,11 @@ module Bundler
539
567
  def resolution_packages
540
568
  @resolution_packages ||= begin
541
569
  last_resolve = converge_locked_specs
542
- remove_invalid_platforms!(current_dependencies)
543
- packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlock[:gems], prerelease: gem_version_promoter.pre?)
544
- additional_base_requirements_for_resolve(packages, last_resolve)
570
+ remove_invalid_platforms!
571
+ packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @gems_to_unlock, prerelease: gem_version_promoter.pre?)
572
+ packages = additional_base_requirements_to_prevent_downgrades(packages, last_resolve)
573
+ packages = additional_base_requirements_to_force_updates(packages)
574
+ packages
545
575
  end
546
576
  end
547
577
 
@@ -556,7 +586,7 @@ module Bundler
556
586
  if missing_specs.any?
557
587
  missing_specs.each do |s|
558
588
  locked_gem = @locked_specs[s.name].last
559
- next if locked_gem.nil? || locked_gem.version != s.version || !@remote
589
+ next if locked_gem.nil? || locked_gem.version != s.version || sources.local_mode?
560
590
  raise GemNotFound, "Your bundle is locked to #{locked_gem} from #{locked_gem.source}, but that version can " \
561
591
  "no longer be found in that source. That means the author of #{locked_gem} has removed it. " \
562
592
  "You'll need to update your bundle to a version other than #{locked_gem} that hasn't been " \
@@ -575,7 +605,7 @@ module Bundler
575
605
  break if incomplete_specs.empty?
576
606
 
577
607
  Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
578
- setup_sources_for_resolve
608
+ sources.remote!
579
609
  resolution_packages.delete(incomplete_specs)
580
610
  @resolve = start_resolution
581
611
  specs = resolve.materialize(dependencies)
@@ -597,12 +627,22 @@ module Bundler
597
627
  end
598
628
 
599
629
  def start_resolution
630
+ local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
631
+ @platforms << local_platform if local_platform_needed_for_resolvability
632
+
600
633
  result = SpecSet.new(resolver.start)
601
634
 
602
635
  @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
603
- @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
604
636
 
605
- result.complete_platforms!(platforms)
637
+ if @most_specific_non_local_locked_ruby_platform
638
+ if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_ruby_platform)
639
+ @platforms.delete(@most_specific_non_local_locked_ruby_platform)
640
+ elsif local_platform_needed_for_resolvability
641
+ @platforms.delete(local_platform)
642
+ end
643
+ end
644
+
645
+ @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
606
646
 
607
647
  SpecSet.new(result.for(dependencies, false, @platforms))
608
648
  end
@@ -624,13 +664,6 @@ module Bundler
624
664
  end
625
665
  end
626
666
 
627
- def current_ruby_platform_locked?
628
- return false unless generic_local_platform_is_ruby?
629
- return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
630
-
631
- current_platform_locked?
632
- end
633
-
634
667
  def current_platform_locked?
635
668
  @platforms.any? do |bundle_platform|
636
669
  MatchPlatform.platforms_match?(bundle_platform, local_platform)
@@ -638,27 +671,41 @@ module Bundler
638
671
  end
639
672
 
640
673
  def add_current_platform
641
- return if current_ruby_platform_locked?
674
+ @most_specific_non_local_locked_ruby_platform = find_most_specific_non_local_locked_ruby_platform
675
+ return if @most_specific_non_local_locked_ruby_platform
642
676
 
643
677
  add_platform(local_platform)
644
678
  end
645
679
 
680
+ def find_most_specific_non_local_locked_ruby_platform
681
+ return unless generic_local_platform_is_ruby? && current_platform_locked?
682
+
683
+ most_specific_locked_ruby_platform = most_specific_locked_platform
684
+ return unless most_specific_locked_ruby_platform != local_platform
685
+
686
+ most_specific_locked_ruby_platform
687
+ end
688
+
646
689
  def change_reason
647
690
  if unlocking?
648
- unlock_reason = @unlock.reject {|_k, v| Array(v).empty? }.map do |k, v|
649
- if v == true
650
- k.to_s
651
- else
652
- v = Array(v)
653
- "#{k}: (#{v.join(", ")})"
654
- end
655
- end.join(", ")
691
+ unlock_targets = if @gems_to_unlock.any?
692
+ ["gems", @gems_to_unlock]
693
+ elsif @sources_to_unlock.any?
694
+ ["sources", @sources_to_unlock]
695
+ end
696
+
697
+ unlock_reason = if unlock_targets
698
+ "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
699
+ else
700
+ @unlock[:ruby] ? "ruby" : ""
701
+ end
702
+
656
703
  return "bundler is unlocking #{unlock_reason}"
657
704
  end
658
705
  [
659
706
  [@source_changes, "the list of sources changed"],
660
707
  [@dependency_changes, "the dependencies in your gemfile changed"],
661
- [@new_platform, "you added a new platform to your gemfile"],
708
+ [@new_platforms.any?, "you added a new platform to your gemfile"],
662
709
  [@path_changes, "the gemspecs for path gems changed"],
663
710
  [@local_changes, "the gemspecs for git local gems changed"],
664
711
  [@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
@@ -707,7 +754,7 @@ module Bundler
707
754
  spec = @dependencies.find {|s| s.name == k }
708
755
  source = spec&.source
709
756
  if source&.respond_to?(:local_override!)
710
- source.unlock! if @unlock[:gems].include?(spec.name)
757
+ source.unlock! if @gems_to_unlock.include?(spec.name)
711
758
  locals << [source, source.local_override!(v)]
712
759
  end
713
760
  end
@@ -715,7 +762,7 @@ module Bundler
715
762
  sources_with_changes = locals.select do |source, changed|
716
763
  changed || specs_changed?(source)
717
764
  end.map(&:first)
718
- !sources_with_changes.each {|source| @unlock[:sources] << source.name }.empty?
765
+ !sources_with_changes.each {|source| @sources_to_unlock << source.name }.empty?
719
766
  end
720
767
 
721
768
  def check_lockfile
@@ -792,7 +839,7 @@ module Bundler
792
839
  # gem), unlock it. For git sources, this means to unlock the revision, which
793
840
  # will cause the `ref` used to be the most recent for the branch (or master) if
794
841
  # an explicit `ref` is not used.
795
- if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
842
+ if source.respond_to?(:unlock!) && @sources_to_unlock.include?(source.name)
796
843
  source.unlock!
797
844
  changes = true
798
845
  end
@@ -809,9 +856,7 @@ module Bundler
809
856
  dep.source = sources.get(dep.source)
810
857
  end
811
858
 
812
- next if unlocking?
813
-
814
- unless locked_dep = @locked_deps[dep.name]
859
+ unless locked_dep = @originally_locked_deps[dep.name]
815
860
  changes = true
816
861
  next
817
862
  end
@@ -838,7 +883,7 @@ module Bundler
838
883
  def converge_locked_specs
839
884
  converged = converge_specs(@locked_specs)
840
885
 
841
- resolve = SpecSet.new(converged.reject {|s| @unlock[:gems].include?(s.name) })
886
+ resolve = SpecSet.new(converged.reject {|s| @gems_to_unlock.include?(s.name) })
842
887
 
843
888
  diff = nil
844
889
 
@@ -871,7 +916,7 @@ module Bundler
871
916
 
872
917
  @specs_that_changed_sources << s if gemfile_source != lockfile_source
873
918
  deps << dep if !dep.source || lockfile_source.include?(dep.source)
874
- @unlock[:gems] << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
919
+ @gems_to_unlock << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
875
920
 
876
921
  # Replace the locked dependency's source with the equivalent source from the Gemfile
877
922
  s.source = gemfile_source
@@ -880,7 +925,7 @@ module Bundler
880
925
  s.source = default_source unless sources.get(lockfile_source)
881
926
  end
882
927
 
883
- next if @unlock[:sources].include?(s.source.name)
928
+ next if @sources_to_unlock.include?(s.source.name)
884
929
 
885
930
  # Path sources have special logic
886
931
  if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
@@ -902,12 +947,12 @@ module Bundler
902
947
  else
903
948
  # If the spec is no longer in the path source, unlock it. This
904
949
  # commonly happens if the version changed in the gemspec
905
- @unlock[:gems] << name
950
+ @gems_to_unlock << name
906
951
  end
907
952
  end
908
953
 
909
954
  if dep.nil? && requested_dependencies.find {|d| name == d.name }
910
- @unlock[:gems] << s.name
955
+ @gems_to_unlock << s.name
911
956
  else
912
957
  converged << s
913
958
  end
@@ -934,7 +979,7 @@ module Bundler
934
979
  else
935
980
  { default: Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
936
981
  end
937
- source_requirements.merge!(source_map.locked_requirements) unless @remote
982
+ source_requirements.merge!(source_map.locked_requirements) if nothing_changed?
938
983
  metadata_dependencies.each do |dep|
939
984
  source_requirements[dep.name] = sources.metadata_source
940
985
  end
@@ -984,7 +1029,7 @@ module Bundler
984
1029
  current == proposed
985
1030
  end
986
1031
 
987
- def additional_base_requirements_for_resolve(resolution_packages, last_resolve)
1032
+ def additional_base_requirements_to_prevent_downgrades(resolution_packages, last_resolve)
988
1033
  return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
989
1034
  converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec|
990
1035
  next if locked_spec.source.is_a?(Source::Path)
@@ -993,21 +1038,45 @@ module Bundler
993
1038
  resolution_packages
994
1039
  end
995
1040
 
996
- def remove_invalid_platforms!(dependencies)
1041
+ def additional_base_requirements_to_force_updates(resolution_packages)
1042
+ return resolution_packages if @explicit_unlocks.empty?
1043
+ full_update = dup_for_full_unlock.resolve
1044
+ @explicit_unlocks.each do |name|
1045
+ version = full_update[name].first&.version
1046
+ resolution_packages.base_requirements[name] = Gem::Requirement.new("= #{version}") if version
1047
+ end
1048
+ resolution_packages
1049
+ end
1050
+
1051
+ def dup_for_full_unlock
1052
+ unlocked_definition = self.class.new(@lockfile, @dependencies, @sources, true, @ruby_version, @optional_groups, @gemfiles)
1053
+ unlocked_definition.gem_version_promoter.tap do |gvp|
1054
+ gvp.level = gem_version_promoter.level
1055
+ gvp.strict = gem_version_promoter.strict
1056
+ gvp.pre = gem_version_promoter.pre
1057
+ end
1058
+ unlocked_definition
1059
+ end
1060
+
1061
+ def remove_invalid_platforms!
997
1062
  return if Bundler.frozen_bundle?
998
1063
 
999
1064
  platforms.reverse_each do |platform|
1000
1065
  next if local_platform == platform ||
1001
- (@new_platform && platforms.last == platform) ||
1066
+ @new_platforms.include?(platform) ||
1002
1067
  @path_changes ||
1003
1068
  @dependency_changes ||
1004
- !@originally_locked_specs.incomplete_for_platform?(dependencies, platform)
1069
+ @locked_spec_with_invalid_deps ||
1070
+ !spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
1005
1071
 
1006
1072
  remove_platform(platform)
1007
- add_current_platform if platform == Gem::Platform::RUBY
1008
1073
  end
1009
1074
  end
1010
1075
 
1076
+ def spec_set_incomplete_for_platform?(spec_set, platform)
1077
+ spec_set.incomplete_for_platform?(current_dependencies, platform)
1078
+ end
1079
+
1011
1080
  def source_map
1012
1081
  @source_map ||= SourceMap.new(sources, dependencies, @locked_specs)
1013
1082
  end
@@ -7,7 +7,7 @@ require_relative "rubygems_ext"
7
7
  module Bundler
8
8
  class Dependency < Gem::Dependency
9
9
  attr_reader :autorequire
10
- attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref
10
+ attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref, :glob
11
11
 
12
12
  ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..34).to_a).freeze
13
13
  PLATFORM_MAP = {
@@ -39,6 +39,7 @@ module Bundler
39
39
  @github = options["github"]
40
40
  @branch = options["branch"]
41
41
  @ref = options["ref"]
42
+ @glob = options["glob"]
42
43
  @platforms = Array(options["platforms"])
43
44
  @env = options["env"]
44
45
  @should_include = options.fetch("should_include", true)
data/lib/bundler/dsl.rb CHANGED
@@ -19,6 +19,7 @@ module Bundler
19
19
  platform platforms type source install_if gemfile force_ruby_platform].freeze
20
20
 
21
21
  GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z}
22
+ GITLAB_MERGE_REQUEST_URL = %r{\Ahttps://gitlab\.com/([A-Za-z0-9_\-\./]+)/-/merge_requests/(\d+)\z}
22
23
 
23
24
  attr_reader :gemspecs, :gemfile
24
25
  attr_accessor :dependencies
@@ -46,7 +47,7 @@ module Bundler
46
47
  @gemfile = expanded_gemfile_path
47
48
  @gemfiles << expanded_gemfile_path
48
49
  contents ||= Bundler.read_file(@gemfile.to_s)
49
- instance_eval(contents, gemfile.to_s, 1)
50
+ instance_eval(contents, @gemfile.to_s, 1)
50
51
  rescue Exception => e # rubocop:disable Lint/RescueException
51
52
  message = "There was an error " \
52
53
  "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \
@@ -308,6 +309,20 @@ module Bundler
308
309
  repo_name ||= user_name
309
310
  "https://#{user_name}@bitbucket.org/#{user_name}/#{repo_name}.git"
310
311
  end
312
+
313
+ git_source(:gitlab) do |repo_name|
314
+ if repo_name =~ GITLAB_MERGE_REQUEST_URL
315
+ {
316
+ "git" => "https://gitlab.com/#{$1}.git",
317
+ "branch" => nil,
318
+ "ref" => "refs/merge-requests/#{$2}/head",
319
+ "tag" => nil,
320
+ }
321
+ else
322
+ repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
323
+ "https://gitlab.com/#{repo_name}.git"
324
+ end
325
+ end
311
326
  end
312
327
 
313
328
  def with_source(source)
@@ -92,6 +92,17 @@ module Bundler
92
92
  end
93
93
  end
94
94
 
95
+ # needed for `bundle fund`
96
+ def metadata
97
+ if @remote_specification
98
+ @remote_specification.metadata
99
+ elsif _local_specification
100
+ _local_specification.metadata
101
+ else
102
+ super
103
+ end
104
+ end
105
+
95
106
  def _local_specification
96
107
  return unless @loaded_from && File.exist?(local_specification_path)
97
108
  eval(File.read(local_specification_path), nil, local_specification_path).tap do |spec|
data/lib/bundler/env.rb CHANGED
@@ -120,7 +120,7 @@ module Bundler
120
120
  specs = Bundler.rubygems.find_name(name)
121
121
  out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
122
122
  end
123
- if (exe = caller.last.split(":").first)&.match? %r{(exe|bin)/bundler?\z}
123
+ if (exe = caller_locations.last.absolute_path)&.match? %r{(exe|bin)/bundler?\z}
124
124
  shebang = File.read(exe).lines.first
125
125
  shebang.sub!(/^#!\s*/, "")
126
126
  unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby")
@@ -19,14 +19,7 @@ module Bundler
19
19
  BUNDLER_PREFIX = "BUNDLER_ORIG_"
20
20
 
21
21
  def self.from_env
22
- new(env_to_hash(ENV), BUNDLER_KEYS)
23
- end
24
-
25
- def self.env_to_hash(env)
26
- to_hash = env.to_hash
27
- return to_hash unless Gem.win_platform?
28
-
29
- to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v }
22
+ new(ENV.to_hash, BUNDLER_KEYS)
30
23
  end
31
24
 
32
25
  # @param env [Hash]
@@ -39,18 +32,7 @@ module Bundler
39
32
 
40
33
  # Replaces `ENV` with the bundler environment variables backed up
41
34
  def replace_with_backup
42
- unless Gem.win_platform?
43
- ENV.replace(backup)
44
- return
45
- end
46
-
47
- # Fallback logic for Windows below to workaround
48
- # https://bugs.ruby-lang.org/issues/16798. Can be dropped once all
49
- # supported rubies include the fix for that.
50
-
51
- ENV.clear
52
-
53
- backup.each {|k, v| ENV[k] = v }
35
+ ENV.replace(backup)
54
36
  end
55
37
 
56
38
  # @return [Hash]
@@ -58,9 +40,9 @@ module Bundler
58
40
  env = @original.clone
59
41
  @keys.each do |key|
60
42
  value = env[key]
61
- if !value.nil? && !value.empty?
43
+ if !value.nil?
62
44
  env[@prefix + key] ||= value
63
- elsif value.nil?
45
+ else
64
46
  env[@prefix + key] ||= INTENTIONALLY_NIL
65
47
  end
66
48
  end
@@ -72,7 +54,7 @@ module Bundler
72
54
  env = @original.clone
73
55
  @keys.each do |key|
74
56
  value_original = env[@prefix + key]
75
- next if value_original.nil? || value_original.empty?
57
+ next if value_original.nil?
76
58
  if value_original == INTENTIONALLY_NIL
77
59
  env.delete(key)
78
60
  else