bundler 4.0.21 → 4.1.0.beta1

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 (190) hide show
  1. checksums.yaml +4 -4
  2. data/{lib/bundler/vendor/connection_pool/LICENSE → MIT.txt} +8 -6
  3. data/bundler.gemspec +23 -6
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/checksum.rb +40 -25
  6. data/lib/bundler/ci_detector.rb +1 -1
  7. data/lib/bundler/cli/add.rb +3 -4
  8. data/lib/bundler/cli/cache.rb +4 -0
  9. data/lib/bundler/cli/clean.rb +5 -0
  10. data/lib/bundler/cli/common.rb +37 -1
  11. data/lib/bundler/cli/config.rb +4 -2
  12. data/lib/bundler/cli/gem.rb +0 -17
  13. data/lib/bundler/cli/install.rb +4 -5
  14. data/lib/bundler/cli/lock.rb +1 -2
  15. data/lib/bundler/cli/outdated.rb +8 -3
  16. data/lib/bundler/cli/pristine.rb +2 -1
  17. data/lib/bundler/cli/update.rb +21 -12
  18. data/lib/bundler/cli.rb +14 -11
  19. data/lib/bundler/definition.rb +61 -24
  20. data/lib/bundler/dependency.rb +4 -0
  21. data/lib/bundler/dsl.rb +77 -11
  22. data/lib/bundler/endpoint_specification.rb +51 -14
  23. data/lib/bundler/env.rb +7 -24
  24. data/lib/bundler/errors.rb +34 -5
  25. data/lib/bundler/fetcher/compact_index.rb +14 -5
  26. data/lib/bundler/fetcher/connection_pools.rb +150 -0
  27. data/lib/bundler/fetcher/downloader.rb +31 -16
  28. data/lib/bundler/fetcher.rb +8 -47
  29. data/lib/bundler/injector.rb +3 -3
  30. data/lib/bundler/inline.rb +44 -4
  31. data/lib/bundler/installer/parallel_installer.rb +25 -30
  32. data/lib/bundler/installer.rb +20 -6
  33. data/lib/bundler/lazy_specification.rb +44 -17
  34. data/lib/bundler/lockfile_generator.rb +24 -2
  35. data/lib/bundler/lockfile_parser.rb +43 -5
  36. data/lib/bundler/man/bundle-add.1 +7 -4
  37. data/lib/bundler/man/bundle-add.1.ronn +8 -4
  38. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  39. data/lib/bundler/man/bundle-cache.1 +2 -2
  40. data/lib/bundler/man/bundle-cache.1.ronn +2 -2
  41. data/lib/bundler/man/bundle-check.1 +1 -1
  42. data/lib/bundler/man/bundle-clean.1 +1 -1
  43. data/lib/bundler/man/bundle-config.1 +38 -6
  44. data/lib/bundler/man/bundle-config.1.ronn +143 -10
  45. data/lib/bundler/man/bundle-console.1 +1 -1
  46. data/lib/bundler/man/bundle-doctor.1 +1 -1
  47. data/lib/bundler/man/bundle-env.1 +1 -1
  48. data/lib/bundler/man/bundle-exec.1 +1 -1
  49. data/lib/bundler/man/bundle-fund.1 +1 -1
  50. data/lib/bundler/man/bundle-gem.1 +1 -1
  51. data/lib/bundler/man/bundle-help.1 +1 -1
  52. data/lib/bundler/man/bundle-info.1 +1 -1
  53. data/lib/bundler/man/bundle-init.1 +1 -1
  54. data/lib/bundler/man/bundle-install.1 +2 -2
  55. data/lib/bundler/man/bundle-install.1.ronn +4 -4
  56. data/lib/bundler/man/bundle-issue.1 +1 -1
  57. data/lib/bundler/man/bundle-licenses.1 +1 -1
  58. data/lib/bundler/man/bundle-list.1 +1 -1
  59. data/lib/bundler/man/bundle-lock.1 +3 -3
  60. data/lib/bundler/man/bundle-lock.1.ronn +5 -5
  61. data/lib/bundler/man/bundle-open.1 +1 -1
  62. data/lib/bundler/man/bundle-outdated.1 +1 -1
  63. data/lib/bundler/man/bundle-platform.1 +1 -1
  64. data/lib/bundler/man/bundle-plugin.1 +1 -1
  65. data/lib/bundler/man/bundle-pristine.1 +1 -1
  66. data/lib/bundler/man/bundle-remove.1 +1 -1
  67. data/lib/bundler/man/bundle-show.1 +1 -1
  68. data/lib/bundler/man/bundle-update.1 +3 -3
  69. data/lib/bundler/man/bundle-update.1.ronn +3 -5
  70. data/lib/bundler/man/bundle-version.1 +1 -1
  71. data/lib/bundler/man/bundle.1 +1 -1
  72. data/lib/bundler/man/gemfile.5 +45 -1
  73. data/lib/bundler/man/gemfile.5.ronn +53 -0
  74. data/lib/bundler/match_metadata.rb +20 -0
  75. data/lib/bundler/match_platform.rb +25 -2
  76. data/lib/bundler/match_remote_metadata.rb +21 -6
  77. data/lib/bundler/materialization.rb +2 -1
  78. data/lib/bundler/override.rb +69 -0
  79. data/lib/bundler/plugin/dsl.rb +3 -5
  80. data/lib/bundler/plugin/events.rb +55 -13
  81. data/lib/bundler/plugin/index.rb +87 -11
  82. data/lib/bundler/plugin/installer/path.rb +1 -1
  83. data/lib/bundler/plugin/installer.rb +13 -5
  84. data/lib/bundler/plugin.rb +58 -30
  85. data/lib/bundler/remote_specification.rb +6 -3
  86. data/lib/bundler/resolver/base.rb +2 -1
  87. data/lib/bundler/resolver/incompatibility.rb +1 -1
  88. data/lib/bundler/resolver.rb +73 -23
  89. data/lib/bundler/ruby_version.rb +0 -2
  90. data/lib/bundler/rubygems_ext.rb +71 -1
  91. data/lib/bundler/rubygems_gem_installer.rb +41 -2
  92. data/lib/bundler/rubygems_integration.rb +7 -2
  93. data/lib/bundler/runtime.rb +69 -2
  94. data/lib/bundler/self_manager.rb +9 -15
  95. data/lib/bundler/settings.rb +373 -30
  96. data/lib/bundler/shared_helpers.rb +2 -1
  97. data/lib/bundler/source/git/git_proxy.rb +2 -10
  98. data/lib/bundler/source/git.rb +15 -6
  99. data/lib/bundler/source/path/installer.rb +1 -1
  100. data/lib/bundler/source/rubygems/remote.rb +10 -5
  101. data/lib/bundler/source/rubygems.rb +48 -12
  102. data/lib/bundler/spec_set.rb +16 -4
  103. data/lib/bundler/stub_specification.rb +2 -1
  104. data/lib/bundler/templates/newgem/Gemfile.tt +4 -4
  105. data/lib/bundler/templates/newgem/newgem.gemspec.tt +3 -3
  106. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
  107. data/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +1 -1
  108. data/lib/bundler/ui/shell.rb +0 -4
  109. data/lib/bundler/ui/silent.rb +0 -4
  110. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +35 -2
  111. data/lib/bundler/vendor/thor/lib/thor/base.rb +2 -1
  112. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +14 -6
  113. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +2 -0
  114. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  115. data/lib/bundler/vendor/thor/lib/thor.rb +34 -1
  116. data/lib/bundler/vendored_pub_grub.rb +5 -2
  117. data/lib/bundler/vendored_securerandom.rb +11 -8
  118. data/lib/bundler/vendored_uri.rb +14 -14
  119. data/lib/bundler/version.rb +1 -1
  120. data/lib/bundler/worker.rb +3 -2
  121. data/lib/bundler.rb +1 -1
  122. data/lib/rubygems/compact_index_client/cache.rb +122 -0
  123. data/lib/rubygems/compact_index_client/cache_file.rb +147 -0
  124. data/lib/rubygems/compact_index_client/http_fetcher.rb +88 -0
  125. data/lib/rubygems/compact_index_client/parser.rb +90 -0
  126. data/lib/rubygems/compact_index_client/updater.rb +113 -0
  127. data/lib/rubygems/compact_index_client.rb +111 -0
  128. data/lib/rubygems/cooldown_settings.rb +57 -0
  129. data/lib/rubygems/credential_store/native/linux.rb +97 -0
  130. data/lib/rubygems/credential_store/native/macos.rb +88 -0
  131. data/lib/rubygems/credential_store/native/windows.rb +130 -0
  132. data/lib/rubygems/credential_store.rb +332 -0
  133. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/assignment.rb +1 -1
  134. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +7 -7
  135. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/failure_writer.rb +1 -1
  136. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/incompatibility.rb +4 -4
  137. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/package.rb +1 -1
  138. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/partial_solution.rb +1 -1
  139. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/rubygems.rb +3 -3
  140. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/solve_failure.rb +1 -1
  141. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/static_package_source.rb +3 -3
  142. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/strategy.rb +2 -2
  143. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/term.rb +1 -1
  144. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version.rb +1 -1
  145. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_constraint.rb +3 -3
  146. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_range.rb +1 -1
  147. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_solver.rb +2 -2
  148. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_union.rb +1 -1
  149. data/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb +57 -0
  150. data/lib/{bundler → rubygems}/vendor/securerandom/lib/securerandom.rb +10 -6
  151. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/common.rb +119 -119
  152. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/file.rb +13 -13
  153. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ftp.rb +24 -24
  154. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/generic.rb +132 -132
  155. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/http.rb +18 -18
  156. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/https.rb +4 -4
  157. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldap.rb +14 -14
  158. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldaps.rb +4 -4
  159. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/mailto.rb +21 -21
  160. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc2396_parser.rb +39 -39
  161. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc3986_parser.rb +14 -14
  162. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/version.rb +1 -1
  163. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ws.rb +12 -12
  164. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/wss.rb +4 -4
  165. data/lib/{bundler → rubygems}/vendor/uri/lib/uri.rb +35 -31
  166. data/lib/rubygems/yaml_serializer.rb +880 -0
  167. metadata +77 -68
  168. data/CHANGELOG.md +0 -5784
  169. data/LICENSE.md +0 -22
  170. data/README.md +0 -58
  171. data/lib/bundler/compact_index_client/cache.rb +0 -107
  172. data/lib/bundler/compact_index_client/cache_file.rb +0 -148
  173. data/lib/bundler/compact_index_client/parser.rb +0 -87
  174. data/lib/bundler/compact_index_client/updater.rb +0 -105
  175. data/lib/bundler/compact_index_client.rb +0 -92
  176. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +0 -227
  177. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +0 -3
  178. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +0 -56
  179. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +0 -230
  180. data/lib/bundler/vendor/net-http-persistent/README.rdoc +0 -82
  181. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +0 -41
  182. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +0 -65
  183. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +0 -80
  184. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +0 -1153
  185. data/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +0 -31
  186. data/lib/bundler/vendored_persistent.rb +0 -11
  187. data/lib/bundler/yaml_serializer.rb +0 -98
  188. /data/lib/{bundler → rubygems}/vendor/pub_grub/LICENSE.txt +0 -0
  189. /data/lib/{bundler → rubygems}/vendor/securerandom/COPYING +0 -0
  190. /data/lib/{bundler → rubygems}/vendor/uri/COPYING +0 -0
@@ -562,6 +562,59 @@ call.
562
562
  This can be useful to run tests against multiple combinations of dependencies,
563
563
  or to load per-developer gems from an untracked gemfile.
564
564
 
565
+ ## OVERRIDE
566
+
567
+ The `override` directive rewrites a constraint on another gem before
568
+ resolution runs. It targets the common case where an upstream gem's
569
+ published metadata is too narrow on the current project's machine -- a stale
570
+ upper bound, an unwanted floor, or a transitive pin that has to be lifted.
571
+
572
+ override <target>, <field>: <operation>
573
+
574
+ `<target>` is a gem name string or `:all`. `<field>` is one of `version:`,
575
+ `required_ruby_version:`, or `required_rubygems_version:`. `<operation>` is
576
+ one of:
577
+
578
+ * a version requirement string (e.g. `">= 8.0"`), which **replaces** the
579
+ target's requirement absolutely. The original requirement, both direct
580
+ and transitive, is discarded in favour of the override.
581
+ * `:ignore_upper`, which removes upper-bound operators (`<` and `<=`) from
582
+ the existing requirement and folds `~>` into its lower bound (`~> 1.5`
583
+ becomes `>= 1.5`). Other operators, including `!=`, are preserved.
584
+ * `nil`, which collapses the requirement to `>= 0` (no constraint at all).
585
+
586
+ `:all` only applies to `required_ruby_version:` and `required_rubygems_version:`.
587
+ A per-gem override on the same field takes precedence over an `:all` override.
588
+ `:all + version:` is rejected: version requirements only make sense per gem.
589
+
590
+ Multiple `override` calls for distinct targets are allowed; declaring the
591
+ same `target` and `field` twice is an error.
592
+
593
+ source "https://rubygems.org"
594
+
595
+ # Force every reference to "rails" -- direct or transitive -- to >= 8.0.
596
+ override "rails", version: ">= 8.0"
597
+
598
+ # Strip the upper bound on nokogiri.
599
+ override "nokogiri", version: :ignore_upper
600
+
601
+ # Drop the version pin on legacy entirely.
602
+ override "legacy", version: nil
603
+
604
+ # Loosen every gem's required_ruby_version upper bound.
605
+ override :all, required_ruby_version: :ignore_upper
606
+
607
+ # Override one specific gem's required_rubygems_version.
608
+ override "tricky", required_rubygems_version: nil
609
+
610
+ gem "rails", "~> 7.0"
611
+
612
+ The override only affects resolution and the install-time Ruby/RubyGems
613
+ compatibility checks; `Gemfile.lock` continues to reflect the resolved
614
+ versions, not the rewritten requirements. When resolution still fails,
615
+ Bundler appends the active overrides (with their Gemfile location) to the
616
+ error message so it is clear which override shaped the constraint set.
617
+
565
618
  ## SOURCE PRIORITY
566
619
 
567
620
  When attempting to locate a gem to satisfy a gem requirement,
@@ -14,6 +14,18 @@ module Bundler
14
14
  @required_rubygems_version.satisfied_by?(Gem.rubygems_version)
15
15
  end
16
16
 
17
+ def matches_current_metadata_with_overrides?(overrides)
18
+ matches_current_ruby_with_overrides?(overrides) && matches_current_rubygems_with_overrides?(overrides)
19
+ end
20
+
21
+ def matches_current_ruby_with_overrides?(overrides)
22
+ effective_required_version(@required_ruby_version, :required_ruby_version, overrides).satisfied_by?(Gem.ruby_version)
23
+ end
24
+
25
+ def matches_current_rubygems_with_overrides?(overrides)
26
+ effective_required_version(@required_rubygems_version, :required_rubygems_version, overrides).satisfied_by?(Gem.rubygems_version)
27
+ end
28
+
17
29
  def expanded_dependencies
18
30
  runtime_dependencies + [
19
31
  metadata_dependency("Ruby", @required_ruby_version),
@@ -26,5 +38,13 @@ module Bundler
26
38
 
27
39
  Gem::Dependency.new("#{name}\0", requirement)
28
40
  end
41
+
42
+ private
43
+
44
+ def effective_required_version(requirement, field, overrides)
45
+ return requirement if overrides.nil? || overrides.empty?
46
+ override = Override.find_for(overrides, name, field)
47
+ override ? override.apply_to(requirement) : requirement
48
+ end
29
49
  end
30
50
  end
@@ -2,6 +2,10 @@
2
2
 
3
3
  module Bundler
4
4
  module MatchPlatform
5
+ def content_address
6
+ nil
7
+ end
8
+
5
9
  def installable_on_platform?(target_platform) # :nodoc:
6
10
  return true if [Gem::Platform::RUBY, nil, target_platform].include?(platform)
7
11
  return true if Gem::Platform.new(platform) === target_platform
@@ -11,13 +15,32 @@ module Bundler
11
15
 
12
16
  def self.select_best_platform_match(specs, platform, force_ruby: false, prefer_locked: false)
13
17
  matching = select_all_platform_match(specs, platform, force_ruby: force_ruby, prefer_locked: prefer_locked)
18
+ matching = prefer_content_addressable(matching)
14
19
 
15
20
  Gem::Platform.sort_and_filter_best_platform_match(matching, platform)
16
21
  end
17
22
 
18
- def self.select_best_local_platform_match(specs, force_ruby: false)
23
+ def self.select_all_content_address_match(specs, content_address)
24
+ return specs unless Gem::ContentAddress.match?(content_address)
25
+
26
+ specs.select {|spec| spec.content_address == content_address }
27
+ end
28
+
29
+ def self.prefer_content_addressable(matching)
30
+ addressable, non_addressable = matching.partition {|s| Gem::ContentAddress.content_addressed?(s, validate_ruby_abi: false) }
31
+ return matching if addressable.empty?
32
+
33
+ compatible = addressable.select(&:matches_current_metadata?)
34
+ return compatible if compatible.any?
35
+
36
+ non_addressable.any? ? non_addressable : matching
37
+ end
38
+
39
+ def self.select_best_local_platform_match(specs, force_ruby: false, locked_platforms: nil)
19
40
  local = Bundler.local_platform
20
- matching = select_all_platform_match(specs, local, force_ruby: force_ruby).filter_map(&:materialized_for_installation)
41
+ matching = select_all_platform_match(specs, local, force_ruby: force_ruby)
42
+ matching = matching.filter_map {|spec| spec.materialized_for_installation(locked_platforms) }
43
+ matching = prefer_content_addressable(matching)
21
44
 
22
45
  Gem::Platform.sort_best_platform_match(matching, local)
23
46
  end
@@ -6,19 +6,34 @@ module Bundler
6
6
  # API didn't include that field, so some marshalled specs in the index have it
7
7
  # set to +nil+.
8
8
  def matches_current_ruby?
9
- @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default
10
-
9
+ ensure_required_ruby_version_loaded
11
10
  super
12
11
  end
13
12
 
14
13
  def matches_current_rubygems?
15
- # A fallback is included because the original version of the specification
16
- # API didn't include that field, so some marshalled specs in the index have it
17
- # set to +nil+.
18
- @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default
14
+ ensure_required_rubygems_version_loaded
15
+ super
16
+ end
17
+
18
+ def matches_current_ruby_with_overrides?(overrides)
19
+ ensure_required_ruby_version_loaded
20
+ super
21
+ end
19
22
 
23
+ def matches_current_rubygems_with_overrides?(overrides)
24
+ ensure_required_rubygems_version_loaded
20
25
  super
21
26
  end
27
+
28
+ private
29
+
30
+ def ensure_required_ruby_version_loaded
31
+ @required_ruby_version ||= _remote_specification.required_ruby_version || Gem::Requirement.default # rubocop:disable Naming/MemoizedInstanceVariableName
32
+ end
33
+
34
+ def ensure_required_rubygems_version_loaded
35
+ @required_rubygems_version ||= _remote_specification.required_rubygems_version || Gem::Requirement.default # rubocop:disable Naming/MemoizedInstanceVariableName
36
+ end
22
37
  end
23
38
 
24
39
  module MatchRemoteMetadata
@@ -12,6 +12,7 @@ module Bundler
12
12
  @dep = dep
13
13
  @platform = platform
14
14
  @candidates = candidates
15
+ @locked_platforms = candidates&.map(&:platform)
15
16
  end
16
17
 
17
18
  def complete?
@@ -24,7 +25,7 @@ module Bundler
24
25
  elsif platform
25
26
  MatchPlatform.select_best_platform_match(@candidates, platform, force_ruby: dep.force_ruby_platform)
26
27
  else
27
- MatchPlatform.select_best_local_platform_match(@candidates, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform)
28
+ MatchPlatform.select_best_local_platform_match(@candidates, force_ruby: dep.force_ruby_platform || dep.default_force_ruby_platform, locked_platforms: @locked_platforms)
28
29
  end
29
30
  end
30
31
 
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ class Override
5
+ UPPER_BOUND_OPERATORS = ["<", "<="].freeze
6
+
7
+ def self.find_for(overrides, name, field)
8
+ overrides.find {|o| o.target == name && o.field == field } ||
9
+ overrides.find {|o| o.target == :all && o.field == field }
10
+ end
11
+
12
+ # Attach the given overrides onto every LazySpecification in `specs` so
13
+ # downstream consumers (LazySpecification#choose_compatible, the install-
14
+ # time compatibility check, etc.) can read the override list off the spec
15
+ # itself. Non-LazySpec entries (StubSpecification, Gem::Specification, ...)
16
+ # are left untouched.
17
+ def self.attach(specs, overrides)
18
+ return if overrides.nil? || overrides.empty?
19
+ specs.each {|s| s.overrides = overrides if s.is_a?(LazySpecification) }
20
+ end
21
+
22
+ attr_reader :target, :field, :operation, :source_location
23
+
24
+ def initialize(target, field, operation, source_location: nil)
25
+ @target = target
26
+ @field = field
27
+ @operation = operation
28
+ @source_location = source_location
29
+ end
30
+
31
+ def source_location_label
32
+ return nil unless @source_location
33
+ "#{File.basename(@source_location.path)}:#{@source_location.lineno}"
34
+ end
35
+
36
+ def apply_to(requirement)
37
+ case operation
38
+ when nil
39
+ Gem::Requirement.default
40
+ when :ignore_upper
41
+ remove_upper_bounds(requirement)
42
+ when String
43
+ Gem::Requirement.new(operation)
44
+ else
45
+ raise ArgumentError, "unsupported override operation: #{operation.inspect}"
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def remove_upper_bounds(requirement)
52
+ return Gem::Requirement.default if requirement.nil? || requirement.none?
53
+
54
+ preserved = requirement.requirements.filter_map do |op, version|
55
+ if UPPER_BOUND_OPERATORS.include?(op)
56
+ nil
57
+ elsif op == "~>"
58
+ [">=", version]
59
+ else
60
+ [op, version]
61
+ end
62
+ end
63
+
64
+ return Gem::Requirement.default if preserved.empty?
65
+
66
+ Gem::Requirement.new(preserved.map {|op, v| "#{op} #{v}" })
67
+ end
68
+ end
69
+ end
@@ -5,12 +5,11 @@ module Bundler
5
5
  # Dsl to parse the Gemfile looking for plugins to install
6
6
  class DSL < Bundler::Dsl
7
7
  class PluginGemfileError < PluginError; end
8
- alias_method :_gem, :gem # To use for plugin installation as gem
9
8
 
10
9
  # So that we don't have to override all there methods to dummy ones
11
10
  # explicitly.
12
11
  # They will be handled by method_missing
13
- [:gemspec, :gem, :install_if, :platforms, :env].each {|m| undef_method m }
12
+ [:gemspec, :install_if, :platforms, :env].each {|m| undef_method m }
14
13
 
15
14
  # This lists the plugins that was added automatically and not specified by
16
15
  # the user.
@@ -24,12 +23,11 @@ module Bundler
24
23
 
25
24
  def initialize
26
25
  super
27
- @sources = Plugin::SourceList.new
28
26
  @inferred_plugins = [] # The source plugins inferred from :type
29
27
  end
30
28
 
31
- def plugin(name, *args)
32
- _gem(name, *args)
29
+ def gem(*args)
30
+ # Ignore regular dependencies when doing the plugins-only pre-parse
33
31
  end
34
32
 
35
33
  def method_missing(name, *args)
@@ -30,6 +30,54 @@ module Bundler
30
30
  @events.key?(event)
31
31
  end
32
32
 
33
+ # @!parse
34
+ # A hook called before the Gemfile is evaluated
35
+ # Includes the Gemfile path and the Lockfile path
36
+ # GEM_BEFORE_EVAL = "before-eval"
37
+ define :GEM_BEFORE_EVAL, "before-eval"
38
+
39
+ # @!parse
40
+ # A hook called after the Gemfile is evaluated
41
+ # Includes a Bundler::Definition
42
+ # GEM_AFTER_EVAL = "after-eval"
43
+ define :GEM_AFTER_EVAL, "after-eval"
44
+
45
+ # @!parse
46
+ # A hook called before any gems install
47
+ # Includes an Array of Bundler::Dependency objects
48
+ # GEM_BEFORE_INSTALL_ALL = "before-install-all"
49
+ define :GEM_BEFORE_INSTALL_ALL, "before-install-all"
50
+
51
+ # @!parse
52
+ # A hook called before each individual gem is downloaded from a remote source.
53
+ # Includes a spec-like object responding to the Gem::Specification API
54
+ # (for example, a Bundler spec proxy such as Bundler::EndpointSpecification
55
+ # or Bundler::RemoteSpecification). Does not fire when the gem is already
56
+ # present at the initial download-cache check.
57
+ # GEM_BEFORE_FETCH = "before-fetch"
58
+ define :GEM_BEFORE_FETCH, "before-fetch"
59
+
60
+ # @!parse
61
+ # A hook called after each individual gem is downloaded from a remote source.
62
+ # Includes a spec-like object responding to the Gem::Specification API
63
+ # (for example, a Bundler spec proxy such as Bundler::EndpointSpecification
64
+ # or Bundler::RemoteSpecification). Does not fire when the gem is already
65
+ # present at the initial download-cache check.
66
+ # GEM_AFTER_FETCH = "after-fetch"
67
+ define :GEM_AFTER_FETCH, "after-fetch"
68
+
69
+ # @!parse
70
+ # A hook called before a git source is fetched or checked out.
71
+ # Includes a Bundler::Source::Git reference.
72
+ # GIT_BEFORE_FETCH = "before-git-fetch"
73
+ define :GIT_BEFORE_FETCH, "before-git-fetch"
74
+
75
+ # @!parse
76
+ # A hook called after a git source is fetched or checked out.
77
+ # Includes a Bundler::Source::Git reference.
78
+ # GIT_AFTER_FETCH = "after-git-fetch"
79
+ define :GIT_AFTER_FETCH, "after-git-fetch"
80
+
33
81
  # @!parse
34
82
  # A hook called before each individual gem is installed
35
83
  # Includes a Bundler::ParallelInstaller::SpecInstallation.
@@ -45,18 +93,18 @@ module Bundler
45
93
  # GEM_AFTER_INSTALL = "after-install"
46
94
  define :GEM_AFTER_INSTALL, "after-install"
47
95
 
48
- # @!parse
49
- # A hook called before any gems install
50
- # Includes an Array of Bundler::Dependency objects
51
- # GEM_BEFORE_INSTALL_ALL = "before-install-all"
52
- define :GEM_BEFORE_INSTALL_ALL, "before-install-all"
53
-
54
96
  # @!parse
55
97
  # A hook called after any gems install
56
98
  # Includes an Array of Bundler::Dependency objects
57
99
  # GEM_AFTER_INSTALL_ALL = "after-install-all"
58
100
  define :GEM_AFTER_INSTALL_ALL, "after-install-all"
59
101
 
102
+ # @!parse
103
+ # A hook called before any gems require
104
+ # Includes an Array of Bundler::Dependency objects.
105
+ # GEM_BEFORE_REQUIRE_ALL = "before-require-all"
106
+ define :GEM_BEFORE_REQUIRE_ALL, "before-require-all"
107
+
60
108
  # @!parse
61
109
  # A hook called before each individual gem is required
62
110
  # Includes a Bundler::Dependency.
@@ -69,17 +117,11 @@ module Bundler
69
117
  # GEM_AFTER_REQUIRE = "after-require"
70
118
  define :GEM_AFTER_REQUIRE, "after-require"
71
119
 
72
- # @!parse
73
- # A hook called before any gems require
74
- # Includes an Array of Bundler::Dependency objects.
75
- # GEM_BEFORE_REQUIRE_ALL = "before-require-all"
76
- define :GEM_BEFORE_REQUIRE_ALL, "before-require-all"
77
-
78
120
  # @!parse
79
121
  # A hook called after all gems required
80
122
  # Includes an Array of Bundler::Dependency objects.
81
123
  # GEM_AFTER_REQUIRE_ALL = "after-require-all"
82
- define :GEM_AFTER_REQUIRE_ALL, "after-require-all"
124
+ define :GEM_AFTER_REQUIRE_ALL, "after-require-all"
83
125
  end
84
126
  end
85
127
  end
@@ -163,20 +163,28 @@ module Bundler
163
163
  # @param [Pathname] index file path
164
164
  # @param [Boolean] is the index file global index
165
165
  def load_index(index_file, global = false)
166
+ base = base_for_index(global)
167
+
166
168
  SharedHelpers.filesystem_access(index_file, :read) do |index_f|
167
169
  valid_file = index_f&.exist? && !index_f.size.zero?
168
170
  break unless valid_file
169
171
 
170
172
  data = index_f.read
171
173
 
172
- require_relative "../yaml_serializer"
173
- index = YAMLSerializer.load(data)
174
+ require "rubygems/yaml_serializer"
175
+ # Empty sections load as nil, e.g. from index files written by
176
+ # older Bundler versions, which dumped empty hashes as a bare key.
177
+ index = Gem::YAMLSerializer.load(data) || {}
178
+
179
+ escaping = escaping_plugins(index, base)
180
+ hooks = (index["hooks"] || {}).transform_values {|names| Array(names) - escaping }
174
181
 
175
- @commands.merge!(index["commands"])
176
- @hooks.merge!(index["hooks"])
177
- @load_paths.merge!(index["load_paths"])
178
- @plugin_paths.merge!(index["plugin_paths"])
179
- @sources.merge!(index["sources"]) unless global
182
+ @commands.merge!(owned_by(index["commands"] || {}, escaping))
183
+ # An event whose plugins all escaped is left out rather than merged in empty.
184
+ @hooks.merge!(hooks.reject {|_, names| names.empty? })
185
+ @load_paths.merge!(named(transform_index_paths(index["load_paths"]) {|p| absolutize_path(p, base) }, escaping))
186
+ @plugin_paths.merge!(named(transform_index_paths(index["plugin_paths"]) {|p| absolutize_path(p, base) }, escaping))
187
+ @sources.merge!(owned_by(index["sources"] || {}, escaping)) unless global
180
188
  end
181
189
  end
182
190
 
@@ -184,20 +192,88 @@ module Bundler
184
192
  # instance variables in YAML format. (The instance variables are supposed
185
193
  # to be only String key value pairs)
186
194
  def save_index
195
+ base = base_for_index(false)
196
+
187
197
  index = {
188
198
  "commands" => @commands,
189
199
  "hooks" => @hooks,
190
- "load_paths" => @load_paths,
191
- "plugin_paths" => @plugin_paths,
200
+ "load_paths" => transform_index_paths(@load_paths) {|p| relativize_path(p, base) },
201
+ "plugin_paths" => transform_index_paths(@plugin_paths) {|p| relativize_path(p, base) },
192
202
  "sources" => @sources,
193
203
  }
194
204
 
195
- require_relative "../yaml_serializer"
205
+ require "rubygems/yaml_serializer"
196
206
  SharedHelpers.filesystem_access(index_file) do |index_f|
197
207
  FileUtils.mkdir_p(index_f.dirname)
198
- File.open(index_f, "w") {|f| f.puts YAMLSerializer.dump(index) }
208
+ File.open(index_f, "w") {|f| f.puts Gem::YAMLSerializer.dump(index) }
209
+ end
210
+ end
211
+
212
+ def base_for_index(global)
213
+ global ? Plugin.global_root : Plugin.root
214
+ end
215
+
216
+ # A relative path only means anything inside the root, so an entry that escapes is not one Bundler installed.
217
+ def escaping_plugins(index, base)
218
+ names = []
219
+
220
+ %w[load_paths plugin_paths].each do |key|
221
+ (index[key] || {}).each do |name, value|
222
+ escapes = Array(value).any? do |path|
223
+ !Pathname.new(path).absolute? && !contained_in?(absolutize_path(path, base), base)
224
+ end
225
+
226
+ names << name if escapes
227
+ end
228
+ end
229
+
230
+ names.uniq
231
+ end
232
+
233
+ # Expanded here, not by the caller: what gets stored stays joined, because
234
+ # #installed_in_plugin_root? matches it against Plugin.root as written.
235
+ def contained_in?(path, base)
236
+ path = File.expand_path(path)
237
+ base = File.expand_path(base)
238
+
239
+ path == base || path.start_with?("#{base}#{File::SEPARATOR}")
240
+ end
241
+
242
+ # commands and sources are keyed by what they provide, load_paths and plugin_paths by the plugin.
243
+ def owned_by(mapping, names)
244
+ mapping.reject {|_, plugin| names.include?(plugin) }
245
+ end
246
+
247
+ def named(mapping, names)
248
+ mapping.reject {|plugin, _| names.include?(plugin) }
249
+ end
250
+
251
+ def transform_index_paths(paths)
252
+ return {} unless paths
253
+
254
+ paths.transform_values do |value|
255
+ if value.is_a?(Array)
256
+ value.map {|path| yield path }
257
+ else
258
+ yield value
259
+ end
199
260
  end
200
261
  end
262
+
263
+ def relativize_path(path, base)
264
+ pathname = Pathname.new(path)
265
+ return path unless pathname.absolute?
266
+
267
+ return path unless contained_in?(pathname.to_s, base)
268
+
269
+ pathname.relative_path_from(Pathname.new(base)).to_s
270
+ end
271
+
272
+ def absolutize_path(path, base)
273
+ pathname = Pathname.new(path)
274
+ pathname = Pathname.new(base).join(pathname) unless pathname.absolute?
275
+ pathname.to_s
276
+ end
201
277
  end
202
278
  end
203
279
  end
@@ -5,7 +5,7 @@ module Bundler
5
5
  class Installer
6
6
  class Path < Bundler::Source::Path
7
7
  def root
8
- SharedHelpers.in_bundle? ? Bundler.root : Plugin.root
8
+ Plugin.root
9
9
  end
10
10
 
11
11
  def eql?(other)
@@ -32,12 +32,18 @@ module Bundler
32
32
  #
33
33
  # @param [Definition] definition object
34
34
  # @return [Hash] map of names to their specs they are installed with
35
- def install_definition(definition)
35
+ def install_definition(definition, latest = false)
36
36
  def definition.lock(*); end
37
- definition.remotely!
37
+
38
+ if latest || definition.missing_specs?
39
+ definition.remotely!
40
+ else
41
+ definition.with_cache!
42
+ end
43
+
38
44
  specs = definition.specs
39
45
 
40
- install_from_specs specs
46
+ install_from_specs(specs)
41
47
  end
42
48
 
43
49
  private
@@ -89,14 +95,14 @@ module Bundler
89
95
  end
90
96
 
91
97
  def install_all_sources(names, version, source_list, source = nil)
92
- deps = names.map {|name| Dependency.new(name, version, { "source" => source }) }
98
+ deps = names.map {|name| Dependency.new(name, version, { "source" => source, "plugin" => true }) }
93
99
 
94
100
  Bundler.configure_gem_home_and_path(Plugin.root)
95
101
 
96
102
  Bundler.settings.temporary(deployment: false, frozen: false) do
97
103
  definition = Definition.new(nil, deps, source_list, true)
98
104
 
99
- install_definition(definition)
105
+ install_definition(definition, true)
100
106
  end
101
107
  end
102
108
 
@@ -110,6 +116,8 @@ module Bundler
110
116
  paths = {}
111
117
 
112
118
  specs.each do |spec|
119
+ next if spec.name == "bundler"
120
+
113
121
  spec.source.download(spec)
114
122
  spec.source.install(spec)
115
123