bundler 2.6.2 → 2.6.6

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +91 -0
  3. data/README.md +2 -2
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/checksum.rb +1 -1
  6. data/lib/bundler/cli/console.rb +8 -6
  7. data/lib/bundler/cli/doctor.rb +23 -19
  8. data/lib/bundler/cli/info.rb +4 -4
  9. data/lib/bundler/cli/inject.rb +2 -2
  10. data/lib/bundler/cli/issue.rb +1 -1
  11. data/lib/bundler/cli/lock.rb +2 -1
  12. data/lib/bundler/cli/outdated.rb +6 -4
  13. data/lib/bundler/cli/show.rb +1 -1
  14. data/lib/bundler/compact_index_client/updater.rb +2 -1
  15. data/lib/bundler/current_ruby.rb +23 -33
  16. data/lib/bundler/definition.rb +125 -112
  17. data/lib/bundler/dependency.rb +92 -47
  18. data/lib/bundler/dsl.rb +83 -78
  19. data/lib/bundler/endpoint_specification.rb +10 -3
  20. data/lib/bundler/errors.rb +22 -0
  21. data/lib/bundler/feature_flag.rb +2 -6
  22. data/lib/bundler/gem_helpers.rb +4 -10
  23. data/lib/bundler/gem_version_promoter.rb +0 -2
  24. data/lib/bundler/injector.rb +9 -9
  25. data/lib/bundler/installer.rb +16 -2
  26. data/lib/bundler/lazy_specification.rb +50 -45
  27. data/lib/bundler/man/bundle-add.1 +3 -3
  28. data/lib/bundler/man/bundle-binstubs.1 +3 -3
  29. data/lib/bundler/man/bundle-cache.1 +3 -3
  30. data/lib/bundler/man/bundle-check.1 +3 -3
  31. data/lib/bundler/man/bundle-clean.1 +3 -3
  32. data/lib/bundler/man/bundle-config.1 +8 -8
  33. data/lib/bundler/man/bundle-config.1.ronn +9 -4
  34. data/lib/bundler/man/bundle-console.1 +3 -3
  35. data/lib/bundler/man/bundle-doctor.1 +3 -3
  36. data/lib/bundler/man/bundle-env.1 +3 -3
  37. data/lib/bundler/man/bundle-exec.1 +5 -5
  38. data/lib/bundler/man/bundle-exec.1.ronn +2 -2
  39. data/lib/bundler/man/bundle-fund.1 +3 -3
  40. data/lib/bundler/man/bundle-gem.1 +3 -3
  41. data/lib/bundler/man/bundle-help.1 +3 -3
  42. data/lib/bundler/man/bundle-info.1 +3 -3
  43. data/lib/bundler/man/bundle-init.1 +3 -3
  44. data/lib/bundler/man/bundle-inject.1 +3 -3
  45. data/lib/bundler/man/bundle-install.1 +3 -3
  46. data/lib/bundler/man/bundle-issue.1 +3 -3
  47. data/lib/bundler/man/bundle-licenses.1 +3 -3
  48. data/lib/bundler/man/bundle-list.1 +3 -3
  49. data/lib/bundler/man/bundle-lock.1 +3 -3
  50. data/lib/bundler/man/bundle-open.1 +3 -3
  51. data/lib/bundler/man/bundle-outdated.1 +3 -3
  52. data/lib/bundler/man/bundle-platform.1 +3 -3
  53. data/lib/bundler/man/bundle-plugin.1 +3 -3
  54. data/lib/bundler/man/bundle-pristine.1 +3 -3
  55. data/lib/bundler/man/bundle-remove.1 +3 -3
  56. data/lib/bundler/man/bundle-show.1 +3 -3
  57. data/lib/bundler/man/bundle-update.1 +3 -3
  58. data/lib/bundler/man/bundle-version.1 +3 -3
  59. data/lib/bundler/man/bundle-viz.1 +3 -3
  60. data/lib/bundler/man/bundle.1 +3 -3
  61. data/lib/bundler/man/gemfile.5 +3 -3
  62. data/lib/bundler/match_metadata.rb +13 -0
  63. data/lib/bundler/plugin/index.rb +5 -1
  64. data/lib/bundler/resolver/base.rb +2 -1
  65. data/lib/bundler/resolver/candidate.rb +11 -8
  66. data/lib/bundler/resolver/package.rb +8 -4
  67. data/lib/bundler/resolver/spec_group.rb +1 -25
  68. data/lib/bundler/resolver.rb +14 -4
  69. data/lib/bundler/ruby_dsl.rb +12 -3
  70. data/lib/bundler/rubygems_ext.rb +82 -81
  71. data/lib/bundler/rubygems_integration.rb +2 -15
  72. data/lib/bundler/runtime.rb +19 -24
  73. data/lib/bundler/shared_helpers.rb +4 -0
  74. data/lib/bundler/source/git/git_proxy.rb +6 -0
  75. data/lib/bundler/source/git.rb +6 -1
  76. data/lib/bundler/source/rubygems/remote.rb +11 -3
  77. data/lib/bundler/source/rubygems.rb +19 -4
  78. data/lib/bundler/source.rb +2 -0
  79. data/lib/bundler/source_list.rb +4 -0
  80. data/lib/bundler/spec_set.rb +66 -29
  81. data/lib/bundler/templates/newgem/Gemfile.tt +1 -0
  82. data/lib/bundler/vendor/uri/lib/uri/common.rb +7 -3
  83. data/lib/bundler/vendor/uri/lib/uri/generic.rb +12 -11
  84. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +6 -6
  85. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  86. data/lib/bundler/version.rb +1 -1
  87. data/lib/bundler.rb +10 -30
  88. metadata +3 -3
@@ -58,17 +58,28 @@ module Bundler
58
58
  # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
59
59
  # @param optional_groups [Array(String)] A list of optional groups
60
60
  def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
61
- if [true, false].include?(unlock)
61
+ unlock ||= {}
62
+
63
+ if unlock == true
64
+ @unlocking_all = true
62
65
  @unlocking_bundler = false
63
66
  @unlocking = unlock
67
+ @sources_to_unlock = []
68
+ @unlocking_ruby = false
69
+ @explicit_unlocks = []
70
+ conservative = false
64
71
  else
72
+ @unlocking_all = false
65
73
  @unlocking_bundler = unlock.delete(:bundler)
66
74
  @unlocking = unlock.any? {|_k, v| !Array(v).empty? }
75
+ @sources_to_unlock = unlock.delete(:sources) || []
76
+ @unlocking_ruby = unlock.delete(:ruby)
77
+ @explicit_unlocks = unlock.delete(:gems) || []
78
+ conservative = unlock.delete(:conservative)
67
79
  end
68
80
 
69
81
  @dependencies = dependencies
70
82
  @sources = sources
71
- @unlock = unlock
72
83
  @optional_groups = optional_groups
73
84
  @prefer_local = false
74
85
  @specs = nil
@@ -83,7 +94,7 @@ module Bundler
83
94
 
84
95
  @locked_ruby_version = nil
85
96
  @new_platforms = []
86
- @removed_platform = nil
97
+ @removed_platforms = []
87
98
 
88
99
  if lockfile_exists?
89
100
  @lockfile_contents = Bundler.read_file(lockfile)
@@ -93,29 +104,24 @@ module Bundler
93
104
  @platforms = @locked_platforms.dup
94
105
  @locked_bundler_version = @locked_gems.bundler_version
95
106
  @locked_ruby_version = @locked_gems.ruby_version
96
- @originally_locked_deps = @locked_gems.dependencies
107
+ @locked_deps = @locked_gems.dependencies
97
108
  @originally_locked_specs = SpecSet.new(@locked_gems.specs)
98
109
  @locked_checksums = @locked_gems.checksums
99
110
 
100
- if unlock != true
101
- @locked_deps = @originally_locked_deps
102
- @locked_specs = @originally_locked_specs
103
- @locked_sources = @locked_gems.sources
104
- else
105
- @unlock = {}
106
- @locked_deps = {}
111
+ if @unlocking_all
107
112
  @locked_specs = SpecSet.new([])
108
113
  @locked_sources = []
114
+ else
115
+ @locked_specs = @originally_locked_specs
116
+ @locked_sources = @locked_gems.sources
109
117
  end
110
118
  else
111
- @unlock = {}
112
- @locked_gems = nil
119
+ @locked_gems = nil
113
120
  @locked_platforms = []
114
121
  @most_specific_locked_platform = nil
115
122
  @platforms = []
116
123
  @locked_deps = {}
117
124
  @locked_specs = SpecSet.new([])
118
- @originally_locked_deps = {}
119
125
  @originally_locked_specs = @locked_specs
120
126
  @locked_sources = []
121
127
  @locked_checksums = Bundler.feature_flag.lockfile_checksums?
@@ -134,11 +140,10 @@ module Bundler
134
140
  @sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
135
141
  end
136
142
 
137
- @sources_to_unlock = @unlock.delete(:sources) || []
138
- @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
143
+ @unlocking_ruby ||= if @ruby_version && locked_ruby_version_object
139
144
  @ruby_version.diff(locked_ruby_version_object)
140
145
  end
141
- @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
146
+ @unlocking ||= @unlocking_ruby ||= (!@locked_ruby_version ^ !@ruby_version)
142
147
 
143
148
  @current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
144
149
 
@@ -146,9 +151,7 @@ module Bundler
146
151
  @path_changes = converge_paths
147
152
  @source_changes = converge_sources
148
153
 
149
- @explicit_unlocks = @unlock.delete(:gems) || []
150
-
151
- if @unlock[:conservative]
154
+ if conservative
152
155
  @gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
153
156
  else
154
157
  eager_unlock = @explicit_unlocks.map {|name| Dependency.new(name, ">= 0") }
@@ -220,6 +223,8 @@ module Bundler
220
223
 
221
224
  def prefer_local!
222
225
  @prefer_local = true
226
+
227
+ sources.prefer_local!
223
228
  end
224
229
 
225
230
  # For given dependency list returns a SpecSet with Gemspec of all the required
@@ -325,7 +330,7 @@ module Bundler
325
330
  SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps))
326
331
  else
327
332
  Bundler.ui.debug "Found no changes, using resolution from the lockfile"
328
- if @removed_platform || @locked_gems.may_include_redundant_platform_specific_gems?
333
+ if @removed_platforms.any? || @locked_gems.may_include_redundant_platform_specific_gems?
329
334
  SpecSet.new(filter_specs(@locked_specs, @dependencies))
330
335
  else
331
336
  @locked_specs
@@ -374,7 +379,7 @@ module Bundler
374
379
 
375
380
  def locked_ruby_version
376
381
  return unless ruby_version
377
- if @unlock[:ruby] || !@locked_ruby_version
382
+ if @unlocking_ruby || !@locked_ruby_version
378
383
  Bundler::RubyVersion.system
379
384
  else
380
385
  @locked_ruby_version
@@ -407,51 +412,18 @@ module Bundler
407
412
 
408
413
  raise ProductionError, "Frozen mode is set, but there's no lockfile" unless lockfile_exists?
409
414
 
410
- added = []
411
- deleted = []
412
- changed = []
413
-
414
- new_platforms = @platforms - @locked_platforms
415
- deleted_platforms = @locked_platforms - @platforms
416
- added.concat new_platforms.map {|p| "* platform: #{p}" }
417
- deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
418
-
419
- added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
420
- deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any?
421
-
422
- both_sources = Hash.new {|h, k| h[k] = [] }
423
- current_dependencies.each {|d| both_sources[d.name][0] = d }
424
- current_locked_dependencies.each {|d| both_sources[d.name][1] = d }
425
-
426
- both_sources.each do |name, (dep, lock_dep)|
427
- next if dep.nil? || lock_dep.nil?
428
-
429
- gemfile_source = dep.source || default_source
430
- lock_source = lock_dep.source || default_source
431
- next if lock_source.include?(gemfile_source)
432
-
433
- gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source"
434
- lockfile_source_name = lock_dep.source ? lock_source.to_gemfile : "no specified source"
435
- changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
436
- end
437
-
438
- reason = nothing_changed? ? "some dependencies were deleted from your gemfile" : change_reason
439
- msg = String.new
440
- msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because frozen mode is set"
441
- msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
442
- msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
443
- msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
444
- msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n"
415
+ msg = lockfile_changes_summary("frozen mode is set")
416
+ return unless msg
445
417
 
446
418
  unless explicit_flag
447
419
  suggested_command = unless Bundler.settings.locations("frozen").keys.include?(:env)
448
420
  "bundle config set frozen false"
449
421
  end
450
- msg << "If this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} " \
422
+ msg << "\n\nIf this is a development machine, remove the #{SharedHelpers.relative_lockfile_path} " \
451
423
  "freeze by running `#{suggested_command}`." if suggested_command
452
424
  end
453
425
 
454
- raise ProductionError, msg if added.any? || deleted.any? || changed.any? || !nothing_changed?
426
+ raise ProductionError, msg
455
427
  end
456
428
 
457
429
  def validate_runtime!
@@ -485,7 +457,7 @@ module Bundler
485
457
  end
486
458
 
487
459
  def validate_platforms!
488
- return if current_platform_locked?
460
+ return if current_platform_locked? || @platforms.include?(Gem::Platform::RUBY)
489
461
 
490
462
  raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
491
463
  "but your local platform is #{local_platform}. " \
@@ -506,10 +478,10 @@ module Bundler
506
478
  end
507
479
 
508
480
  def remove_platform(platform)
509
- removed_platform = @platforms.delete(Gem::Platform.new(platform))
510
- @removed_platform ||= removed_platform
511
- return if removed_platform
512
- raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
481
+ raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" unless @platforms.include?(platform)
482
+
483
+ @removed_platforms << platform
484
+ @platforms.delete(platform)
513
485
  end
514
486
 
515
487
  def nothing_changed?
@@ -536,6 +508,46 @@ module Bundler
536
508
 
537
509
  private
538
510
 
511
+ def lockfile_changes_summary(update_refused_reason)
512
+ added = []
513
+ deleted = []
514
+ changed = []
515
+
516
+ added.concat @new_platforms.map {|p| "* platform: #{p}" }
517
+ deleted.concat @removed_platforms.map {|p| "* platform: #{p}" }
518
+
519
+ added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
520
+ deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any?
521
+
522
+ both_sources = Hash.new {|h, k| h[k] = [] }
523
+ current_dependencies.each {|d| both_sources[d.name][0] = d }
524
+ current_locked_dependencies.each {|d| both_sources[d.name][1] = d }
525
+
526
+ both_sources.each do |name, (dep, lock_dep)|
527
+ next if dep.nil? || lock_dep.nil?
528
+
529
+ gemfile_source = dep.source || default_source
530
+ lock_source = lock_dep.source || default_source
531
+ next if lock_source.include?(gemfile_source)
532
+
533
+ gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source"
534
+ lockfile_source_name = lock_dep.source ? lock_source.to_gemfile : "no specified source"
535
+ changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
536
+ end
537
+
538
+ return unless added.any? || deleted.any? || changed.any? || resolve_needed?
539
+
540
+ reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile"
541
+
542
+ msg = String.new
543
+ msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because #{update_refused_reason}"
544
+ msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
545
+ msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
546
+ msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
547
+ msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n" unless unlocking?
548
+ msg
549
+ end
550
+
539
551
  def install_needed?
540
552
  resolve_needed? || missing_specs?
541
553
  end
@@ -596,8 +608,12 @@ module Bundler
596
608
  return
597
609
  end
598
610
 
599
- SharedHelpers.filesystem_access(file) do |p|
600
- File.open(p, "wb") {|f| f.puts(contents) }
611
+ begin
612
+ SharedHelpers.filesystem_access(file) do |p|
613
+ File.open(p, "wb") {|f| f.puts(contents) }
614
+ end
615
+ rescue ReadOnlyFileSystemError
616
+ raise ProductionError, lockfile_changes_summary("file system is read-only")
601
617
  end
602
618
  end
603
619
 
@@ -620,8 +636,9 @@ module Bundler
620
636
  @resolution_packages ||= begin
621
637
  last_resolve = converge_locked_specs
622
638
  remove_invalid_platforms!
623
- packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local)
624
- packages = additional_base_requirements_to_prevent_downgrades(packages, last_resolve)
639
+ new_resolution_platforms = @current_platform_missing ? @new_platforms + [local_platform] : @new_platforms
640
+ packages = Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: @unlocking_all || @gems_to_unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms)
641
+ packages = additional_base_requirements_to_prevent_downgrades(packages)
625
642
  packages = additional_base_requirements_to_force_updates(packages)
626
643
  packages
627
644
  end
@@ -639,6 +656,8 @@ module Bundler
639
656
  specs = begin
640
657
  resolve.materialize(dependencies)
641
658
  rescue IncorrectLockfileDependencies => e
659
+ raise if Bundler.frozen_bundle?
660
+
642
661
  spec = e.spec
643
662
  raise "Infinite loop while fixing lockfile dependencies" if incorrect_spec == spec
644
663
 
@@ -724,7 +743,7 @@ module Bundler
724
743
  end
725
744
 
726
745
  def start_resolution
727
- local_platform_needed_for_resolvability = @most_specific_non_local_locked_ruby_platform && !@platforms.include?(local_platform)
746
+ local_platform_needed_for_resolvability = @most_specific_non_local_locked_platform && !@platforms.include?(local_platform)
728
747
  @platforms << local_platform if local_platform_needed_for_resolvability
729
748
  add_platform(Gem::Platform::RUBY) if RUBY_ENGINE == "truffleruby"
730
749
 
@@ -732,9 +751,9 @@ module Bundler
732
751
 
733
752
  @resolved_bundler_version = result.find {|spec| spec.name == "bundler" }&.version
734
753
 
735
- if @most_specific_non_local_locked_ruby_platform
736
- if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_ruby_platform)
737
- @platforms.delete(@most_specific_non_local_locked_ruby_platform)
754
+ if @most_specific_non_local_locked_platform
755
+ if spec_set_incomplete_for_platform?(result, @most_specific_non_local_locked_platform)
756
+ @platforms.delete(@most_specific_non_local_locked_platform)
738
757
  elsif local_platform_needed_for_resolvability
739
758
  @platforms.delete(local_platform)
740
759
  end
@@ -742,7 +761,7 @@ module Bundler
742
761
 
743
762
  @platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
744
763
 
745
- SpecSet.new(result.for(dependencies, @platforms))
764
+ SpecSet.new(result.for(dependencies, @platforms | [Gem::Platform::RUBY]))
746
765
  end
747
766
 
748
767
  def precompute_source_requirements_for_indirect_dependencies?
@@ -751,22 +770,22 @@ module Bundler
751
770
 
752
771
  def current_platform_locked?
753
772
  @platforms.any? do |bundle_platform|
754
- MatchPlatform.platforms_match?(bundle_platform, local_platform)
773
+ generic_local_platform == bundle_platform || local_platform === bundle_platform
755
774
  end
756
775
  end
757
776
 
758
777
  def add_current_platform
759
778
  return if @platforms.include?(local_platform)
760
779
 
761
- @most_specific_non_local_locked_ruby_platform = find_most_specific_locked_ruby_platform
762
- return if @most_specific_non_local_locked_ruby_platform
780
+ @most_specific_non_local_locked_platform = find_most_specific_locked_platform
781
+ return if @most_specific_non_local_locked_platform
763
782
 
764
783
  @platforms << local_platform
765
784
  true
766
785
  end
767
786
 
768
- def find_most_specific_locked_ruby_platform
769
- return unless generic_local_platform_is_ruby? && current_platform_locked?
787
+ def find_most_specific_locked_platform
788
+ return unless current_platform_locked?
770
789
 
771
790
  @most_specific_locked_platform
772
791
  end
@@ -782,7 +801,7 @@ module Bundler
782
801
  unlock_reason = if unlock_targets
783
802
  "#{unlock_targets.first}: (#{unlock_targets.last.join(", ")})"
784
803
  else
785
- @unlock[:ruby] ? "ruby" : ""
804
+ @unlocking_ruby ? "ruby" : ""
786
805
  end
787
806
 
788
807
  return "bundler is unlocking #{unlock_reason}"
@@ -791,7 +810,7 @@ module Bundler
791
810
  [@source_changes, "the list of sources changed"],
792
811
  [@dependency_changes, "the dependencies in your gemfile changed"],
793
812
  [@current_platform_missing, "your lockfile does not include the current platform"],
794
- [@new_platforms.any?, "you added a new platform to your gemfile"],
813
+ [@new_platforms.any?, "you are adding a new platform to your lockfile"],
795
814
  [@path_changes, "the gemspecs for path gems changed"],
796
815
  [@local_changes, "the gemspecs for git local gems changed"],
797
816
  [@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
@@ -852,8 +871,6 @@ module Bundler
852
871
  end
853
872
 
854
873
  def check_lockfile
855
- @missing_lockfile_dep = nil
856
-
857
874
  @locked_spec_with_invalid_deps = nil
858
875
  @locked_spec_with_missing_deps = nil
859
876
 
@@ -871,10 +888,6 @@ module Bundler
871
888
  @locked_specs.delete(missing)
872
889
 
873
890
  @locked_spec_with_missing_deps = missing.first.name
874
- elsif !@dependency_changes
875
- @missing_lockfile_dep = current_dependencies.find do |d|
876
- @locked_specs[d.name].empty? && d.name != "bundler"
877
- end&.name
878
891
  end
879
892
 
880
893
  if invalid.any?
@@ -935,32 +948,33 @@ module Bundler
935
948
  end
936
949
 
937
950
  def converge_dependencies
938
- changes = false
951
+ @missing_lockfile_dep = nil
952
+ @changed_dependencies = []
939
953
 
940
- @dependencies.each do |dep|
954
+ current_dependencies.each do |dep|
941
955
  if dep.source
942
956
  dep.source = sources.get(dep.source)
943
957
  end
944
958
 
945
- unless locked_dep = @originally_locked_deps[dep.name]
946
- changes = true
947
- next
959
+ name = dep.name
960
+
961
+ dep_changed = @locked_deps[name].nil?
962
+
963
+ unless name == "bundler"
964
+ locked_specs = @originally_locked_specs[name]
965
+
966
+ if locked_specs.any? && !dep.matches_spec?(locked_specs.first)
967
+ @gems_to_unlock << name
968
+ dep_changed = true
969
+ elsif locked_specs.empty? && dep_changed == false
970
+ @missing_lockfile_dep = name
971
+ end
948
972
  end
949
973
 
950
- # Gem::Dependency#== matches Gem::Dependency#type. As the lockfile
951
- # doesn't carry a notion of the dependency type, if you use
952
- # add_development_dependency in a gemspec that's loaded with the gemspec
953
- # directive, the lockfile dependencies and resolved dependencies end up
954
- # with a mismatch on #type. Work around that by setting the type on the
955
- # dep from the lockfile.
956
- locked_dep.instance_variable_set(:@type, dep.type)
957
-
958
- # We already know the name matches from the hash lookup
959
- # so we only need to check the requirement now
960
- changes ||= dep.requirement != locked_dep.requirement
974
+ @changed_dependencies << name if dep_changed
961
975
  end
962
976
 
963
- changes
977
+ @changed_dependencies.any?
964
978
  end
965
979
 
966
980
  # Remove elements from the locked specs that are expired. This will most
@@ -1022,11 +1036,6 @@ module Bundler
1022
1036
  end
1023
1037
  end
1024
1038
 
1025
- if dep.nil? && requested_dep = requested_dependencies.find {|d| name == d.name }
1026
- @gems_to_unlock << name
1027
- deps << requested_dep
1028
- end
1029
-
1030
1039
  converged << s
1031
1040
  end
1032
1041
 
@@ -1095,11 +1104,15 @@ module Bundler
1095
1104
  current == proposed
1096
1105
  end
1097
1106
 
1098
- def additional_base_requirements_to_prevent_downgrades(resolution_packages, last_resolve)
1107
+ def additional_base_requirements_to_prevent_downgrades(resolution_packages)
1099
1108
  return resolution_packages unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
1100
- converge_specs(@originally_locked_specs - last_resolve).each do |locked_spec|
1109
+ @originally_locked_specs.each do |locked_spec|
1101
1110
  next if locked_spec.source.is_a?(Source::Path)
1102
- resolution_packages.base_requirements[locked_spec.name] = Gem::Requirement.new(">= #{locked_spec.version}")
1111
+
1112
+ name = locked_spec.name
1113
+ next if @changed_dependencies.include?(name)
1114
+
1115
+ resolution_packages.base_requirements[name] = Gem::Requirement.new(">= #{locked_spec.version}")
1103
1116
  end
1104
1117
  resolution_packages
1105
1118
  end
@@ -1108,7 +1121,7 @@ module Bundler
1108
1121
  return resolution_packages if @explicit_unlocks.empty?
1109
1122
  full_update = dup_for_full_unlock.resolve
1110
1123
  @explicit_unlocks.each do |name|
1111
- version = full_update[name].first&.version
1124
+ version = full_update.version_for(name)
1112
1125
  resolution_packages.base_requirements[name] = Gem::Requirement.new("= #{version}") if version
1113
1126
  end
1114
1127
  resolution_packages
@@ -2,51 +2,92 @@
2
2
 
3
3
  require "rubygems/dependency"
4
4
  require_relative "shared_helpers"
5
- require_relative "rubygems_ext"
6
5
 
7
6
  module Bundler
8
7
  class Dependency < Gem::Dependency
9
- attr_reader :autorequire
10
- attr_reader :groups, :platforms, :gemfile, :path, :git, :github, :branch, :ref, :glob
11
-
12
- ALL_RUBY_VERSIONS = (18..27).to_a.concat((30..34).to_a).freeze
13
- PLATFORM_MAP = {
14
- ruby: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
15
- mri: [Gem::Platform::RUBY, ALL_RUBY_VERSIONS],
16
- rbx: [Gem::Platform::RUBY],
17
- truffleruby: [Gem::Platform::RUBY],
18
- jruby: [Gem::Platform::JAVA, [18, 19]],
19
- windows: [Gem::Platform::WINDOWS, ALL_RUBY_VERSIONS],
20
- # deprecated
21
- mswin: [Gem::Platform::MSWIN, ALL_RUBY_VERSIONS],
22
- mswin64: [Gem::Platform::MSWIN64, ALL_RUBY_VERSIONS - [18]],
23
- mingw: [Gem::Platform::MINGW, ALL_RUBY_VERSIONS],
24
- x64_mingw: [Gem::Platform::X64_MINGW, ALL_RUBY_VERSIONS - [18, 19]],
25
- }.each_with_object({}) do |(platform, spec), hash|
26
- hash[platform] = spec[0]
27
- spec[1]&.each {|version| hash[:"#{platform}_#{version}"] = spec[0] }
28
- end.freeze
29
-
30
8
  def initialize(name, version, options = {}, &blk)
31
9
  type = options["type"] || :runtime
32
10
  super(name, version, type)
33
11
 
34
- @autorequire = nil
35
- @groups = Array(options["group"] || :default).map(&:to_sym)
36
- @source = options["source"]
37
- @path = options["path"]
38
- @git = options["git"]
39
- @github = options["github"]
40
- @branch = options["branch"]
41
- @ref = options["ref"]
42
- @glob = options["glob"]
43
- @platforms = Array(options["platforms"])
44
- @env = options["env"]
45
- @should_include = options.fetch("should_include", true)
46
- @gemfile = options["gemfile"]
47
- @force_ruby_platform = options["force_ruby_platform"] if options.key?("force_ruby_platform")
12
+ @options = options
13
+ end
14
+
15
+ def groups
16
+ @groups ||= Array(@options["group"] || :default).map(&:to_sym)
17
+ end
18
+
19
+ def source
20
+ return @source if defined?(@source)
21
+
22
+ @source = @options["source"]
23
+ end
24
+
25
+ def path
26
+ return @path if defined?(@path)
27
+
28
+ @path = @options["path"]
29
+ end
30
+
31
+ def git
32
+ return @git if defined?(@git)
48
33
 
49
- @autorequire = Array(options["require"] || []) if options.key?("require")
34
+ @git = @options["git"]
35
+ end
36
+
37
+ def github
38
+ return @github if defined?(@github)
39
+
40
+ @github = @options["github"]
41
+ end
42
+
43
+ def branch
44
+ return @branch if defined?(@branch)
45
+
46
+ @branch = @options["branch"]
47
+ end
48
+
49
+ def ref
50
+ return @ref if defined?(@ref)
51
+
52
+ @ref = @options["ref"]
53
+ end
54
+
55
+ def glob
56
+ return @glob if defined?(@glob)
57
+
58
+ @glob = @options["glob"]
59
+ end
60
+
61
+ def platforms
62
+ @platforms ||= Array(@options["platforms"])
63
+ end
64
+
65
+ def env
66
+ return @env if defined?(@env)
67
+
68
+ @env = @options["env"]
69
+ end
70
+
71
+ def should_include
72
+ @should_include ||= @options.fetch("should_include", true)
73
+ end
74
+
75
+ def gemfile
76
+ return @gemfile if defined?(@gemfile)
77
+
78
+ @gemfile = @options["gemfile"]
79
+ end
80
+
81
+ def force_ruby_platform
82
+ return @force_ruby_platform if defined?(@force_ruby_platform)
83
+
84
+ @force_ruby_platform = @options["force_ruby_platform"]
85
+ end
86
+
87
+ def autorequire
88
+ return @autorequire if defined?(@autorequire)
89
+
90
+ @autorequire = Array(@options["require"] || []) if @options.key?("require")
50
91
  end
51
92
 
52
93
  RUBY_PLATFORM_ARRAY = [Gem::Platform::RUBY].freeze
@@ -56,37 +97,41 @@ module Bundler
56
97
  # passed in the `valid_platforms` parameter
57
98
  def gem_platforms(valid_platforms)
58
99
  return RUBY_PLATFORM_ARRAY if force_ruby_platform
59
- return valid_platforms if @platforms.empty?
100
+ return valid_platforms if platforms.empty?
60
101
 
61
102
  valid_platforms.select {|p| expanded_platforms.include?(GemHelpers.generic(p)) }
62
103
  end
63
104
 
64
105
  def expanded_platforms
65
- @expanded_platforms ||= @platforms.filter_map {|pl| PLATFORM_MAP[pl] }.flatten.uniq
106
+ @expanded_platforms ||= platforms.filter_map {|pl| CurrentRuby::PLATFORM_MAP[pl] }.flatten.uniq
66
107
  end
67
108
 
68
109
  def should_include?
69
- @should_include && current_env? && current_platform?
110
+ should_include && current_env? && current_platform?
70
111
  end
71
112
 
72
113
  def gemspec_dev_dep?
73
- type == :development
114
+ @gemspec_dev_dep ||= @options.fetch("gemspec_dev_dep", false)
115
+ end
116
+
117
+ def gemfile_dep?
118
+ !gemspec_dev_dep?
74
119
  end
75
120
 
76
121
  def current_env?
77
- return true unless @env
78
- if @env.is_a?(Hash)
79
- @env.all? do |key, val|
122
+ return true unless env
123
+ if env.is_a?(Hash)
124
+ env.all? do |key, val|
80
125
  ENV[key.to_s] && (val.is_a?(String) ? ENV[key.to_s] == val : ENV[key.to_s] =~ val)
81
126
  end
82
127
  else
83
- ENV[@env.to_s]
128
+ ENV[env.to_s]
84
129
  end
85
130
  end
86
131
 
87
132
  def current_platform?
88
- return true if @platforms.empty?
89
- @platforms.any? do |p|
133
+ return true if platforms.empty?
134
+ platforms.any? do |p|
90
135
  Bundler.current_ruby.send("#{p}?")
91
136
  end
92
137
  end