bundler 4.1.0.beta1 → 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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/bundler/build_metadata.rb +2 -2
  3. data/lib/bundler/cli/common.rb +4 -0
  4. data/lib/bundler/cli/doctor/ssl.rb +4 -8
  5. data/lib/bundler/cli/info.rb +1 -1
  6. data/lib/bundler/cli/lock.rb +14 -3
  7. data/lib/bundler/cli/open.rb +7 -1
  8. data/lib/bundler/cli/outdated.rb +8 -10
  9. data/lib/bundler/cli/platform.rb +15 -1
  10. data/lib/bundler/cli/show.rb +5 -1
  11. data/lib/bundler/cli/update.rb +1 -1
  12. data/lib/bundler/cli.rb +22 -7
  13. data/lib/bundler/constants.rb +1 -1
  14. data/lib/bundler/definition.rb +64 -14
  15. data/lib/bundler/dsl.rb +61 -3
  16. data/lib/bundler/fetcher/downloader.rb +5 -1
  17. data/lib/bundler/gem_helper.rb +1 -1
  18. data/lib/bundler/installer/parallel_installer.rb +2 -1
  19. data/lib/bundler/installer.rb +5 -1
  20. data/lib/bundler/lazy_specification.rb +1 -1
  21. data/lib/bundler/lockfile_parser.rb +1 -1
  22. data/lib/bundler/man/bundle-info.1 +4 -1
  23. data/lib/bundler/man/bundle-info.1.ronn +4 -0
  24. data/lib/bundler/man/bundle-lock.1 +2 -2
  25. data/lib/bundler/man/bundle-lock.1.ronn +4 -3
  26. data/lib/bundler/man/bundle-open.1 +4 -1
  27. data/lib/bundler/man/bundle-open.1.ronn +4 -1
  28. data/lib/bundler/man/bundle-outdated.1 +1 -1
  29. data/lib/bundler/man/bundle-outdated.1.ronn +1 -1
  30. data/lib/bundler/man/bundle-show.1 +4 -1
  31. data/lib/bundler/man/bundle-show.1.ronn +4 -0
  32. data/lib/bundler/man/bundle-update.1 +3 -3
  33. data/lib/bundler/man/bundle-update.1.ronn +5 -3
  34. data/lib/bundler/man/gemfile.5 +33 -1
  35. data/lib/bundler/man/gemfile.5.ronn +53 -2
  36. data/lib/bundler/materialization.rb +3 -1
  37. data/lib/bundler/override.rb +30 -2
  38. data/lib/bundler/resolver.rb +28 -4
  39. data/lib/bundler/self_manager.rb +15 -9
  40. data/lib/bundler/settings.rb +10 -26
  41. data/lib/bundler/source/git/git_proxy.rb +39 -2
  42. data/lib/bundler/source/git.rb +34 -7
  43. data/lib/bundler/source/rubygems_aggregate.rb +1 -1
  44. data/lib/bundler/source_map.rb +7 -3
  45. data/lib/bundler/spec_set.rb +8 -4
  46. data/lib/bundler/templates/newgem/ext/newgem/Cargo.toml.tt +1 -1
  47. data/lib/bundler/version.rb +1 -1
  48. data/lib/bundler.rb +1 -3
  49. data/lib/rubygems/compact_index_client/http_fetcher.rb +5 -3
  50. metadata +391 -390
@@ -4,7 +4,7 @@
4
4
  .SH "NAME"
5
5
  \fBbundle\-info\fR \- Show information for the given gem in your bundle
6
6
  .SH "SYNOPSIS"
7
- \fBbundle info\fR [GEM_NAME] [\-\-path] [\-\-version]
7
+ \fBbundle info\fR [GEM_NAME] [\-\-path] [\-\-version] [\-\-exact\-match]
8
8
  .SH "DESCRIPTION"
9
9
  Given a gem name present in your bundle, print the basic information about it such as homepage, version, path and summary\.
10
10
  .SH "OPTIONS"
@@ -14,4 +14,7 @@ Print the path of the given gem
14
14
  .TP
15
15
  \fB\-\-version\fR
16
16
  Print gem version
17
+ .TP
18
+ \fB\-\-exact\-match\fR
19
+ Only match gems whose names exactly match the given name\.
17
20
 
@@ -6,6 +6,7 @@ bundle-info(1) -- Show information for the given gem in your bundle
6
6
  `bundle info` [GEM_NAME]
7
7
  [--path]
8
8
  [--version]
9
+ [--exact-match]
9
10
 
10
11
  ## DESCRIPTION
11
12
 
@@ -19,3 +20,6 @@ Given a gem name present in your bundle, print the basic information about it
19
20
 
20
21
  * `--version`:
21
22
  Print gem version
23
+
24
+ * `--exact-match`:
25
+ Only match gems whose names exactly match the given name.
@@ -13,7 +13,7 @@ Lock the gems specified in Gemfile\.
13
13
  Ignores the existing lockfile\. Resolve then updates lockfile\. Taking a list of gems or updating all gems if no list is given\.
14
14
  .TP
15
15
  \fB\-\-bundler[=BUNDLER]\fR
16
- Update the locked version of bundler to the given version or the latest version if no version is given\.
16
+ Update the locked version of bundler\. BUNDLER can be a version such as \fB4\.0\.20\fR, or a requirement such as \fB"> 0\.a"\fR\. With no argument, update to the latest released version, which never selects a prerelease\.
17
17
  .TP
18
18
  \fB\-\-local\fR
19
19
  Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems' cache or in \fBvendor/cache\fR\. Note that if a appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\.
@@ -49,7 +49,7 @@ If updating, prefer updating only to next patch version\.
49
49
  If updating, prefer updating only to next minor version\.
50
50
  .TP
51
51
  \fB\-\-major\fR
52
- If updating, prefer updating to next major version (default)\.
52
+ If updating, prefer updating to latest major version (default)\.
53
53
  .TP
54
54
  \fB\-\-pre\fR
55
55
  If updating, always choose the highest allowed version, regardless of prerelease status\.
@@ -33,8 +33,9 @@ Lock the gems specified in Gemfile.
33
33
  of gems or updating all gems if no list is given.
34
34
 
35
35
  * `--bundler[=BUNDLER]`:
36
- Update the locked version of bundler to the given version or the latest
37
- version if no version is given.
36
+ Update the locked version of bundler. BUNDLER can be a version such as
37
+ `4.0.20`, or a requirement such as `"> 0.a"`. With no argument, update to the
38
+ latest released version, which never selects a prerelease.
38
39
 
39
40
  * `--local`:
40
41
  Do not attempt to connect to `rubygems.org`. Instead, Bundler will use the
@@ -74,7 +75,7 @@ Lock the gems specified in Gemfile.
74
75
  If updating, prefer updating only to next minor version.
75
76
 
76
77
  * `--major`:
77
- If updating, prefer updating to next major version (default).
78
+ If updating, prefer updating to latest major version (default).
78
79
 
79
80
  * `--pre`:
80
81
  If updating, always choose the highest allowed version, regardless of prerelease status.
@@ -4,7 +4,7 @@
4
4
  .SH "NAME"
5
5
  \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle
6
6
  .SH "SYNOPSIS"
7
- \fBbundle open\fR [GEM] [\-\-path=PATH]
7
+ \fBbundle open\fR [GEM] [\-\-path=PATH] [\-\-exact\-match]
8
8
  .SH "DESCRIPTION"
9
9
  Opens the source directory of the provided GEM in your editor\.
10
10
  .P
@@ -29,4 +29,7 @@ Will open the README\.md file of the 'rack' gem source in your bundle\.
29
29
  .TP
30
30
  \fB\-\-path[=PATH]\fR
31
31
  Specify GEM source relative path to open\.
32
+ .TP
33
+ \fB\-\-exact\-match\fR
34
+ Only match gems whose names exactly match the given name\.
32
35
 
@@ -3,7 +3,7 @@ bundle-open(1) -- Opens the source directory for a gem in your bundle
3
3
 
4
4
  ## SYNOPSIS
5
5
 
6
- `bundle open` [GEM] [--path=PATH]
6
+ `bundle open` [GEM] [--path=PATH] [--exact-match]
7
7
 
8
8
  ## DESCRIPTION
9
9
 
@@ -26,3 +26,6 @@ Will open the README.md file of the 'rack' gem source in your bundle.
26
26
 
27
27
  * `--path[=PATH]`:
28
28
  Specify GEM source relative path to open.
29
+
30
+ * `--exact-match`:
31
+ Only match gems whose names exactly match the given name.
@@ -37,7 +37,7 @@ List gems organized by groups\.
37
37
  Prefer updating only to next minor version\.
38
38
  .TP
39
39
  \fB\-\-major\fR
40
- Prefer updating to next major version (default)\.
40
+ Prefer updating to latest major version (default)\.
41
41
  .TP
42
42
  \fB\-\-patch\fR
43
43
  Prefer updating only to next patch version\.
@@ -55,7 +55,7 @@ are up to date, Bundler will exit with a status of 0. Otherwise, it will exit 1.
55
55
  Prefer updating only to next minor version.
56
56
 
57
57
  * `--major`:
58
- Prefer updating to next major version (default).
58
+ Prefer updating to latest major version (default).
59
59
 
60
60
  * `--patch`:
61
61
  Prefer updating only to next patch version.
@@ -4,7 +4,7 @@
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.
@@ -27,7 +27,7 @@ Do not attempt to fetch gems remotely and use the gem cache instead\.
27
27
  Update the locked version of Ruby to the current version of Ruby\.
28
28
  .TP
29
29
  \fB\-\-bundler[=BUNDLER]\fR
30
- Update the locked version of bundler to the invoked bundler version\.
30
+ Update the locked version of bundler\. BUNDLER can be a version such as \fB4\.0\.20\fR, or a requirement such as \fB"> 0\.a"\fR\. With no argument, update to the latest released version, which never selects a prerelease\.
31
31
  .TP
32
32
  \fB\-\-force\fR, \fB\-\-redownload\fR
33
33
  Force reinstalling every gem, even if already installed\.
@@ -54,7 +54,7 @@ Prefer updating only to next patch version\.
54
54
  Prefer updating only to next minor version\.
55
55
  .TP
56
56
  \fB\-\-major\fR
57
- Prefer updating to next major version (default)\.
57
+ Prefer updating to latest major version (default)\.
58
58
  .TP
59
59
  \fB\-\-pre\fR
60
60
  Always choose the highest allowed version, regardless of prerelease status\.
@@ -175,7 +175,7 @@ Prefer updating only to next patch version\.
175
175
  Prefer updating only to next minor version\.
176
176
  .TP
177
177
  \fB\-\-major\fR
178
- Prefer updating to next major version (default)\.
178
+ Prefer updating to latest major version (default)\.
179
179
  .TP
180
180
  \fB\-\-strict\fR
181
181
  Do not allow any gem to be updated past latest \fB\-\-patch\fR | \fB\-\-minor\fR | \fB\-\-major\fR\.
@@ -53,7 +53,9 @@ gem.
53
53
  Update the locked version of Ruby to the current version of Ruby.
54
54
 
55
55
  * `--bundler[=BUNDLER]`:
56
- Update the locked version of bundler to the invoked bundler version.
56
+ Update the locked version of bundler. BUNDLER can be a version such as
57
+ `4.0.20`, or a requirement such as `"> 0.a"`. With no argument, update to the
58
+ latest released version, which never selects a prerelease.
57
59
 
58
60
  * `--force`, `--redownload`:
59
61
  Force reinstalling every gem, even if already installed.
@@ -81,7 +83,7 @@ gem.
81
83
  Prefer updating only to next minor version.
82
84
 
83
85
  * `--major`:
84
- Prefer updating to next major version (default).
86
+ Prefer updating to latest major version (default).
85
87
 
86
88
  * `--pre`:
87
89
  Always choose the highest allowed version, regardless of prerelease status.
@@ -236,7 +238,7 @@ versions are resolved. One of the following options can be used: `--patch`,
236
238
  Prefer updating only to next minor version.
237
239
 
238
240
  * `--major`:
239
- Prefer updating to next major version (default).
241
+ Prefer updating to latest major version (default).
240
242
 
241
243
  * `--strict`:
242
244
  Do not allow any gem to be updated past latest `--patch` | `--minor` | `--major`.
@@ -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
@@ -490,7 +497,7 @@ a version requirement string (e\.g\. \fB">= 8\.0"\fR), which \fBreplaces\fR the
490
497
  .P
491
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\.
492
499
  .P
493
- Multiple \fBoverride\fR calls for distinct targets are allowed; declaring the same \fBtarget\fR and \fBfield\fR twice is an error\.
500
+ Declaring the same \fBtarget\fR and \fBfield\fR twice is an error\.
494
501
  .IP "" 4
495
502
  .nf
496
503
  source "https://rubygems\.org"
@@ -515,6 +522,31 @@ gem "rails", "~> 7\.0"
515
522
  .IP "" 0
516
523
  .P
517
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\.
518
550
  .SH "SOURCE PRIORITY"
519
551
  When attempting to locate a gem to satisfy a gem requirement, bundler uses the following priority order:
520
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`.
@@ -587,8 +601,7 @@ one of:
587
601
  A per-gem override on the same field takes precedence over an `:all` override.
588
602
  `:all + version:` is rejected: version requirements only make sense per gem.
589
603
 
590
- Multiple `override` calls for distinct targets are allowed; declaring the
591
- same `target` and `field` twice is an error.
604
+ Declaring the same `target` and `field` twice is an error.
592
605
 
593
606
  source "https://rubygems.org"
594
607
 
@@ -615,6 +628,44 @@ versions, not the rewritten requirements. When resolution still fails,
615
628
  Bundler appends the active overrides (with their Gemfile location) to the
616
629
  error message so it is clear which override shaped the constraint set.
617
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
+
618
669
  ## SOURCE PRIORITY
619
670
 
620
671
  When attempting to locate a gem to satisfy a gem requirement,
@@ -30,7 +30,9 @@ module Bundler
30
30
  end
31
31
 
32
32
  def dependencies
33
- (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] }
34
36
  end
35
37
 
36
38
  def materialized_spec
@@ -9,6 +9,20 @@ module Bundler
9
9
  overrides.find {|o| o.target == :all && o.field == field }
10
10
  end
11
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
+
12
26
  # Attach the given overrides onto every LazySpecification in `specs` so
13
27
  # downstream consumers (LazySpecification#choose_compatible, the install-
14
28
  # time compatibility check, etc.) can read the override list off the spec
@@ -19,12 +33,14 @@ module Bundler
19
33
  specs.each {|s| s.overrides = overrides if s.is_a?(LazySpecification) }
20
34
  end
21
35
 
22
- attr_reader :target, :field, :operation, :source_location
36
+ attr_reader :target, :field, :operation, :from, :requirement, :source_location
23
37
 
24
- def initialize(target, field, operation, source_location: nil)
38
+ def initialize(target, field, operation, from: nil, requirement: nil, source_location: nil)
25
39
  @target = target
26
40
  @field = field
27
41
  @operation = operation
42
+ @from = from
43
+ @requirement = requirement
28
44
  @source_location = source_location
29
45
  end
30
46
 
@@ -33,7 +49,19 @@ module Bundler
33
49
  "#{File.basename(@source_location.path)}:#{@source_location.lineno}"
34
50
  end
35
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
+
36
62
  def apply_to(requirement)
63
+ raise ArgumentError, "#{self} rewrites a dependency and has no requirement to apply" if @from
64
+
37
65
  case operation
38
66
  when nil
39
67
  Gem::Requirement.default
@@ -71,6 +71,7 @@ module Bundler
71
71
  @cached_dependencies = Hash.new do |dependencies, package|
72
72
  dependencies[package] = Hash.new do |versions, version|
73
73
  deps = version.dependencies.reject {|d| d.name == package.name }
74
+ deps = Override.rewrite_dependencies(@base.overrides, package.name, deps)
74
75
  deps = apply_metadata_overrides(deps, package.name)
75
76
  versions[version] = to_dependency_hash(deps, @packages)
76
77
  end
@@ -88,6 +89,7 @@ module Bundler
88
89
  solver = Gem::PubGrub::VersionSolver.new(source: self, root: root, strategy: Strategy.new(self), logger: logger)
89
90
  result = solver.solve
90
91
  resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) }
92
+ check_replaced_gems(resolved_specs)
91
93
  Override.attach(resolved_specs, @base.overrides)
92
94
  spec_set = SpecSet.new(resolved_specs).specs_with_additional_variants_from(@base.locked_specs)
93
95
  @cooldown_skipped = cooldown_skipped_summary(spec_set)
@@ -137,15 +139,37 @@ module Bundler
137
139
  raise SolveFailure.new(explanation)
138
140
  end
139
141
 
142
+ # A replacement is only useful when it provides the files of the gem it
143
+ # replaces, so the two cannot be loaded side by side.
144
+ def check_replaced_gems(specs)
145
+ names = specs.map(&:name)
146
+
147
+ @base.overrides.each do |override|
148
+ next unless override.from && override.operation
149
+ next unless names.include?(override.target) && names.include?(override.operation)
150
+ next unless specs.any? {|s| s.name == override.from && s.dependencies.any? {|d| d.name == override.target } }
151
+
152
+ dependents = specs.select do |spec|
153
+ Override.rewrite_dependencies(@base.overrides, spec.name, spec.dependencies).any? {|d| d.name == override.target }
154
+ end.map(&:name).uniq
155
+
156
+ lines = ["#{override} would leave both #{override.target} and #{override.operation} in the bundle because #{override.target} is still required by:"]
157
+ lines << " the Gemfile" if @base.requirements.any? {|d| d.name == override.target }
158
+ lines.concat(dependents.map {|name| " #{name}" })
159
+ if dependents.any?
160
+ lines << "Replace it for each of them, for example:"
161
+ lines << " #{Override.new(override.target, :to, override.operation, from: dependents.first)}"
162
+ end
163
+ raise GemfileError, lines.join("\n")
164
+ end
165
+ end
166
+
140
167
  def override_diagnostic_summary
141
168
  return nil if @base.overrides.empty?
142
169
 
143
170
  lines = ["Bundler applied the following overrides while resolving:"]
144
171
  @base.overrides.each do |override|
145
- target = override.target == :all ? ":all" : override.target.inspect
146
- location = override.source_location_label
147
- lines << " override #{target}, #{override.field}: #{override.operation.inspect}" \
148
- "#{location ? " (declared at #{location})" : ""}"
172
+ lines << " #{override}"
149
173
  end
150
174
  "\n\n#{lines.join("\n")}"
151
175
  end
@@ -30,8 +30,8 @@ module Bundler
30
30
  install_and_restart_with(restart_version)
31
31
  end
32
32
 
33
- def update_bundler_and_restart_with_it_if_needed(target)
34
- spec = resolve_update_version_from(target)
33
+ def update_bundler_and_restart_with_it_if_needed(target, pre: false)
34
+ spec = resolve_update_version_from(target, pre: pre)
35
35
  return unless spec
36
36
 
37
37
  version = spec.version
@@ -108,9 +108,9 @@ module Bundler
108
108
  lockfile_version
109
109
  end
110
110
 
111
- def resolve_update_version_from(target)
111
+ def resolve_update_version_from(target, pre: false)
112
112
  requirement = Gem::Requirement.new(target)
113
- update_candidate = find_latest_matching_spec(requirement)
113
+ update_candidate = find_latest_matching_spec(requirement, pre: pre)
114
114
 
115
115
  if update_candidate.nil?
116
116
  raise InvalidOption, "The `bundle update --bundler` target version (#{target}) does not exist"
@@ -137,18 +137,24 @@ module Bundler
137
137
  end
138
138
  end
139
139
 
140
- def find_latest_matching_spec(requirement)
140
+ def find_latest_matching_spec(requirement, pre: false)
141
141
  Bundler.configure
142
- local_result = find_latest_matching_spec_from_collection(local_specs, requirement)
142
+ # A bare `bundle update --bundler` must stay on releases, like `gem update
143
+ # --system`, so only `--pre` or a prerelease requirement opts into one.
144
+ allow_prerelease = pre || requirement.prerelease?
145
+
146
+ local_result = find_latest_matching_spec_from_collection(local_specs, requirement, allow_prerelease)
143
147
  return local_result if local_result && requirement.specific?
144
148
 
145
- remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement)
149
+ remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement, allow_prerelease)
146
150
  return remote_result if local_result.nil?
147
151
 
148
- [local_result, remote_result].max
152
+ [local_result, remote_result].compact.max
149
153
  end
150
154
 
151
- def find_latest_matching_spec_from_collection(specs, requirement)
155
+ def find_latest_matching_spec_from_collection(specs, requirement, allow_prerelease)
156
+ specs = specs.reject {|spec| spec.version.prerelease? } unless allow_prerelease
157
+
152
158
  specs.sort.reverse_each.find {|spec| requirement.satisfied_by?(spec.version) }
153
159
  end
154
160
 
@@ -896,32 +896,16 @@ module Bundler
896
896
  "#{prefix}#{uri}#{suffix}"
897
897
  end
898
898
 
899
- # This is a hot method, so avoid respond_to? checks on every invocation
900
- if :read.respond_to?(:name)
901
- def self.key_to_s(key)
902
- case key
903
- when String
904
- key
905
- when Symbol
906
- key.name
907
- when Gem::URI::HTTP
908
- key.to_s
909
- else
910
- raise ArgumentError, "Invalid key: #{key.inspect}"
911
- end
912
- end
913
- else
914
- def self.key_to_s(key)
915
- case key
916
- when String
917
- key
918
- when Symbol
919
- key.to_s
920
- when Gem::URI::HTTP
921
- key.to_s
922
- else
923
- raise ArgumentError, "Invalid key: #{key.inspect}"
924
- end
899
+ def self.key_to_s(key)
900
+ case key
901
+ when String
902
+ key
903
+ when Symbol
904
+ key.name
905
+ when Gem::URI::HTTP
906
+ key.to_s
907
+ else
908
+ raise ArgumentError, "Invalid key: #{key.inspect}"
925
909
  end
926
910
  end
927
911
  end
@@ -54,7 +54,7 @@ module Bundler
54
54
  # All actions required by the Git source is encapsulated in this
55
55
  # object.
56
56
  class GitProxy
57
- attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref
57
+ attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref, :sparse_checkout
58
58
  attr_writer :revision
59
59
 
60
60
  def self.version
@@ -95,6 +95,7 @@ module Bundler
95
95
  @revision = revision
96
96
  @git = git
97
97
  @commit_ref = nil
98
+ @sparse_checkout = options["sparse_checkout"]
98
99
  end
99
100
 
100
101
  def revision
@@ -159,6 +160,8 @@ module Bundler
159
160
  end
160
161
  end
161
162
 
163
+ setup_sparse_checkout(destination)
164
+
162
165
  ref = @commit_ref || (locked_to_full_sha? && @revision)
163
166
  if ref
164
167
  git "config", "uploadpack.allowAnySHA1InWant", "true", dir: path.to_s if @commit_ref.nil? && needs_allow_any_sha1_in_want?
@@ -507,7 +510,15 @@ module Bundler
507
510
 
508
511
  return ["git", *opts, *cmd] unless dir
509
512
 
510
- ["git", "-C", dir.to_s, *opts, *cmd]
513
+ # With safe.bareRepository=explicit, git refuses to discover a bare
514
+ # repository from -C, so the cache clone is named with --git-dir.
515
+ # Working trees, like a local override, still go through -C.
516
+ location = bare_repo?(dir) ? "--git-dir" : "-C"
517
+ ["git", location, dir.to_s, *opts, *cmd]
518
+ end
519
+
520
+ def bare_repo?(dir)
521
+ File.exist?(File.join(dir, "objects")) && File.exist?(File.join(dir, "HEAD"))
511
522
  end
512
523
 
513
524
  def extra_clone_args
@@ -565,6 +576,32 @@ module Bundler
565
576
  def supports_cloning_with_no_tags?
566
577
  @supports_cloning_with_no_tags ||= Gem::Version.new(version) >= Gem::Version.new("2.14.0-rc0")
567
578
  end
579
+
580
+ def supports_sparse_checkout?
581
+ @supports_sparse_checkout ||= Gem::Version.new(version) >= Gem::Version.new("2.25.0")
582
+ end
583
+
584
+ def supports_sparse_checkout_set_with_cone?
585
+ @supports_sparse_checkout_set_with_cone ||= Gem::Version.new(version) >= Gem::Version.new("2.35.0")
586
+ end
587
+
588
+ def setup_sparse_checkout(destination)
589
+ return unless @sparse_checkout
590
+
591
+ unless supports_sparse_checkout?
592
+ Bundler.ui.warn "Git #{version} doesn't support sparse-checkout (requires 2.25+). Checking out the full repository."
593
+ return
594
+ end
595
+
596
+ Bundler.ui.debug "Setting sparse checkout to only include #{@sparse_checkout.join(", ")}"
597
+ if supports_sparse_checkout_set_with_cone?
598
+ git "sparse-checkout", "set", "--cone", *@sparse_checkout, dir: destination
599
+ else
600
+ # Before git 2.35, `set` keeps an unknown --cone as a pattern instead of rejecting it.
601
+ git "sparse-checkout", "init", "--cone", dir: destination
602
+ git "sparse-checkout", "set", *@sparse_checkout, dir: destination
603
+ end
604
+ end
568
605
  end
569
606
  end
570
607
  end