bundler 4.0.22 → 4.1.0.beta2

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 (200) 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 +41 -1
  11. data/lib/bundler/cli/config.rb +4 -2
  12. data/lib/bundler/cli/doctor/ssl.rb +4 -8
  13. data/lib/bundler/cli/gem.rb +0 -17
  14. data/lib/bundler/cli/info.rb +1 -1
  15. data/lib/bundler/cli/install.rb +4 -5
  16. data/lib/bundler/cli/lock.rb +15 -5
  17. data/lib/bundler/cli/open.rb +7 -1
  18. data/lib/bundler/cli/outdated.rb +16 -13
  19. data/lib/bundler/cli/pristine.rb +2 -1
  20. data/lib/bundler/cli/show.rb +5 -1
  21. data/lib/bundler/cli/update.rb +20 -11
  22. data/lib/bundler/cli.rb +15 -9
  23. data/lib/bundler/constants.rb +1 -1
  24. data/lib/bundler/definition.rb +102 -15
  25. data/lib/bundler/dependency.rb +4 -0
  26. data/lib/bundler/dsl.rb +137 -13
  27. data/lib/bundler/endpoint_specification.rb +51 -14
  28. data/lib/bundler/env.rb +7 -24
  29. data/lib/bundler/errors.rb +34 -5
  30. data/lib/bundler/fetcher/compact_index.rb +14 -5
  31. data/lib/bundler/fetcher/connection_pools.rb +150 -0
  32. data/lib/bundler/fetcher/downloader.rb +35 -16
  33. data/lib/bundler/fetcher.rb +8 -47
  34. data/lib/bundler/gem_helper.rb +1 -1
  35. data/lib/bundler/injector.rb +3 -3
  36. data/lib/bundler/inline.rb +44 -4
  37. data/lib/bundler/installer/parallel_installer.rb +27 -31
  38. data/lib/bundler/installer.rb +21 -7
  39. data/lib/bundler/lazy_specification.rb +45 -18
  40. data/lib/bundler/lockfile_generator.rb +24 -2
  41. data/lib/bundler/lockfile_parser.rb +44 -6
  42. data/lib/bundler/man/bundle-add.1 +7 -4
  43. data/lib/bundler/man/bundle-add.1.ronn +8 -4
  44. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  45. data/lib/bundler/man/bundle-cache.1 +2 -2
  46. data/lib/bundler/man/bundle-cache.1.ronn +2 -2
  47. data/lib/bundler/man/bundle-check.1 +1 -1
  48. data/lib/bundler/man/bundle-clean.1 +1 -1
  49. data/lib/bundler/man/bundle-config.1 +38 -6
  50. data/lib/bundler/man/bundle-config.1.ronn +143 -10
  51. data/lib/bundler/man/bundle-console.1 +1 -1
  52. data/lib/bundler/man/bundle-doctor.1 +1 -1
  53. data/lib/bundler/man/bundle-env.1 +1 -1
  54. data/lib/bundler/man/bundle-exec.1 +1 -1
  55. data/lib/bundler/man/bundle-fund.1 +1 -1
  56. data/lib/bundler/man/bundle-gem.1 +1 -1
  57. data/lib/bundler/man/bundle-help.1 +1 -1
  58. data/lib/bundler/man/bundle-info.1 +5 -2
  59. data/lib/bundler/man/bundle-info.1.ronn +4 -0
  60. data/lib/bundler/man/bundle-init.1 +1 -1
  61. data/lib/bundler/man/bundle-install.1 +2 -2
  62. data/lib/bundler/man/bundle-install.1.ronn +4 -4
  63. data/lib/bundler/man/bundle-issue.1 +1 -1
  64. data/lib/bundler/man/bundle-licenses.1 +1 -1
  65. data/lib/bundler/man/bundle-list.1 +1 -1
  66. data/lib/bundler/man/bundle-lock.1 +2 -2
  67. data/lib/bundler/man/bundle-lock.1.ronn +3 -2
  68. data/lib/bundler/man/bundle-open.1 +5 -2
  69. data/lib/bundler/man/bundle-open.1.ronn +4 -1
  70. data/lib/bundler/man/bundle-outdated.1 +1 -1
  71. data/lib/bundler/man/bundle-platform.1 +1 -1
  72. data/lib/bundler/man/bundle-plugin.1 +1 -1
  73. data/lib/bundler/man/bundle-pristine.1 +1 -1
  74. data/lib/bundler/man/bundle-remove.1 +1 -1
  75. data/lib/bundler/man/bundle-show.1 +5 -2
  76. data/lib/bundler/man/bundle-show.1.ronn +4 -0
  77. data/lib/bundler/man/bundle-update.1 +2 -2
  78. data/lib/bundler/man/bundle-update.1.ronn +2 -2
  79. data/lib/bundler/man/bundle-version.1 +1 -1
  80. data/lib/bundler/man/bundle.1 +1 -1
  81. data/lib/bundler/man/gemfile.5 +77 -1
  82. data/lib/bundler/man/gemfile.5.ronn +104 -0
  83. data/lib/bundler/match_metadata.rb +20 -0
  84. data/lib/bundler/match_platform.rb +25 -2
  85. data/lib/bundler/match_remote_metadata.rb +21 -6
  86. data/lib/bundler/materialization.rb +5 -2
  87. data/lib/bundler/override.rb +97 -0
  88. data/lib/bundler/plugin/dsl.rb +3 -5
  89. data/lib/bundler/plugin/events.rb +55 -13
  90. data/lib/bundler/plugin/index.rb +87 -11
  91. data/lib/bundler/plugin/installer/path.rb +1 -1
  92. data/lib/bundler/plugin/installer.rb +13 -5
  93. data/lib/bundler/plugin.rb +58 -30
  94. data/lib/bundler/remote_specification.rb +6 -3
  95. data/lib/bundler/resolver/base.rb +2 -1
  96. data/lib/bundler/resolver/incompatibility.rb +1 -1
  97. data/lib/bundler/resolver.rb +97 -23
  98. data/lib/bundler/ruby_version.rb +0 -2
  99. data/lib/bundler/rubygems_ext.rb +71 -1
  100. data/lib/bundler/rubygems_gem_installer.rb +41 -2
  101. data/lib/bundler/rubygems_integration.rb +7 -2
  102. data/lib/bundler/runtime.rb +69 -2
  103. data/lib/bundler/settings.rb +383 -56
  104. data/lib/bundler/shared_helpers.rb +2 -1
  105. data/lib/bundler/source/git/git_proxy.rb +31 -2
  106. data/lib/bundler/source/git.rb +49 -13
  107. data/lib/bundler/source/path/installer.rb +1 -1
  108. data/lib/bundler/source/rubygems/remote.rb +10 -5
  109. data/lib/bundler/source/rubygems.rb +48 -12
  110. data/lib/bundler/source/rubygems_aggregate.rb +1 -1
  111. data/lib/bundler/source_map.rb +7 -3
  112. data/lib/bundler/spec_set.rb +23 -7
  113. data/lib/bundler/stub_specification.rb +2 -1
  114. data/lib/bundler/templates/newgem/Gemfile.tt +4 -4
  115. data/lib/bundler/templates/newgem/newgem.gemspec.tt +3 -3
  116. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
  117. data/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +1 -1
  118. data/lib/bundler/ui/shell.rb +0 -4
  119. data/lib/bundler/ui/silent.rb +0 -4
  120. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +35 -2
  121. data/lib/bundler/vendor/thor/lib/thor/base.rb +2 -1
  122. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +14 -6
  123. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +2 -0
  124. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  125. data/lib/bundler/vendor/thor/lib/thor.rb +34 -1
  126. data/lib/bundler/vendored_pub_grub.rb +5 -2
  127. data/lib/bundler/vendored_securerandom.rb +11 -8
  128. data/lib/bundler/vendored_uri.rb +14 -14
  129. data/lib/bundler/version.rb +1 -1
  130. data/lib/bundler/worker.rb +3 -2
  131. data/lib/bundler.rb +1 -1
  132. data/lib/rubygems/compact_index_client/cache.rb +122 -0
  133. data/lib/rubygems/compact_index_client/cache_file.rb +147 -0
  134. data/lib/rubygems/compact_index_client/http_fetcher.rb +90 -0
  135. data/lib/rubygems/compact_index_client/parser.rb +90 -0
  136. data/lib/rubygems/compact_index_client/updater.rb +113 -0
  137. data/lib/rubygems/compact_index_client.rb +111 -0
  138. data/lib/rubygems/cooldown_settings.rb +57 -0
  139. data/lib/rubygems/credential_store/native/linux.rb +97 -0
  140. data/lib/rubygems/credential_store/native/macos.rb +88 -0
  141. data/lib/rubygems/credential_store/native/windows.rb +130 -0
  142. data/lib/rubygems/credential_store.rb +332 -0
  143. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/assignment.rb +1 -1
  144. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +7 -7
  145. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/failure_writer.rb +1 -1
  146. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/incompatibility.rb +4 -4
  147. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/package.rb +1 -1
  148. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/partial_solution.rb +1 -1
  149. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/rubygems.rb +3 -3
  150. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/solve_failure.rb +1 -1
  151. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/static_package_source.rb +3 -3
  152. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/strategy.rb +2 -2
  153. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/term.rb +1 -1
  154. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version.rb +1 -1
  155. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_constraint.rb +3 -3
  156. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_range.rb +1 -1
  157. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_solver.rb +2 -2
  158. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_union.rb +1 -1
  159. data/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb +57 -0
  160. data/lib/{bundler → rubygems}/vendor/securerandom/lib/securerandom.rb +10 -6
  161. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/common.rb +119 -119
  162. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/file.rb +13 -13
  163. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ftp.rb +24 -24
  164. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/generic.rb +132 -132
  165. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/http.rb +18 -18
  166. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/https.rb +4 -4
  167. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldap.rb +14 -14
  168. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldaps.rb +4 -4
  169. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/mailto.rb +21 -21
  170. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc2396_parser.rb +39 -39
  171. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc3986_parser.rb +14 -14
  172. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/version.rb +1 -1
  173. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ws.rb +12 -12
  174. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/wss.rb +4 -4
  175. data/lib/{bundler → rubygems}/vendor/uri/lib/uri.rb +35 -31
  176. data/lib/rubygems/yaml_serializer.rb +880 -0
  177. metadata +391 -381
  178. data/CHANGELOG.md +0 -5801
  179. data/LICENSE.md +0 -22
  180. data/README.md +0 -58
  181. data/lib/bundler/compact_index_client/cache.rb +0 -107
  182. data/lib/bundler/compact_index_client/cache_file.rb +0 -148
  183. data/lib/bundler/compact_index_client/parser.rb +0 -87
  184. data/lib/bundler/compact_index_client/updater.rb +0 -105
  185. data/lib/bundler/compact_index_client.rb +0 -92
  186. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +0 -227
  187. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +0 -3
  188. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +0 -56
  189. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +0 -230
  190. data/lib/bundler/vendor/net-http-persistent/README.rdoc +0 -82
  191. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +0 -41
  192. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +0 -65
  193. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +0 -80
  194. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +0 -1153
  195. data/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +0 -31
  196. data/lib/bundler/vendored_persistent.rb +0 -11
  197. data/lib/bundler/yaml_serializer.rb +0 -98
  198. /data/lib/{bundler → rubygems}/vendor/pub_grub/LICENSE.txt +0 -0
  199. /data/lib/{bundler → rubygems}/vendor/securerandom/COPYING +0 -0
  200. /data/lib/{bundler → rubygems}/vendor/uri/COPYING +0 -0
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-REMOVE" "1" "April 2026" ""
3
+ .TH "BUNDLE\-REMOVE" "1" "May 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-remove\fR \- Removes gems from the Gemfile
6
6
  .SH "SYNOPSIS"
@@ -1,10 +1,10 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-SHOW" "1" "April 2026" ""
3
+ .TH "BUNDLE\-SHOW" "1" "May 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem
6
6
  .SH "SYNOPSIS"
7
- \fBbundle show\fR [GEM] [\-\-paths]
7
+ \fBbundle show\fR [GEM] [\-\-paths] [\-\-exact\-match]
8
8
  .SH "DESCRIPTION"
9
9
  Without the [GEM] option, \fBshow\fR will print a list of the names and versions of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by name\.
10
10
  .P
@@ -13,4 +13,7 @@ Calling show with [GEM] will list the exact location of that gem on your machine
13
13
  .TP
14
14
  \fB\-\-paths\fR
15
15
  List the paths of all gems that are required by your [\fBGemfile(5)\fR][Gemfile(5)], sorted by gem name\.
16
+ .TP
17
+ \fB\-\-exact\-match\fR
18
+ Only match gems whose names exactly match the given name\.
16
19
 
@@ -5,6 +5,7 @@ bundle-show(1) -- Shows all the gems in your bundle, or the path to a gem
5
5
 
6
6
  `bundle show` [GEM]
7
7
  [--paths]
8
+ [--exact-match]
8
9
 
9
10
  ## DESCRIPTION
10
11
 
@@ -19,3 +20,6 @@ machine.
19
20
  * `--paths`:
20
21
  List the paths of all gems that are required by your [`Gemfile(5)`][Gemfile(5)],
21
22
  sorted by gem name.
23
+
24
+ * `--exact-match`:
25
+ Only match gems whose names exactly match the given name.
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-UPDATE" "1" "April 2026" ""
3
+ .TH "BUNDLE\-UPDATE" "1" "May 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-update\fR \- Update your gems to the latest available versions
6
6
  .SH "SYNOPSIS"
@@ -66,7 +66,7 @@ Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR
66
66
  Use bundle install conservative update behavior and do not allow indirect dependencies to be updated\.
67
67
  .TP
68
68
  \fB\-\-cooldown=<number>\fR
69
- Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding any per\-source or global configuration\. Combine with \fB\-\-conservative\fR to minimize transitive churn when bypassing cooldown for an urgent update\. See \fBcooldown\fR in bundle\-config(1)\.
69
+ Only consider gem versions published at least \fInumber\fR days ago when resolving\. Pass \fB0\fR to disable cooldown for this run, overriding every other cooldown setting, RubyGems' own included\. Combine with \fB\-\-conservative\fR to minimize transitive churn when bypassing cooldown for an urgent update\. See \fBcooldown\fR in bundle\-config(1)\.
70
70
  .SH "UPDATING ALL GEMS"
71
71
  If you run \fBbundle update \-\-all\fR, bundler will ignore any previously installed gems and resolve all dependencies again based on the latest versions of all gems available in the sources\.
72
72
  .P
@@ -96,8 +96,8 @@ gem.
96
96
 
97
97
  * `--cooldown=<number>`:
98
98
  Only consider gem versions published at least <number> days ago when
99
- resolving. Pass `0` to disable cooldown for this run, overriding any
100
- per-source or global configuration. Combine with `--conservative` to
99
+ resolving. Pass `0` to disable cooldown for this run, overriding every
100
+ other cooldown setting, RubyGems' own included. Combine with `--conservative` to
101
101
  minimize transitive churn when bypassing cooldown for an urgent
102
102
  update. See `cooldown` in bundle-config(1).
103
103
 
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE\-VERSION" "1" "April 2026" ""
3
+ .TH "BUNDLE\-VERSION" "1" "May 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\-version\fR \- Prints Bundler version information
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "BUNDLE" "1" "April 2026" ""
3
+ .TH "BUNDLE" "1" "May 2026" ""
4
4
  .SH "NAME"
5
5
  \fBbundle\fR \- Ruby Dependency Management
6
6
  .SH "SYNOPSIS"
@@ -1,6 +1,6 @@
1
1
  .\" generated with Ronn-NG/v0.10.1
2
2
  .\" http://github.com/apjanke/ronn-ng/tree/0.10.1
3
- .TH "GEMFILE" "5" "April 2026" ""
3
+ .TH "GEMFILE" "5" "May 2026" ""
4
4
  .SH "NAME"
5
5
  \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs
6
6
  .SH "SYNOPSIS"
@@ -295,6 +295,13 @@ gem "rails", git: "https://github\.com/rails/rails\.git", ref: "4aded"
295
295
  .TP
296
296
  \fBsubmodules\fR
297
297
  For reference, a git submodule \fIhttps://git\-scm\.com/book/en/v2/Git\-Tools\-Submodules\fR lets you have another git repository within a subfolder of your repository\. Specify \fBsubmodules: true\fR to cause bundler to expand any submodules included in the git repository
298
+ .TP
299
+ \fBsparse_checkout\fR
300
+ Specify a directory, or an array of directories, to include when checking out a git repository\. Uses git's sparse\-checkout feature (requires git 2\.25+) to only check out the specified directories, reducing disk usage for large repos\. Unless \fBglob\fR is given, the \fB\.gemspec\fR is looked up within those directories\.
301
+ .IP
302
+ gem "foo", git: "https://github\.com/org/monorepo\.git", sparse_checkout: "packages/foo"
303
+ .IP
304
+ Files at the top level of the repository are always checked out\. On git versions below 2\.25, the entire repository will be checked out with a warning\.
298
305
  .P
299
306
  If a git repository contains multiple \fB\.gemspecs\fR, each \fB\.gemspec\fR represents a gem located at the same place in the file system as the \fB\.gemspec\fR\.
300
307
  .IP "" 4
@@ -471,6 +478,75 @@ eval_gemfile "another\.gemfile"
471
478
  .IP "" 0
472
479
  .P
473
480
  This can be useful to run tests against multiple combinations of dependencies, or to load per\-developer gems from an untracked gemfile\.
481
+ .SH "OVERRIDE"
482
+ The \fBoverride\fR directive rewrites a constraint on another gem before resolution runs\. It targets the common case where an upstream gem's published metadata is too narrow on the current project's machine \-\- a stale upper bound, an unwanted floor, or a transitive pin that has to be lifted\.
483
+ .IP "" 4
484
+ .nf
485
+ override <target>, <field>: <operation>
486
+ .fi
487
+ .IP "" 0
488
+ .P
489
+ \fB<target>\fR is a gem name string or \fB:all\fR\. \fB<field>\fR is one of \fBversion:\fR, \fBrequired_ruby_version:\fR, or \fBrequired_rubygems_version:\fR\. \fB<operation>\fR is one of:
490
+ .IP "\(bu" 4
491
+ a version requirement string (e\.g\. \fB">= 8\.0"\fR), which \fBreplaces\fR the target's requirement absolutely\. The original requirement, both direct and transitive, is discarded in favour of the override\.
492
+ .IP "\(bu" 4
493
+ \fB:ignore_upper\fR, which removes upper\-bound operators (\fB<\fR and \fB<=\fR) from the existing requirement and folds \fB~>\fR into its lower bound (\fB~> 1\.5\fR becomes \fB>= 1\.5\fR)\. Other operators, including \fB!=\fR, are preserved\.
494
+ .IP "\(bu" 4
495
+ \fBnil\fR, which collapses the requirement to \fB>= 0\fR (no constraint at all)\.
496
+ .IP "" 0
497
+ .P
498
+ \fB:all\fR only applies to \fBrequired_ruby_version:\fR and \fBrequired_rubygems_version:\fR\. A per\-gem override on the same field takes precedence over an \fB:all\fR override\. \fB:all + version:\fR is rejected: version requirements only make sense per gem\.
499
+ .P
500
+ Declaring the same \fBtarget\fR and \fBfield\fR twice is an error\.
501
+ .IP "" 4
502
+ .nf
503
+ source "https://rubygems\.org"
504
+
505
+ # Force every reference to "rails" \-\- direct or transitive \-\- to >= 8\.0\.
506
+ override "rails", version: ">= 8\.0"
507
+
508
+ # Strip the upper bound on nokogiri\.
509
+ override "nokogiri", version: :ignore_upper
510
+
511
+ # Drop the version pin on legacy entirely\.
512
+ override "legacy", version: nil
513
+
514
+ # Loosen every gem's required_ruby_version upper bound\.
515
+ override :all, required_ruby_version: :ignore_upper
516
+
517
+ # Override one specific gem's required_rubygems_version\.
518
+ override "tricky", required_rubygems_version: nil
519
+
520
+ gem "rails", "~> 7\.0"
521
+ .fi
522
+ .IP "" 0
523
+ .P
524
+ The override only affects resolution and the install\-time Ruby/RubyGems compatibility checks; \fBGemfile\.lock\fR continues to reflect the resolved versions, not the rewritten requirements\. When resolution still fails, Bundler appends the active overrides (with their Gemfile location) to the error message so it is clear which override shaped the constraint set\.
525
+ .SS "DROPPING OR REPLACING A DEPENDENCY"
526
+ \fBfrom:\fR and \fBto:\fR rewrite a single dependency of a single gem:
527
+ .IP "" 4
528
+ .nf
529
+ override <target>, from: <gem>, to: nil
530
+ override <target>, from: <gem>, to: <replacement>, version: <requirement>
531
+ .fi
532
+ .IP "" 0
533
+ .P
534
+ \fBto: nil\fR removes the dependency of \fB<gem>\fR on \fB<target>\fR, so \fB<target>\fR is not installed unless something else still requires it\. \fBto: <replacement>\fR makes \fB<gem>\fR depend on \fB<replacement>\fR instead of \fB<target>\fR\. The requirement \fB<gem>\fR put on \fB<target>\fR is discarded, and the optional \fBversion:\fR gives the replacement its own\. Both forms apply whether \fB<gem>\fR is a direct or a transitive dependency\.
535
+ .P
536
+ \fBfrom:\fR is required, and so is \fBto:\fR once \fBfrom:\fR is given\. To rewrite the same dependency of several gems, write one \fBoverride\fR per gem\. It is an error to declare the same \fB<target>\fR and \fBfrom:\fR twice, to drop a gem that the Gemfile requires directly, or to replace a gem that another gem still requires, since both would then be in the bundle\.
537
+ .IP "" 4
538
+ .nf
539
+ # jekyll only loads em\-websocket for `jekyll serve \-\-livereload`\.
540
+ override "em\-websocket", from: "jekyll", to: nil
541
+
542
+ # Use an API\-compatible gem that provides the same files\.
543
+ override "foo", from: "bar", to: "foo\-lite"
544
+ .fi
545
+ .IP "" 0
546
+ .P
547
+ Bundler does not check what a gem loads at runtime\. If \fB<gem>\fR requires \fB<target>\fR unconditionally, dropping it makes that require raise \fBLoadError\fR, as with jekyll's dependency on jekyll\-sass\-converter or the adapters that faraday 1\.x requires on load\. A replacement only works when it provides the files \fB<gem>\fR requires, and it does not take over the name of \fB<target>\fR: \fBGem\.loaded_specs\fR has no entry for \fB<target>\fR, and \fBgem "<target>"\fR fails\.
548
+ .P
549
+ \fBGemfile\.lock\fR keeps listing \fB<target>\fR under \fB<gem>\fR as the gem publishes it, while the locked gems leave \fB<target>\fR out or include \fB<replacement>\fR\. A frozen install accepts that lockfile as long as the Gemfile still has the override\. Removing the override makes Bundler resolve \fB<target>\fR again\.
474
550
  .SH "SOURCE PRIORITY"
475
551
  When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
476
552
  .IP "1." 4
@@ -359,6 +359,20 @@ Git repositories support a number of additional options.
359
359
  Specify `submodules: true` to cause bundler to expand any
360
360
  submodules included in the git repository
361
361
 
362
+ * `sparse_checkout`:
363
+ Specify a directory, or an array of directories, to include when
364
+ checking out a git repository. Uses git's sparse-checkout feature
365
+ (requires git 2.25+) to only check out the specified directories,
366
+ reducing disk usage for large repos. Unless `glob` is given, the
367
+ `.gemspec` is looked up within those directories.
368
+
369
+ gem "foo", git: "https://github.com/org/monorepo.git",
370
+ sparse_checkout: "packages/foo"
371
+
372
+ Files at the top level of the repository are always checked out.
373
+ On git versions below 2.25, the entire repository will be checked
374
+ out with a warning.
375
+
362
376
  If a git repository contains multiple `.gemspecs`, each `.gemspec`
363
377
  represents a gem located at the same place in the file system as
364
378
  the `.gemspec`.
@@ -562,6 +576,96 @@ call.
562
576
  This can be useful to run tests against multiple combinations of dependencies,
563
577
  or to load per-developer gems from an untracked gemfile.
564
578
 
579
+ ## OVERRIDE
580
+
581
+ The `override` directive rewrites a constraint on another gem before
582
+ resolution runs. It targets the common case where an upstream gem's
583
+ published metadata is too narrow on the current project's machine -- a stale
584
+ upper bound, an unwanted floor, or a transitive pin that has to be lifted.
585
+
586
+ override <target>, <field>: <operation>
587
+
588
+ `<target>` is a gem name string or `:all`. `<field>` is one of `version:`,
589
+ `required_ruby_version:`, or `required_rubygems_version:`. `<operation>` is
590
+ one of:
591
+
592
+ * a version requirement string (e.g. `">= 8.0"`), which **replaces** the
593
+ target's requirement absolutely. The original requirement, both direct
594
+ and transitive, is discarded in favour of the override.
595
+ * `:ignore_upper`, which removes upper-bound operators (`<` and `<=`) from
596
+ the existing requirement and folds `~>` into its lower bound (`~> 1.5`
597
+ becomes `>= 1.5`). Other operators, including `!=`, are preserved.
598
+ * `nil`, which collapses the requirement to `>= 0` (no constraint at all).
599
+
600
+ `:all` only applies to `required_ruby_version:` and `required_rubygems_version:`.
601
+ A per-gem override on the same field takes precedence over an `:all` override.
602
+ `:all + version:` is rejected: version requirements only make sense per gem.
603
+
604
+ Declaring the same `target` and `field` twice is an error.
605
+
606
+ source "https://rubygems.org"
607
+
608
+ # Force every reference to "rails" -- direct or transitive -- to >= 8.0.
609
+ override "rails", version: ">= 8.0"
610
+
611
+ # Strip the upper bound on nokogiri.
612
+ override "nokogiri", version: :ignore_upper
613
+
614
+ # Drop the version pin on legacy entirely.
615
+ override "legacy", version: nil
616
+
617
+ # Loosen every gem's required_ruby_version upper bound.
618
+ override :all, required_ruby_version: :ignore_upper
619
+
620
+ # Override one specific gem's required_rubygems_version.
621
+ override "tricky", required_rubygems_version: nil
622
+
623
+ gem "rails", "~> 7.0"
624
+
625
+ The override only affects resolution and the install-time Ruby/RubyGems
626
+ compatibility checks; `Gemfile.lock` continues to reflect the resolved
627
+ versions, not the rewritten requirements. When resolution still fails,
628
+ Bundler appends the active overrides (with their Gemfile location) to the
629
+ error message so it is clear which override shaped the constraint set.
630
+
631
+ ### DROPPING OR REPLACING A DEPENDENCY
632
+
633
+ `from:` and `to:` rewrite a single dependency of a single gem:
634
+
635
+ override <target>, from: <gem>, to: nil
636
+ override <target>, from: <gem>, to: <replacement>, version: <requirement>
637
+
638
+ `to: nil` removes the dependency of `<gem>` on `<target>`, so `<target>` is
639
+ not installed unless something else still requires it. `to: <replacement>`
640
+ makes `<gem>` depend on `<replacement>` instead of `<target>`. The requirement
641
+ `<gem>` put on `<target>` is discarded, and the optional `version:` gives the
642
+ replacement its own. Both forms apply whether `<gem>` is a direct or a
643
+ transitive dependency.
644
+
645
+ `from:` is required, and so is `to:` once `from:` is given. To rewrite the
646
+ same dependency of several gems, write one `override` per gem. It is an error
647
+ to declare the same `<target>` and `from:` twice, to drop a gem that the
648
+ Gemfile requires directly, or to replace a gem that another gem still
649
+ requires, since both would then be in the bundle.
650
+
651
+ # jekyll only loads em-websocket for `jekyll serve --livereload`.
652
+ override "em-websocket", from: "jekyll", to: nil
653
+
654
+ # Use an API-compatible gem that provides the same files.
655
+ override "foo", from: "bar", to: "foo-lite"
656
+
657
+ Bundler does not check what a gem loads at runtime. If `<gem>` requires
658
+ `<target>` unconditionally, dropping it makes that require raise `LoadError`,
659
+ as with jekyll's dependency on jekyll-sass-converter or the adapters that
660
+ faraday 1.x requires on load. A replacement only works when it provides the
661
+ files `<gem>` requires, and it does not take over the name of `<target>`:
662
+ `Gem.loaded_specs` has no entry for `<target>`, and `gem "<target>"` fails.
663
+
664
+ `Gemfile.lock` keeps listing `<target>` under `<gem>` as the gem publishes it,
665
+ while the locked gems leave `<target>` out or include `<replacement>`. A
666
+ frozen install accepts that lockfile as long as the Gemfile still has the
667
+ override. Removing the override makes Bundler resolve `<target>` again.
668
+
565
669
  ## SOURCE PRIORITY
566
670
 
567
671
  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,12 +25,14 @@ 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
 
31
32
  def dependencies
32
- (materialized_spec || specs.first).runtime_dependencies.map {|d| [d, platform] }
33
+ spec = materialized_spec || specs.first
34
+ overrides = specs.first.overrides if specs.first.is_a?(LazySpecification)
35
+ Override.rewrite_dependencies(overrides, spec.name, spec.runtime_dependencies).map {|d| [d, platform] }
33
36
  end
34
37
 
35
38
  def materialized_spec
@@ -0,0 +1,97 @@
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
+ # Drops or replaces the dependencies of the gem named `from` that a
13
+ # `from:`/`to:` override targets. The requirement `from` put on the
14
+ # replaced gem is discarded.
15
+ def self.rewrite_dependencies(overrides, from, dependencies)
16
+ return dependencies if overrides.nil? || overrides.none? {|o| o.from == from }
17
+
18
+ dependencies.filter_map do |dep|
19
+ override = overrides.find {|o| o.from == from && o.target == dep.name }
20
+ next dep unless override
21
+ next unless override.operation
22
+ Gem::Dependency.new(override.operation, *Array(override.requirement))
23
+ end
24
+ end
25
+
26
+ # Attach the given overrides onto every LazySpecification in `specs` so
27
+ # downstream consumers (LazySpecification#choose_compatible, the install-
28
+ # time compatibility check, etc.) can read the override list off the spec
29
+ # itself. Non-LazySpec entries (StubSpecification, Gem::Specification, ...)
30
+ # are left untouched.
31
+ def self.attach(specs, overrides)
32
+ return if overrides.nil? || overrides.empty?
33
+ specs.each {|s| s.overrides = overrides if s.is_a?(LazySpecification) }
34
+ end
35
+
36
+ attr_reader :target, :field, :operation, :from, :requirement, :source_location
37
+
38
+ def initialize(target, field, operation, from: nil, requirement: nil, source_location: nil)
39
+ @target = target
40
+ @field = field
41
+ @operation = operation
42
+ @from = from
43
+ @requirement = requirement
44
+ @source_location = source_location
45
+ end
46
+
47
+ def source_location_label
48
+ return nil unless @source_location
49
+ "#{File.basename(@source_location.path)}:#{@source_location.lineno}"
50
+ end
51
+
52
+ def to_s
53
+ options = if @from
54
+ ["from: #{@from.inspect}", "to: #{@operation.inspect}", *("version: #{@requirement.inspect}" if @requirement)].join(", ")
55
+ else
56
+ "#{@field}: #{@operation.inspect}"
57
+ end
58
+ location = source_location_label
59
+ "override #{@target == :all ? ":all" : @target.inspect}, #{options}#{" (declared at #{location})" if location}"
60
+ end
61
+
62
+ def apply_to(requirement)
63
+ raise ArgumentError, "#{self} rewrites a dependency and has no requirement to apply" if @from
64
+
65
+ case operation
66
+ when nil
67
+ Gem::Requirement.default
68
+ when :ignore_upper
69
+ remove_upper_bounds(requirement)
70
+ when String
71
+ Gem::Requirement.new(operation)
72
+ else
73
+ raise ArgumentError, "unsupported override operation: #{operation.inspect}"
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def remove_upper_bounds(requirement)
80
+ return Gem::Requirement.default if requirement.nil? || requirement.none?
81
+
82
+ preserved = requirement.requirements.filter_map do |op, version|
83
+ if UPPER_BOUND_OPERATORS.include?(op)
84
+ nil
85
+ elsif op == "~>"
86
+ [">=", version]
87
+ else
88
+ [op, version]
89
+ end
90
+ end
91
+
92
+ return Gem::Requirement.default if preserved.empty?
93
+
94
+ Gem::Requirement.new(preserved.map {|op, v| "#{op} #{v}" })
95
+ end
96
+ end
97
+ 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)