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
@@ -15,8 +15,6 @@ module Bundler
15
15
 
16
16
  Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler, pre: options[:pre]) if update_bundler
17
17
 
18
- Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.settings[:plugins]
19
-
20
18
  sources = Array(options[:source])
21
19
  groups = Array(options[:group]).map(&:to_sym)
22
20
 
@@ -33,29 +31,39 @@ module Bundler
33
31
 
34
32
  conservative = options[:conservative]
35
33
 
36
- if full_update
34
+ unlock = if full_update
37
35
  if conservative
38
- Bundler.definition(conservative: conservative)
36
+ { conservative: conservative }
39
37
  else
40
- Bundler.definition(true)
38
+ true
41
39
  end
42
40
  else
43
41
  unless Bundler.default_lockfile.exist?
44
42
  raise GemfileLockNotFound, "This Bundle hasn't been installed yet. " \
45
43
  "Run `bundle install` to update and install the bundled gems."
46
44
  end
47
- Bundler::CLI::Common.ensure_all_gems_in_lockfile!(gems)
45
+ explicit_gems = gems.dup
48
46
 
49
47
  if groups.any?
50
48
  deps = Bundler.definition.dependencies.select {|d| (d.groups & groups).any? }
51
49
  gems.concat(deps.map(&:name))
52
50
  end
53
51
 
54
- Bundler.definition(gems: gems, sources: sources, ruby: options[:ruby],
55
- conservative: conservative,
56
- bundler: update_bundler)
52
+ {
53
+ gems: gems,
54
+ sources: sources,
55
+ ruby: options[:ruby],
56
+ conservative: conservative,
57
+ bundler: update_bundler,
58
+ }
57
59
  end
58
60
 
61
+ Plugin.gemfile_install(Bundler.default_gemfile, Bundler.default_lockfile, unlock.dup) if Bundler.settings[:plugins]
62
+
63
+ Bundler::CLI::Common.ensure_all_gems_in_lockfile!(explicit_gems) if explicit_gems
64
+
65
+ Bundler.definition(unlock)
66
+
59
67
  Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
60
68
 
61
69
  Bundler::Fetcher.disable_endpoint = options["full-index"]
@@ -66,8 +74,7 @@ module Bundler
66
74
  opts["force"] = options[:redownload] if options[:redownload]
67
75
 
68
76
  Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
69
- Bundler::CLI::Common.validate_cooldown!(options[:cooldown])
70
- Bundler.settings.set_command_option_if_given :cooldown, options[:cooldown]
77
+ Bundler::CLI::Common.configure_cooldown(options)
71
78
 
72
79
  Bundler.definition.validate_runtime!
73
80
 
@@ -84,6 +91,8 @@ module Bundler
84
91
  if CLI::Common.clean_after_install?
85
92
  require_relative "clean"
86
93
  Bundler::CLI::Clean.new(options).run
94
+ else
95
+ CLI::Common.prune(options)
87
96
  end
88
97
 
89
98
  if locked_gems
data/lib/bundler/cli.rb CHANGED
@@ -288,10 +288,12 @@ module Bundler
288
288
  method_option "with", type: :array, banner: "Include gems that are part of the specified named group (removed)."
289
289
  method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
290
290
  def install
291
- %w[clean deployment frozen no-prune path shebang without with].each do |option|
291
+ %w[clean deployment frozen path shebang without with].each do |option|
292
292
  remembered_flag_deprecation(option)
293
293
  end
294
294
 
295
+ remembered_flag_deprecation("no-prune", option_name: "keep_outdated_cache")
296
+
295
297
  print_remembered_flag_deprecation("--system", "path.system", "true") if ARGV.include?("--system")
296
298
 
297
299
  remembered_flag_deprecation("deployment", negative: true)
@@ -352,6 +354,7 @@ module Bundler
352
354
  D
353
355
  method_option "paths", type: :boolean, banner: "List the paths of all gems that are required by your Gemfile."
354
356
  method_option "outdated", type: :boolean, banner: "Show verbose output including whether gems are outdated (removed)."
357
+ method_option "exact-match", type: :boolean, banner: "Only match gems whose names exactly match the given name"
355
358
  def show(gem_name = nil)
356
359
  if ARGV.include?("--outdated")
357
360
  removed_message = "the `--outdated` flag to `bundle show` has been removed in favor of `bundle show --verbose`"
@@ -377,6 +380,7 @@ module Bundler
377
380
  desc "info GEM [OPTIONS]", "Show information for the given gem"
378
381
  method_option "path", type: :boolean, banner: "Print full path to gem"
379
382
  method_option "version", type: :boolean, banner: "Print gem version"
383
+ method_option "exact-match", type: :boolean, banner: "Only match gems whose names exactly match the given name"
380
384
  def info(gem_name)
381
385
  require_relative "cli/info"
382
386
  Info.new(options, gem_name).run
@@ -417,7 +421,8 @@ module Bundler
417
421
  method_option "glob", type: :string, banner: "The location of a dependency's .gemspec, expanded within Ruby (single quotes recommended)"
418
422
  method_option "quiet", type: :boolean, banner: "Only output warnings and errors."
419
423
  method_option "skip-install", type: :boolean, banner: "Adds gem to the Gemfile but does not install it"
420
- method_option "optimistic", type: :boolean, banner: "Adds optimistic declaration of version to gem"
424
+ method_option "optimistic", type: :boolean, banner: "Ignored (now default behavior)"
425
+ method_option "pessimistic", type: :boolean, banner: "Adds pessimistic declaration of version to gem"
421
426
  method_option "strict", type: :boolean, banner: "Adds strict declaration of version to gem"
422
427
  method_option "cooldown", type: :numeric, banner: "Only consider gem versions published at least N days ago. Use 0 to disable."
423
428
  def add(*gems)
@@ -484,9 +489,8 @@ module Bundler
484
489
  print_remembered_flag_deprecation("--all", "cache_all", "true") if ARGV.include?("--all")
485
490
  print_remembered_flag_deprecation("--no-all", "cache_all", "false") if ARGV.include?("--no-all")
486
491
 
487
- %w[frozen no-prune].each do |option|
488
- remembered_flag_deprecation(option)
489
- end
492
+ remembered_flag_deprecation("frozen")
493
+ remembered_flag_deprecation("no-prune", option_name: "keep_outdated_cache")
490
494
 
491
495
  if flag_passed?("--path")
492
496
  removed_message =
@@ -540,6 +544,7 @@ module Bundler
540
544
 
541
545
  desc "open GEM", "Opens the source directory of the given bundled gem"
542
546
  method_option "path", type: :string, lazy_default: "", banner: "Open relative path of the gem source."
547
+ method_option "exact-match", type: :boolean, banner: "Only match gems whose names exactly match the given name"
543
548
  def open(name)
544
549
  require_relative "cli/open"
545
550
  Open.new(options, name).run
@@ -771,9 +776,6 @@ module Bundler
771
776
  config[:current_command] = original_command
772
777
  end
773
778
 
774
- def current_command=(command)
775
- end
776
-
777
779
  def print_command
778
780
  return unless Bundler.ui.debug?
779
781
  cmd = current_command
@@ -799,9 +801,13 @@ module Bundler
799
801
  return unless SharedHelpers.md5_available?
800
802
 
801
803
  require_relative "vendored_uri"
804
+ require "rubygems/compact_index_client"
805
+ if Gem::CompactIndexClient.respond_to?(:filesystem_access=)
806
+ Gem::CompactIndexClient.filesystem_access = SharedHelpers.method(:filesystem_access)
807
+ end
802
808
  remote = Source::Rubygems::Remote.new(Gem::URI("https://rubygems.org"))
803
809
  cache_path = Bundler.user_cache.join("compact_index", remote.cache_slug)
804
- latest = Bundler::CompactIndexClient.new(cache_path).latest_version("bundler")
810
+ latest = Gem::CompactIndexClient.new(cache_path).latest_version("bundler")
805
811
  return unless latest
806
812
 
807
813
  current = Gem::Version.new(VERSION)
@@ -3,7 +3,7 @@
3
3
  require "rbconfig"
4
4
 
5
5
  module Bundler
6
- WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/
6
+ WINDOWS = RbConfig::CONFIG["host_os"] =~ /(mswin|mingw)/
7
7
  deprecate_constant :WINDOWS
8
8
 
9
9
  FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd")
@@ -10,13 +10,14 @@ module Bundler
10
10
  attr_accessor :no_lock
11
11
  end
12
12
 
13
- attr_writer :lockfile
13
+ attr_writer :lockfile, :overrides
14
14
 
15
15
  attr_reader(
16
16
  :dependencies,
17
17
  :locked_checksums,
18
18
  :locked_deps,
19
19
  :locked_gems,
20
+ :overrides,
20
21
  :platforms,
21
22
  :ruby_version,
22
23
  :lockfile,
@@ -37,7 +38,10 @@ module Bundler
37
38
 
38
39
  raise GemfileNotFound, "#{gemfile} not found" unless gemfile.file?
39
40
 
40
- Dsl.evaluate(gemfile, lockfile, unlock)
41
+ Plugin.hook(Plugin::Events::GEM_BEFORE_EVAL, gemfile, lockfile)
42
+ Dsl.evaluate(gemfile, lockfile, unlock).tap do |definition|
43
+ Plugin.hook(Plugin::Events::GEM_AFTER_EVAL, definition)
44
+ end
41
45
  end
42
46
 
43
47
  #
@@ -58,7 +62,7 @@ module Bundler
58
62
  # to be updated or true if all gems should be updated
59
63
  # @param ruby_version [Bundler::RubyVersion, nil] Requested Ruby Version
60
64
  # @param optional_groups [Array(String)] A list of optional groups
61
- def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [])
65
+ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, optional_groups = [], gemfiles = [], overrides = [])
62
66
  unlock ||= {}
63
67
 
64
68
  if unlock == true
@@ -88,6 +92,7 @@ module Bundler
88
92
  @specs = nil
89
93
  @ruby_version = ruby_version
90
94
  @gemfiles = gemfiles
95
+ @overrides = overrides
91
96
 
92
97
  @lockfile = lockfile
93
98
  @lockfile_contents = String.new
@@ -109,6 +114,7 @@ module Bundler
109
114
  @locked_bundler_version = @locked_gems.bundler_version
110
115
  @locked_ruby_version = @locked_gems.ruby_version
111
116
  @locked_deps = @locked_gems.dependencies
117
+ Override.attach(@locked_gems.specs, @overrides)
112
118
  @originally_locked_specs = SpecSet.new(@locked_gems.specs)
113
119
  @originally_locked_sources = @locked_gems.sources
114
120
  @locked_checksums = @locked_gems.checksums
@@ -192,7 +198,7 @@ module Bundler
192
198
 
193
199
  sources.cached!
194
200
 
195
- if options[:add_checksums] || (!options[:local] && (install_needed? || @locked_spec_with_empty_checksums))
201
+ if options[:add_checksums] || (!options[:local] && (install_needed? || refetch_needed?(options) || @locked_spec_with_empty_checksums))
196
202
  sources.remote!
197
203
  true
198
204
  else
@@ -340,7 +346,9 @@ module Bundler
340
346
  #
341
347
  # @return [SpecSet] resolved dependencies
342
348
  def resolve
343
- @resolve ||= if Bundler.frozen_bundle?
349
+ return @resolve if @resolve
350
+
351
+ @resolve = if Bundler.frozen_bundle?
344
352
  Bundler.ui.debug "Frozen, using resolution from the lockfile"
345
353
  @locked_specs
346
354
  elsif no_resolve_needed?
@@ -360,6 +368,8 @@ module Bundler
360
368
 
361
369
  start_resolution
362
370
  end
371
+ warn_inert_overrides(@resolve)
372
+ @resolve
363
373
  end
364
374
 
365
375
  def spec_git_paths
@@ -509,12 +519,6 @@ module Bundler
509
519
  "Your Ruby version is #{actual}, but your Gemfile specified #{expected}"
510
520
  when :engine_version
511
521
  "Your #{Bundler::RubyVersion.system.engine} version is #{actual}, but your Gemfile specified #{ruby_version.engine} #{expected}"
512
- when :patchlevel
513
- if !expected.is_a?(String)
514
- "The Ruby patchlevel in your Gemfile must be a string"
515
- else
516
- "Your Ruby patchlevel is #{actual}, but your Gemfile specified #{expected}"
517
- end
518
522
  end
519
523
 
520
524
  raise RubyVersionMismatch, msg
@@ -627,6 +631,17 @@ module Bundler
627
631
  resolve_needed? || missing_specs?
628
632
  end
629
633
 
634
+ # Reinstalling installs from the cached archive, and `bundle cache` copies it
635
+ # into the app cache, so a cache emptied by the `prune` setting or by hand has
636
+ # to go back to the remotes to refill it.
637
+ def refetch_needed?(options)
638
+ return false unless options[:force] || options["cache-archives"]
639
+
640
+ resolve.for(requested_dependencies, [Bundler.local_platform]).any? do |spec|
641
+ spec.source.is_a?(Source::Rubygems) && spec.source.uncached?(spec)
642
+ end
643
+ end
644
+
630
645
  def something_changed?
631
646
  return true unless lockfile_exists?
632
647
 
@@ -671,7 +686,20 @@ module Bundler
671
686
  end
672
687
 
673
688
  def expanded_dependencies
674
- dependencies_with_bundler + metadata_dependencies
689
+ apply_overrides_to(dependencies_with_bundler) + metadata_dependencies
690
+ end
691
+
692
+ def apply_overrides_to(deps)
693
+ return deps if @overrides.empty?
694
+ deps.map {|dep| apply_override_to(dep) }
695
+ end
696
+
697
+ def apply_override_to(dep)
698
+ override = Override.find_for(@overrides, dep.name, :version)
699
+ return dep unless override
700
+ new_dep = dep.dup
701
+ new_dep.instance_variable_set(:@requirement, override.apply_to(dep.requirement))
702
+ new_dep
675
703
  end
676
704
 
677
705
  def dependencies_with_bundler
@@ -1070,7 +1098,7 @@ module Bundler
1070
1098
  @locked_specs.delete(locked_specs.select {|s| s.source != dep.source })
1071
1099
  end
1072
1100
 
1073
- unless dep.matches_spec?(locked_specs.first)
1101
+ unless apply_override_to(dep).matches_spec?(locked_specs.first)
1074
1102
  @gems_to_unlock << name
1075
1103
  dep_changed = true
1076
1104
  end
@@ -1080,9 +1108,68 @@ module Bundler
1080
1108
  @changed_dependencies << name if dep_changed
1081
1109
  end
1082
1110
 
1111
+ converge_overrides_outside_dependencies
1112
+ converge_rewritten_dependencies
1113
+
1083
1114
  @changed_dependencies.any?
1084
1115
  end
1085
1116
 
1117
+ # The lockfile keeps the upstream dependencies of every gem, so a gem that
1118
+ # a `from:`/`to:` override cut loose stays locked until a resolution drops
1119
+ # it.
1120
+ def converge_rewritten_dependencies
1121
+ @overrides.each do |override|
1122
+ next unless override.from
1123
+
1124
+ name = override.target
1125
+ next if @originally_locked_specs[name].empty?
1126
+ next if @dependencies.any? {|d| d.name == name }
1127
+
1128
+ still_required = @originally_locked_specs.any? do |s|
1129
+ Override.rewrite_dependencies(@overrides, s.name, s.runtime_dependencies).any? {|d| d.name == name }
1130
+ end
1131
+ next if still_required
1132
+
1133
+ @gems_to_unlock << name
1134
+ @changed_dependencies << name
1135
+ end
1136
+ end
1137
+
1138
+ # A misspelled `from:` gem leaves the override with nothing to rewrite.
1139
+ def warn_inert_overrides(specs)
1140
+ @overrides.each do |override|
1141
+ next unless override.from
1142
+ next if specs[override.from].any? {|s| s.dependencies.any? {|d| d.name == override.target } }
1143
+
1144
+ Bundler.ui.warn "#{override} has no effect because the bundle has no #{override.from} that depends on #{override.target}"
1145
+ end
1146
+ end
1147
+
1148
+ def converge_overrides_outside_dependencies
1149
+ @overrides.each do |override|
1150
+ # :all and metadata overrides are intentionally not pre-unlocked. The
1151
+ # lockfile does not record overrides, so unlocking for them would
1152
+ # re-resolve on every run and reject every frozen install. Install-time
1153
+ # compatibility checks already honor them for locked specs, and they
1154
+ # affect resolution on a fresh lock or when the user runs `bundle update`.
1155
+ next unless override.target.is_a?(String) && override.field == :version
1156
+
1157
+ name = override.target
1158
+ # Overrides on direct deps are detected in the per-dep
1159
+ # converge_dependencies loop via apply_override_to + matches_spec?.
1160
+ next if @dependencies.any? {|d| d.name == name }
1161
+
1162
+ locked_specs = @originally_locked_specs[name]
1163
+ next if locked_specs.empty?
1164
+ # Only a version string constrains on its own. :ignore_upper and nil
1165
+ # loosen requirements the lockfile already satisfies.
1166
+ next if override.apply_to(Gem::Requirement.default).satisfied_by?(locked_specs.first.version)
1167
+
1168
+ @gems_to_unlock << name
1169
+ @changed_dependencies << name
1170
+ end
1171
+ end
1172
+
1086
1173
  # Remove elements from the locked specs that are expired. This will most
1087
1174
  # commonly happen if the Gemfile has changed since the lockfile was last
1088
1175
  # generated
@@ -1305,7 +1392,7 @@ module Bundler
1305
1392
  end
1306
1393
 
1307
1394
  def source_map
1308
- @source_map ||= SourceMap.new(sources, dependencies, @locked_specs)
1395
+ @source_map ||= SourceMap.new(sources, dependencies, @locked_specs, @overrides.filter_map {|o| o.operation if o.from })
1309
1396
  end
1310
1397
 
1311
1398
  def new_resolver_for_full_update
@@ -1318,7 +1405,7 @@ module Bundler
1318
1405
 
1319
1406
  def new_resolution_base(last_resolve:, unlock:)
1320
1407
  new_resolution_platforms = @current_platform_missing ? @new_platforms + [Bundler.local_platform] : @new_platforms
1321
- Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms, explicit_unlocks: @explicit_unlocks)
1408
+ Resolver::Base.new(source_requirements, expanded_dependencies, last_resolve, @platforms, locked_specs: @originally_locked_specs, unlock: unlock, prerelease: gem_version_promoter.pre?, prefer_local: @prefer_local, new_platforms: new_resolution_platforms, overrides: @overrides, explicit_unlocks: @explicit_unlocks)
1322
1409
  end
1323
1410
 
1324
1411
  def new_resolver(base)
@@ -118,6 +118,10 @@ module Bundler
118
118
  !gemspec_dev_dep?
119
119
  end
120
120
 
121
+ def plugin?
122
+ @plugin ||= @options.fetch("plugin", false)
123
+ end
124
+
121
125
  def current_env?
122
126
  return true unless env
123
127
  if env.is_a?(Hash)
data/lib/bundler/dsl.rb CHANGED
@@ -17,12 +17,12 @@ module Bundler
17
17
  VALID_PLATFORMS = Bundler::CurrentRuby::PLATFORM_MAP.keys.freeze
18
18
 
19
19
  VALID_KEYS = %w[group groups git path glob name branch ref tag require submodules
20
- platform platforms source install_if force_ruby_platform].freeze
20
+ platform platforms source install_if force_ruby_platform sparse_checkout].freeze
21
21
 
22
22
  GITHUB_PULL_REQUEST_URL = %r{\Ahttps://github\.com/([A-Za-z0-9_\-\.]+/[A-Za-z0-9_\-\.]+)/pull/(\d+)\z}
23
23
  GITLAB_MERGE_REQUEST_URL = %r{\Ahttps://gitlab\.com/([A-Za-z0-9_\-\./]+)/-/merge_requests/(\d+)\z}
24
24
 
25
- attr_reader :gemspecs, :gemfile
25
+ attr_reader :gemspecs, :gemfile, :overrides
26
26
  attr_accessor :dependencies
27
27
 
28
28
  def initialize
@@ -40,6 +40,7 @@ module Bundler
40
40
  @gemfile = nil
41
41
  @gemfiles = []
42
42
  @lockfile = nil
43
+ @overrides = []
43
44
  add_git_sources
44
45
  end
45
46
 
@@ -123,9 +124,15 @@ module Bundler
123
124
 
124
125
  if options.key?("type")
125
126
  options["type"] = options["type"].to_s
126
- unless Plugin.source?(options["type"])
127
+ unless (source_plugin = Plugin.source_plugin(options["type"]))
127
128
  raise InvalidOption, "No plugin sources available for #{options["type"]}"
128
129
  end
130
+ # Implicitly add a dependency on source plugins who are named bundler-source-<type>,
131
+ # and aren't already mentioned in the Gemfile.
132
+ # See also Plugin::DSL#source
133
+ if source_plugin.start_with?("bundler-source-") && !@dependencies.any? {|d| d.name == source_plugin }
134
+ plugin(source_plugin)
135
+ end
129
136
 
130
137
  unless block_given?
131
138
  raise InvalidOption, "You need to pass a block to #source with :type option"
@@ -188,10 +195,38 @@ module Bundler
188
195
  with_source(git_source) { yield }
189
196
  end
190
197
 
198
+ SUPPORTED_OVERRIDE_FIELDS = [:version, :required_ruby_version, :required_rubygems_version].freeze
199
+ SUPPORTED_OVERRIDE_SYMBOL_OPERATIONS = [:ignore_upper].freeze
200
+
201
+ def override(target, **operations)
202
+ validate_override_target!(target)
203
+ source_location = caller_locations(1, 1)&.first
204
+
205
+ if operations.key?(:from) || operations.key?(:to)
206
+ add_dependency_override(target, operations, source_location)
207
+ return
208
+ end
209
+
210
+ if target == :all && operations.key?(:version)
211
+ raise ArgumentError, "`override :all, version:` is not allowed; version requirements are per-gem"
212
+ end
213
+
214
+ operations.each do |field, operation|
215
+ validate_override_field!(field)
216
+ validate_override_operation!(operation)
217
+ validate_override_uniqueness!(target, field)
218
+ end
219
+
220
+ operations.each do |field, operation|
221
+ @overrides << Override.new(target, field, operation, source_location: source_location)
222
+ end
223
+ end
224
+
191
225
  def to_definition(lockfile, unlock)
192
226
  check_primary_source_safety
227
+ check_dropped_dependencies
193
228
  lockfile = @lockfile unless @lockfile.nil?
194
- Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles)
229
+ Definition.new(lockfile, @dependencies, @sources, unlock, @ruby_version, @optional_groups, @gemfiles, @overrides)
195
230
  end
196
231
 
197
232
  def group(*args, &blk)
@@ -233,8 +268,15 @@ module Bundler
233
268
  @env = old
234
269
  end
235
270
 
236
- def plugin(*args)
237
- # Pass on
271
+ def plugin(name, *args)
272
+ options = args.last.is_a?(Hash) ? args.pop.dup : {}
273
+ version = args || [">= 0"]
274
+
275
+ normalize_options(name, version, options)
276
+ options["plugin"] = true
277
+ options["require"] = false
278
+
279
+ add_dependency(name, version, options)
238
280
  end
239
281
 
240
282
  def method_missing(name, *args)
@@ -248,6 +290,87 @@ module Bundler
248
290
 
249
291
  private
250
292
 
293
+ def validate_override_target!(target)
294
+ return if target == :all
295
+ return if target.is_a?(String)
296
+ raise ArgumentError, "override target must be :all or a gem name string, got #{target.inspect}"
297
+ end
298
+
299
+ def validate_override_field!(field)
300
+ return if SUPPORTED_OVERRIDE_FIELDS.include?(field)
301
+ supported = SUPPORTED_OVERRIDE_FIELDS.map {|f| "`#{f}:`" }.join(", ")
302
+ raise ArgumentError, "unsupported override field `#{field}:`; supported fields: #{supported}"
303
+ end
304
+
305
+ def validate_override_operation!(operation)
306
+ case operation
307
+ when String
308
+ Gem::Requirement.new(operation)
309
+ when nil
310
+ # ok
311
+ when Symbol
312
+ return if SUPPORTED_OVERRIDE_SYMBOL_OPERATIONS.include?(operation)
313
+ raise ArgumentError, "unsupported override operation: #{operation.inspect}"
314
+ else
315
+ raise ArgumentError, "override operation must be a String, Symbol, or nil, got #{operation.inspect}"
316
+ end
317
+ rescue Gem::Requirement::BadRequirementError => e
318
+ raise ArgumentError, "invalid override version requirement #{operation.inspect}: #{e.message}"
319
+ end
320
+
321
+ def validate_override_uniqueness!(target, field)
322
+ return unless @overrides.any? {|o| o.target == target && o.field == field }
323
+ raise ArgumentError, "duplicate override for #{target.inspect} `#{field}:`"
324
+ end
325
+
326
+ def add_dependency_override(target, operations, source_location)
327
+ unless operations.key?(:from)
328
+ raise ArgumentError, "`override #{target.inspect}, to:` requires `from:` naming the gem whose dependency is rewritten"
329
+ end
330
+ unless operations.key?(:to)
331
+ raise ArgumentError, "`override #{target.inspect}, from:` requires `to:`; use `to: nil` to drop the dependency or `to: \"<gem>\"` to replace it"
332
+ end
333
+
334
+ from = operations[:from]
335
+ to = operations[:to]
336
+ requirement = operations[:version]
337
+
338
+ raise ArgumentError, "`override :all` does not accept `from:`" if target == :all
339
+ raise ArgumentError, "`from:` must be a gem name string, got #{from.inspect}" unless from.is_a?(String)
340
+ raise ArgumentError, "`to:` must be a gem name string or nil, got #{to.inspect}" unless to.nil? || to.is_a?(String)
341
+ raise ArgumentError, "`to:` must name a gem other than #{target.inspect} and #{from.inspect}" if to == target || to == from
342
+ validate_gem_name!(from)
343
+ validate_gem_name!(to) if to
344
+
345
+ unsupported = operations.keys - [:from, :to, :version]
346
+ if unsupported.any?
347
+ raise ArgumentError, "unsupported override field `#{unsupported.first}:` with `from:`; supported fields: `to:`, `version:`"
348
+ end
349
+
350
+ if operations.key?(:version)
351
+ raise ArgumentError, "`version:` with `from:` requires `to:` to name a replacement gem" if to.nil?
352
+ raise ArgumentError, "`version:` with `from:` must be a version requirement string, got #{requirement.inspect}" unless requirement.is_a?(String)
353
+ validate_override_operation!(requirement)
354
+ end
355
+
356
+ if @overrides.any? {|o| o.target == target && o.from == from }
357
+ raise ArgumentError, "duplicate override for #{target.inspect} `from: #{from.inspect}`"
358
+ end
359
+
360
+ @overrides << Override.new(target, :to, to, from: from, requirement: requirement, source_location: source_location)
361
+ end
362
+
363
+ # Dropping a gem the Gemfile requires directly would leave it installed
364
+ # anyway, with only the parent's requirement gone.
365
+ def check_dropped_dependencies
366
+ @overrides.each do |override|
367
+ next unless override.from && override.operation.nil?
368
+ next unless @dependencies.any? {|d| d.name == override.target }
369
+
370
+ raise GemfileError, "#{override} cannot drop #{override.target} because the Gemfile depends on it directly"
371
+ end
372
+ end
373
+
251
374
  def add_dependency(name, version = nil, options = {})
252
375
  options["gemfile"] = @gemfile
253
376
  options["source"] ||= @source
@@ -262,13 +385,10 @@ module Bundler
262
385
 
263
386
  gemspec_dep = [dep, current].find(&:gemspec_dev_dep?)
264
387
  if gemspec_dep
265
- require_relative "vendor/pub_grub/lib/pub_grub/version_range"
266
- require_relative "vendor/pub_grub/lib/pub_grub/version_constraint"
267
- require_relative "vendor/pub_grub/lib/pub_grub/version_union"
268
- require_relative "vendor/pub_grub/lib/pub_grub/rubygems"
388
+ require_relative "vendored_pub_grub"
269
389
 
270
- current_gemspec_range = PubGrub::RubyGems.requirement_to_range(current.requirement)
271
- next_gemspec_range = PubGrub::RubyGems.requirement_to_range(dep.requirement)
390
+ current_gemspec_range = Gem::PubGrub::RubyGems.requirement_to_range(current.requirement)
391
+ next_gemspec_range = Gem::PubGrub::RubyGems.requirement_to_range(dep.requirement)
272
392
 
273
393
  if current_gemspec_range.intersects?(next_gemspec_range)
274
394
  dep = Dependency.new(name, current.requirement.as_list + dep.requirement.as_list, options)
@@ -394,7 +514,7 @@ module Bundler
394
514
  @valid_keys ||= VALID_KEYS
395
515
  end
396
516
 
397
- def normalize_options(name, version, opts)
517
+ def validate_gem_name!(name)
398
518
  if name.is_a?(Symbol)
399
519
  raise GemfileError, %(You need to specify gem names as Strings. Use 'gem "#{name}"' instead)
400
520
  end
@@ -402,6 +522,10 @@ module Bundler
402
522
  raise GemfileError, %('#{name}' is not a valid gem name because it contains whitespace)
403
523
  end
404
524
  raise GemfileError, %(an empty gem name is not valid) if name.empty?
525
+ end
526
+
527
+ def normalize_options(name, version, opts)
528
+ validate_gem_name!(name)
405
529
 
406
530
  normalize_hash(opts)
407
531