bundler 4.0.21 → 4.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/{lib/bundler/vendor/connection_pool/LICENSE → MIT.txt} +8 -6
  3. data/bundler.gemspec +23 -6
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/checksum.rb +40 -25
  6. data/lib/bundler/ci_detector.rb +1 -1
  7. data/lib/bundler/cli/add.rb +3 -4
  8. data/lib/bundler/cli/cache.rb +4 -0
  9. data/lib/bundler/cli/clean.rb +5 -0
  10. data/lib/bundler/cli/common.rb +37 -1
  11. data/lib/bundler/cli/config.rb +4 -2
  12. data/lib/bundler/cli/gem.rb +0 -17
  13. data/lib/bundler/cli/install.rb +4 -5
  14. data/lib/bundler/cli/lock.rb +1 -2
  15. data/lib/bundler/cli/outdated.rb +8 -3
  16. data/lib/bundler/cli/pristine.rb +2 -1
  17. data/lib/bundler/cli/update.rb +21 -12
  18. data/lib/bundler/cli.rb +14 -11
  19. data/lib/bundler/definition.rb +61 -24
  20. data/lib/bundler/dependency.rb +4 -0
  21. data/lib/bundler/dsl.rb +77 -11
  22. data/lib/bundler/endpoint_specification.rb +51 -14
  23. data/lib/bundler/env.rb +7 -24
  24. data/lib/bundler/errors.rb +34 -5
  25. data/lib/bundler/fetcher/compact_index.rb +14 -5
  26. data/lib/bundler/fetcher/connection_pools.rb +150 -0
  27. data/lib/bundler/fetcher/downloader.rb +31 -16
  28. data/lib/bundler/fetcher.rb +8 -47
  29. data/lib/bundler/injector.rb +3 -3
  30. data/lib/bundler/inline.rb +44 -4
  31. data/lib/bundler/installer/parallel_installer.rb +25 -30
  32. data/lib/bundler/installer.rb +20 -6
  33. data/lib/bundler/lazy_specification.rb +44 -17
  34. data/lib/bundler/lockfile_generator.rb +24 -2
  35. data/lib/bundler/lockfile_parser.rb +43 -5
  36. data/lib/bundler/man/bundle-add.1 +7 -4
  37. data/lib/bundler/man/bundle-add.1.ronn +8 -4
  38. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  39. data/lib/bundler/man/bundle-cache.1 +2 -2
  40. data/lib/bundler/man/bundle-cache.1.ronn +2 -2
  41. data/lib/bundler/man/bundle-check.1 +1 -1
  42. data/lib/bundler/man/bundle-clean.1 +1 -1
  43. data/lib/bundler/man/bundle-config.1 +38 -6
  44. data/lib/bundler/man/bundle-config.1.ronn +143 -10
  45. data/lib/bundler/man/bundle-console.1 +1 -1
  46. data/lib/bundler/man/bundle-doctor.1 +1 -1
  47. data/lib/bundler/man/bundle-env.1 +1 -1
  48. data/lib/bundler/man/bundle-exec.1 +1 -1
  49. data/lib/bundler/man/bundle-fund.1 +1 -1
  50. data/lib/bundler/man/bundle-gem.1 +1 -1
  51. data/lib/bundler/man/bundle-help.1 +1 -1
  52. data/lib/bundler/man/bundle-info.1 +1 -1
  53. data/lib/bundler/man/bundle-init.1 +1 -1
  54. data/lib/bundler/man/bundle-install.1 +2 -2
  55. data/lib/bundler/man/bundle-install.1.ronn +4 -4
  56. data/lib/bundler/man/bundle-issue.1 +1 -1
  57. data/lib/bundler/man/bundle-licenses.1 +1 -1
  58. data/lib/bundler/man/bundle-list.1 +1 -1
  59. data/lib/bundler/man/bundle-lock.1 +3 -3
  60. data/lib/bundler/man/bundle-lock.1.ronn +5 -5
  61. data/lib/bundler/man/bundle-open.1 +1 -1
  62. data/lib/bundler/man/bundle-outdated.1 +1 -1
  63. data/lib/bundler/man/bundle-platform.1 +1 -1
  64. data/lib/bundler/man/bundle-plugin.1 +1 -1
  65. data/lib/bundler/man/bundle-pristine.1 +1 -1
  66. data/lib/bundler/man/bundle-remove.1 +1 -1
  67. data/lib/bundler/man/bundle-show.1 +1 -1
  68. data/lib/bundler/man/bundle-update.1 +3 -3
  69. data/lib/bundler/man/bundle-update.1.ronn +3 -5
  70. data/lib/bundler/man/bundle-version.1 +1 -1
  71. data/lib/bundler/man/bundle.1 +1 -1
  72. data/lib/bundler/man/gemfile.5 +45 -1
  73. data/lib/bundler/man/gemfile.5.ronn +53 -0
  74. data/lib/bundler/match_metadata.rb +20 -0
  75. data/lib/bundler/match_platform.rb +25 -2
  76. data/lib/bundler/match_remote_metadata.rb +21 -6
  77. data/lib/bundler/materialization.rb +2 -1
  78. data/lib/bundler/override.rb +69 -0
  79. data/lib/bundler/plugin/dsl.rb +3 -5
  80. data/lib/bundler/plugin/events.rb +55 -13
  81. data/lib/bundler/plugin/index.rb +87 -11
  82. data/lib/bundler/plugin/installer/path.rb +1 -1
  83. data/lib/bundler/plugin/installer.rb +13 -5
  84. data/lib/bundler/plugin.rb +58 -30
  85. data/lib/bundler/remote_specification.rb +6 -3
  86. data/lib/bundler/resolver/base.rb +2 -1
  87. data/lib/bundler/resolver/incompatibility.rb +1 -1
  88. data/lib/bundler/resolver.rb +73 -23
  89. data/lib/bundler/ruby_version.rb +0 -2
  90. data/lib/bundler/rubygems_ext.rb +71 -1
  91. data/lib/bundler/rubygems_gem_installer.rb +41 -2
  92. data/lib/bundler/rubygems_integration.rb +7 -2
  93. data/lib/bundler/runtime.rb +69 -2
  94. data/lib/bundler/self_manager.rb +9 -15
  95. data/lib/bundler/settings.rb +373 -30
  96. data/lib/bundler/shared_helpers.rb +2 -1
  97. data/lib/bundler/source/git/git_proxy.rb +2 -10
  98. data/lib/bundler/source/git.rb +15 -6
  99. data/lib/bundler/source/path/installer.rb +1 -1
  100. data/lib/bundler/source/rubygems/remote.rb +10 -5
  101. data/lib/bundler/source/rubygems.rb +48 -12
  102. data/lib/bundler/spec_set.rb +16 -4
  103. data/lib/bundler/stub_specification.rb +2 -1
  104. data/lib/bundler/templates/newgem/Gemfile.tt +4 -4
  105. data/lib/bundler/templates/newgem/newgem.gemspec.tt +3 -3
  106. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +1 -1
  107. data/lib/bundler/templates/newgem/test/minitest/test_newgem.rb.tt +1 -1
  108. data/lib/bundler/ui/shell.rb +0 -4
  109. data/lib/bundler/ui/silent.rb +0 -4
  110. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +35 -2
  111. data/lib/bundler/vendor/thor/lib/thor/base.rb +2 -1
  112. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +14 -6
  113. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +2 -0
  114. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  115. data/lib/bundler/vendor/thor/lib/thor.rb +34 -1
  116. data/lib/bundler/vendored_pub_grub.rb +5 -2
  117. data/lib/bundler/vendored_securerandom.rb +11 -8
  118. data/lib/bundler/vendored_uri.rb +14 -14
  119. data/lib/bundler/version.rb +1 -1
  120. data/lib/bundler/worker.rb +3 -2
  121. data/lib/bundler.rb +1 -1
  122. data/lib/rubygems/compact_index_client/cache.rb +122 -0
  123. data/lib/rubygems/compact_index_client/cache_file.rb +147 -0
  124. data/lib/rubygems/compact_index_client/http_fetcher.rb +88 -0
  125. data/lib/rubygems/compact_index_client/parser.rb +90 -0
  126. data/lib/rubygems/compact_index_client/updater.rb +113 -0
  127. data/lib/rubygems/compact_index_client.rb +111 -0
  128. data/lib/rubygems/cooldown_settings.rb +57 -0
  129. data/lib/rubygems/credential_store/native/linux.rb +97 -0
  130. data/lib/rubygems/credential_store/native/macos.rb +88 -0
  131. data/lib/rubygems/credential_store/native/windows.rb +130 -0
  132. data/lib/rubygems/credential_store.rb +332 -0
  133. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/assignment.rb +1 -1
  134. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/basic_package_source.rb +7 -7
  135. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/failure_writer.rb +1 -1
  136. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/incompatibility.rb +4 -4
  137. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/package.rb +1 -1
  138. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/partial_solution.rb +1 -1
  139. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/rubygems.rb +3 -3
  140. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/solve_failure.rb +1 -1
  141. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/static_package_source.rb +3 -3
  142. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/strategy.rb +2 -2
  143. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/term.rb +1 -1
  144. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version.rb +1 -1
  145. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_constraint.rb +3 -3
  146. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_range.rb +1 -1
  147. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_solver.rb +2 -2
  148. data/lib/{bundler → rubygems}/vendor/pub_grub/lib/pub_grub/version_union.rb +1 -1
  149. data/lib/rubygems/vendor/pub_grub/lib/pub_grub.rb +57 -0
  150. data/lib/{bundler → rubygems}/vendor/securerandom/lib/securerandom.rb +10 -6
  151. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/common.rb +119 -119
  152. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/file.rb +13 -13
  153. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ftp.rb +24 -24
  154. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/generic.rb +132 -132
  155. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/http.rb +18 -18
  156. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/https.rb +4 -4
  157. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldap.rb +14 -14
  158. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ldaps.rb +4 -4
  159. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/mailto.rb +21 -21
  160. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc2396_parser.rb +39 -39
  161. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/rfc3986_parser.rb +14 -14
  162. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/version.rb +1 -1
  163. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/ws.rb +12 -12
  164. data/lib/{bundler → rubygems}/vendor/uri/lib/uri/wss.rb +4 -4
  165. data/lib/{bundler → rubygems}/vendor/uri/lib/uri.rb +35 -31
  166. data/lib/rubygems/yaml_serializer.rb +880 -0
  167. metadata +77 -68
  168. data/CHANGELOG.md +0 -5784
  169. data/LICENSE.md +0 -22
  170. data/README.md +0 -58
  171. data/lib/bundler/compact_index_client/cache.rb +0 -107
  172. data/lib/bundler/compact_index_client/cache_file.rb +0 -148
  173. data/lib/bundler/compact_index_client/parser.rb +0 -87
  174. data/lib/bundler/compact_index_client/updater.rb +0 -105
  175. data/lib/bundler/compact_index_client.rb +0 -92
  176. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +0 -227
  177. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +0 -3
  178. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +0 -56
  179. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +0 -230
  180. data/lib/bundler/vendor/net-http-persistent/README.rdoc +0 -82
  181. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +0 -41
  182. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +0 -65
  183. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/timed_stack_multi.rb +0 -80
  184. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +0 -1153
  185. data/lib/bundler/vendor/pub_grub/lib/pub_grub.rb +0 -31
  186. data/lib/bundler/vendored_persistent.rb +0 -11
  187. data/lib/bundler/yaml_serializer.rb +0 -98
  188. /data/lib/{bundler → rubygems}/vendor/pub_grub/LICENSE.txt +0 -0
  189. /data/lib/{bundler → rubygems}/vendor/securerandom/COPYING +0 -0
  190. /data/lib/{bundler → rubygems}/vendor/uri/COPYING +0 -0
@@ -18,6 +18,14 @@ module Bundler
18
18
 
19
19
  PLUGIN_FILE_NAME = "plugins.rb"
20
20
 
21
+ # Module-level flag set while .gemfile_install parses the Gemfile and
22
+ # consulted by .from_lock to substitute plugin sources with
23
+ # UnloadedSource. It relies on definitions being built one at a time in
24
+ # a single thread; if they are ever built concurrently or reentrantly,
25
+ # this needs to be replaced by explicit state passed down to the
26
+ # lockfile parser.
27
+ @gemfile_parse = false
28
+
21
29
  module_function
22
30
 
23
31
  def reset!
@@ -27,6 +35,7 @@ module Bundler
27
35
  @commands = {}
28
36
  @hooks_by_event = Hash.new {|h, k| h[k] = [] }
29
37
  @loaded_plugin_names = []
38
+ @index = nil
30
39
  end
31
40
 
32
41
  reset!
@@ -41,7 +50,7 @@ module Bundler
41
50
 
42
51
  specs = Installer.new.install(names, options)
43
52
 
44
- save_plugins names, specs
53
+ save_plugins specs.slice(*names)
45
54
  rescue PluginError
46
55
  specs_to_delete = specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) }
47
56
  specs_to_delete.each_value {|spec| Bundler.rm_rf(spec.full_gem_path) }
@@ -101,29 +110,44 @@ module Bundler
101
110
  #
102
111
  # @param [Pathname] gemfile path
103
112
  # @param [Proc] block that can be evaluated for (inline) Gemfile
104
- def gemfile_install(gemfile = nil, &inline)
105
- Bundler.settings.temporary(frozen: false, deployment: false) do
106
- builder = DSL.new
107
- if block_given?
108
- builder.instance_eval(&inline)
109
- else
110
- builder.eval_gemfile(gemfile)
111
- end
112
- builder.check_primary_source_safety
113
- definition = builder.to_definition(nil, true)
114
-
115
- return if definition.dependencies.empty?
113
+ def gemfile_install(gemfile = nil, lockfile = nil, unlock = {}, &inline)
114
+ @gemfile_parse = true
115
+ Bundler.configure
116
+ builder = DSL.new
117
+ if block_given?
118
+ builder.instance_eval(&inline)
119
+ else
120
+ builder.eval_gemfile(gemfile)
121
+ end
122
+ builder.check_primary_source_safety
116
123
 
117
- plugins = definition.dependencies.map(&:name)
118
- installed_specs = Installer.new.install_definition(definition)
124
+ plugins = builder.dependencies.map(&:name)
125
+ return if plugins.empty?
119
126
 
120
- save_plugins plugins, installed_specs, builder.inferred_plugins
127
+ # skip the update if unlocking specific gems, but none of them are plugins
128
+ # declared in the Gemfile
129
+ if unlock.is_a?(Hash) && unlock[:gems] && !unlock[:gems].empty? &&
130
+ (unlock[:gems] & plugins).empty?
131
+ unlock = {}
121
132
  end
133
+
134
+ # resolve remotely when unlocking, so that plugins can be updated.
135
+ # Definition#initialize consumes the unlock hash, so this must be decided
136
+ # before building the definition.
137
+ updating = unlock == true || (unlock.is_a?(Hash) && !unlock.empty?)
138
+
139
+ definition = builder.to_definition(lockfile, unlock)
140
+
141
+ installed_specs = Installer.new.install_definition(definition, updating)
142
+
143
+ save_plugins installed_specs.slice(*plugins), builder.inferred_plugins
122
144
  rescue RuntimeError => e
123
145
  unless e.is_a?(GemfileError)
124
146
  Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}"
125
147
  end
126
148
  raise
149
+ ensure
150
+ @gemfile_parse = false
127
151
  end
128
152
 
129
153
  # The index object used to store the details about the plugin
@@ -184,12 +208,17 @@ module Bundler
184
208
 
185
209
  # Checks if any plugin declares the source
186
210
  def source?(name)
187
- !index.source_plugin(name.to_s).nil?
211
+ !!source_plugin(name)
212
+ end
213
+
214
+ # Returns the plugin that handles the source +name+ if any
215
+ def source_plugin(name)
216
+ index.source_plugin(name.to_s)
188
217
  end
189
218
 
190
219
  # @return [Class] that handles the source. The class includes API::Source
191
220
  def source(name)
192
- raise UnknownSourceError, "Source #{name} not found" unless source? name
221
+ raise UnknownSourceError, "Source #{name} not found" unless source_plugin(name)
193
222
 
194
223
  load_plugin(index.source_plugin(name)) unless @sources.key? name
195
224
 
@@ -201,6 +230,9 @@ module Bundler
201
230
  # type passed in locked_opts
202
231
  def from_lock(locked_opts)
203
232
  opts = locked_opts.merge("uri" => locked_opts["remote"])
233
+ # when reading the lockfile while doing the plugin-install-from-gemfile phase,
234
+ # we need to ignore any plugin sources
235
+ return UnloadedSource.new(opts) if @gemfile_parse
204
236
  # use an inert placeholder when the plugin handling this source is not
205
237
  # installed, so that the lockfile can still be parsed
206
238
  return UnloadedSource.new(opts) unless source?(locked_opts["type"])
@@ -243,7 +275,9 @@ module Bundler
243
275
  #
244
276
  # @return [String, nil] installed path
245
277
  def installed?(plugin)
246
- Index.new.installed?(plugin)
278
+ (path = index.installed?(plugin)) &&
279
+ index.plugin_path(plugin).join(PLUGIN_FILE_NAME).file? &&
280
+ path
247
281
  end
248
282
 
249
283
  # @return [true, false] whether the plugin is loaded
@@ -253,19 +287,11 @@ module Bundler
253
287
 
254
288
  # Post installation processing and registering with index
255
289
  #
256
- # @param [Array<String>] plugins list to be installed
257
290
  # @param [Hash] specs of plugins mapped to installation path (currently they
258
291
  # contain all the installed specs, including plugins)
259
292
  # @param [Array<String>] names of inferred source plugins that can be ignored
260
- def save_plugins(plugins, specs, optional_plugins = [])
261
- plugins.each do |name|
262
- spec = specs[name]
263
-
264
- # It's possible that the `plugin` found in the Gemfile don't appear in the specs. For instance when
265
- # calling `BUNDLE_WITHOUT=default bundle install`, the plugins will not get installed.
266
- next if spec.nil?
267
- next if index.up_to_date?(spec)
268
-
293
+ def save_plugins(specs, optional_plugins = [])
294
+ specs.each do |name, spec|
269
295
  save_plugin(name, spec, optional_plugins.include?(name))
270
296
  end
271
297
  end
@@ -290,6 +316,8 @@ module Bundler
290
316
  #
291
317
  # @raise [PluginInstallError] if validation or registration raises any error
292
318
  def save_plugin(name, spec, optional_plugin = false)
319
+ return if index.up_to_date?(spec)
320
+
293
321
  validate_plugin! Pathname.new(spec.full_gem_path)
294
322
  installed = register_plugin(name, spec, optional_plugin)
295
323
  Bundler.ui.info "Installed plugin #{name}" if installed
@@ -325,7 +353,7 @@ module Bundler
325
353
  raise MalformattedPlugin, "#{e.class}: #{e.message}"
326
354
  end
327
355
 
328
- if optional_plugin && @sources.keys.any? {|s| source? s }
356
+ if optional_plugin && @sources.keys.any? {|s| source_plugin(s) }
329
357
  Bundler.rm_rf(path)
330
358
  false
331
359
  else
@@ -10,11 +10,11 @@ module Bundler
10
10
  include MatchPlatform
11
11
  include Comparable
12
12
 
13
- attr_reader :name, :version, :platform
13
+ attr_reader :name, :version, :platform, :content_address
14
14
  attr_writer :dependencies
15
15
  attr_accessor :source, :remote, :locked_platform, :created_at
16
16
 
17
- def initialize(name, version, platform, spec_fetcher)
17
+ def initialize(name, version, platform, spec_fetcher, content_address: nil)
18
18
  @name = name
19
19
  @version = Gem::Version.create version
20
20
  @original_platform = platform || Gem::Platform::RUBY
@@ -22,6 +22,7 @@ module Bundler
22
22
  @spec_fetcher = spec_fetcher
23
23
  @dependencies = nil
24
24
  @locked_platform = nil
25
+ @content_address = content_address
25
26
  end
26
27
 
27
28
  def insecurely_materialized?
@@ -35,7 +36,9 @@ module Bundler
35
36
  end
36
37
 
37
38
  def full_name
38
- @full_name ||= if @platform == Gem::Platform::RUBY
39
+ @full_name ||= if Gem::ContentAddress.content_addressed?(self, validate_ruby_abi: false)
40
+ "#{@name}-#{@version}-#{@content_address}"
41
+ elsif @platform == Gem::Platform::RUBY
39
42
  "#{@name}-#{@version}"
40
43
  else
41
44
  "#{@name}-#{@version}-#{@platform}"
@@ -5,9 +5,10 @@ require_relative "package"
5
5
  module Bundler
6
6
  class Resolver
7
7
  class Base
8
- attr_reader :packages, :requirements, :source_requirements, :locked_specs
8
+ attr_reader :packages, :requirements, :source_requirements, :locked_specs, :overrides
9
9
 
10
10
  def initialize(source_requirements, dependencies, base, platforms, options)
11
+ @overrides = options.delete(:overrides) || []
11
12
  @explicit_unlocks = options.delete(:explicit_unlocks) || []
12
13
  @source_requirements = source_requirements
13
14
  @locked_specs = options[:locked_specs]
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Bundler
4
4
  class Resolver
5
- class Incompatibility < PubGrub::Incompatibility
5
+ class Incompatibility < Gem::PubGrub::Incompatibility
6
6
  attr_reader :extended_explanation
7
7
 
8
8
  def initialize(terms, cause:, custom_explanation: nil, extended_explanation: nil)
@@ -70,7 +70,9 @@ module Bundler
70
70
 
71
71
  @cached_dependencies = Hash.new do |dependencies, package|
72
72
  dependencies[package] = Hash.new do |versions, version|
73
- versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages)
73
+ deps = version.dependencies.reject {|d| d.name == package.name }
74
+ deps = apply_metadata_overrides(deps, package.name)
75
+ versions[version] = to_dependency_hash(deps, @packages)
74
76
  end
75
77
  end
76
78
 
@@ -83,13 +85,14 @@ module Bundler
83
85
  end
84
86
 
85
87
  def solve_versions(root:, logger:)
86
- solver = PubGrub::VersionSolver.new(source: self, root: root, strategy: Strategy.new(self), logger: logger)
88
+ solver = Gem::PubGrub::VersionSolver.new(source: self, root: root, strategy: Strategy.new(self), logger: logger)
87
89
  result = solver.solve
88
90
  resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) }
91
+ Override.attach(resolved_specs, @base.overrides)
89
92
  spec_set = SpecSet.new(resolved_specs).specs_with_additional_variants_from(@base.locked_specs)
90
93
  @cooldown_skipped = cooldown_skipped_summary(spec_set)
91
94
  spec_set
92
- rescue PubGrub::SolveFailure => e
95
+ rescue Gem::PubGrub::SolveFailure => e
93
96
  incompatibility = e.incompatibility
94
97
 
95
98
  names_to_unlock, names_to_allow_prereleases_for, names_to_allow_remote_specs_for, extended_explanation = find_names_to_relax(incompatibility)
@@ -128,9 +131,25 @@ module Bundler
128
131
  explanation << extended_explanation
129
132
  end
130
133
 
134
+ override_summary = override_diagnostic_summary
135
+ explanation << override_summary if override_summary
136
+
131
137
  raise SolveFailure.new(explanation)
132
138
  end
133
139
 
140
+ def override_diagnostic_summary
141
+ return nil if @base.overrides.empty?
142
+
143
+ lines = ["Bundler applied the following overrides while resolving:"]
144
+ @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})" : ""}"
149
+ end
150
+ "\n\n#{lines.join("\n")}"
151
+ end
152
+
134
153
  def find_names_to_relax(incompatibility)
135
154
  names_to_unlock = []
136
155
  names_to_allow_prereleases_for = []
@@ -153,7 +172,7 @@ module Bundler
153
172
  names_to_allow_remote_specs_for << name
154
173
  end
155
174
 
156
- no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(PubGrub::Incompatibility::NoVersions) }
175
+ no_versions_incompat = [cause.incompatibility, cause.satisfier].find {|incompat| incompat.cause.is_a?(Gem::PubGrub::Incompatibility::NoVersions) }
157
176
  next unless no_versions_incompat
158
177
 
159
178
  extended_explanation = no_versions_incompat.extended_explanation
@@ -165,12 +184,12 @@ module Bundler
165
184
 
166
185
  def parse_dependency(package, dependency)
167
186
  range = if repository_for(package).is_a?(Source::Gemspec)
168
- PubGrub::VersionRange.any
187
+ Gem::PubGrub::VersionRange.any
169
188
  else
170
189
  requirement_to_range(dependency)
171
190
  end
172
191
 
173
- PubGrub::VersionConstraint.new(package, range: range)
192
+ Gem::PubGrub::VersionConstraint.new(package, range: range)
174
193
  end
175
194
 
176
195
  def versions_for(package, range = VersionRange.any)
@@ -178,7 +197,7 @@ module Bundler
178
197
  end
179
198
 
180
199
  def no_versions_incompatibility_for(package, unsatisfied_term)
181
- cause = PubGrub::Incompatibility::NoVersions.new(unsatisfied_term)
200
+ cause = Gem::PubGrub::Incompatibility::NoVersions.new(unsatisfied_term)
182
201
  name = package.name
183
202
  constraint = unsatisfied_term.constraint
184
203
  constraint_string = constraint.constraint_string
@@ -239,24 +258,24 @@ module Bundler
239
258
  sorted_versions[high]
240
259
  end
241
260
 
242
- range = PubGrub::VersionRange.new(min: low, max: high, include_min: !low.nil?)
261
+ range = Gem::PubGrub::VersionRange.new(min: low, max: high, include_min: !low.nil?)
243
262
 
244
- self_constraint = PubGrub::VersionConstraint.new(package, range: range)
263
+ self_constraint = Gem::PubGrub::VersionConstraint.new(package, range: range)
245
264
 
246
- dep_term = PubGrub::Term.new(dep_constraint, false)
247
- self_term = PubGrub::Term.new(self_constraint, true)
265
+ dep_term = Gem::PubGrub::Term.new(dep_constraint, false)
266
+ self_term = Gem::PubGrub::Term.new(self_constraint, true)
248
267
 
249
268
  custom_explanation = if dep_package.meta? && package.root?
250
269
  "current #{dep_package} version is #{dep_constraint.constraint_string}"
251
270
  end
252
271
 
253
- PubGrub::Incompatibility.new([self_term, dep_term], cause: :dependency, custom_explanation: custom_explanation)
272
+ Gem::PubGrub::Incompatibility.new([self_term, dep_term], cause: :dependency, custom_explanation: custom_explanation)
254
273
  end
255
274
  end
256
275
 
257
276
  def all_versions_for(package)
258
277
  name = package.name
259
- results = (@base[name] + filter_specs(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform] }
278
+ results = (@base[name] + filter_specs(@all_specs[name], package)).uniq {|spec| [spec.version.hash, spec.platform, spec.content_address] }
260
279
 
261
280
  if name == "bundler" && !bundler_pinned_to_current_version?
262
281
  bundler_spec = Gem.loaded_specs["bundler"]
@@ -294,11 +313,15 @@ module Bundler
294
313
  next groups if package.force_ruby_platform?
295
314
  end
296
315
 
297
- platform_group = Resolver::SpecGroup.new(platform_specs.flatten.uniq)
316
+ platform_specs = platform_specs.flatten.uniq
317
+ platform_group = Resolver::SpecGroup.new((platform_specs + ruby_specs).uniq)
298
318
  next groups if platform_group == ruby_group
299
319
 
300
320
  groups << Resolver::Candidate.new(version, group: platform_group, priority: 1)
301
321
 
322
+ platform_only_group = Resolver::SpecGroup.new(platform_specs)
323
+ groups << Resolver::Candidate.new(version, group: platform_only_group, priority: 0) unless platform_only_group == platform_group
324
+
302
325
  groups
303
326
  end
304
327
  end
@@ -446,9 +469,9 @@ module Bundler
446
469
  def cooldown_excluded?(spec)
447
470
  return false unless spec.respond_to?(:created_at) && spec.created_at
448
471
  return false unless spec.respond_to?(:remote) && spec.remote
449
- return false if locked_by_lockfile?(spec)
450
472
  days = spec.remote.effective_cooldown
451
473
  return false if days.nil? || days <= 0
474
+ return false if locked_by_lockfile?(spec)
452
475
  (cooldown_now - spec.created_at) < (days * 86_400)
453
476
  end
454
477
 
@@ -602,19 +625,19 @@ module Bundler
602
625
  when "~>"
603
626
  name = "~> #{ver}"
604
627
  bump = Resolver::Candidate.new(version.bump.to_s + ".A")
605
- PubGrub::VersionRange.new(name: name, min: ver, max: bump, include_min: true)
628
+ Gem::PubGrub::VersionRange.new(name: name, min: ver, max: bump, include_min: true)
606
629
  when ">"
607
- PubGrub::VersionRange.new(min: platform_ver)
630
+ Gem::PubGrub::VersionRange.new(min: platform_ver)
608
631
  when ">="
609
- PubGrub::VersionRange.new(min: ver, include_min: true)
632
+ Gem::PubGrub::VersionRange.new(min: ver, include_min: true)
610
633
  when "<"
611
- PubGrub::VersionRange.new(max: ver)
634
+ Gem::PubGrub::VersionRange.new(max: ver)
612
635
  when "<="
613
- PubGrub::VersionRange.new(max: platform_ver, include_max: true)
636
+ Gem::PubGrub::VersionRange.new(max: platform_ver, include_max: true)
614
637
  when "="
615
- PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true)
638
+ Gem::PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true)
616
639
  when "!="
617
- PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true).invert
640
+ Gem::PubGrub::VersionRange.new(min: ver, max: platform_ver, include_min: true, include_max: true).invert
618
641
  else
619
642
  raise "bad version specifier: #{op}"
620
643
  end
@@ -624,7 +647,7 @@ module Bundler
624
647
  end
625
648
 
626
649
  def to_dependency_hash(dependencies, packages)
627
- dependencies.inject({}) do |deps, dep|
650
+ apply_overrides(dependencies).inject({}) do |deps, dep|
628
651
  package = packages[dep.name]
629
652
 
630
653
  current_req = deps[package]
@@ -640,6 +663,33 @@ module Bundler
640
663
  end
641
664
  end
642
665
 
666
+ def apply_overrides(dependencies)
667
+ return dependencies if @base.overrides.empty?
668
+
669
+ dependencies.map do |dep|
670
+ override = Override.find_for(@base.overrides, dep.name, :version)
671
+ next dep unless override
672
+ Gem::Dependency.new(dep.name, override.apply_to(dep.requirement))
673
+ end
674
+ end
675
+
676
+ METADATA_DEP_FIELD = {
677
+ "Ruby\0" => :required_ruby_version,
678
+ "RubyGems\0" => :required_rubygems_version,
679
+ }.freeze
680
+
681
+ def apply_metadata_overrides(dependencies, name)
682
+ return dependencies if @base.overrides.empty?
683
+
684
+ dependencies.map do |dep|
685
+ field = METADATA_DEP_FIELD[dep.name]
686
+ next dep unless field
687
+ override = Override.find_for(@base.overrides, name, field)
688
+ next dep unless override
689
+ Gem::Dependency.new(dep.name, override.apply_to(dep.requirement))
690
+ end
691
+ end
692
+
643
693
  def bundler_not_found_message(conflict_dependencies)
644
694
  candidate_specs = filter_matching_specs(default_bundler_source.specs.search("bundler"), conflict_dependencies)
645
695
 
@@ -96,8 +96,6 @@ module Bundler
96
96
  [:version, versions_string(versions), versions_string(other.versions)]
97
97
  elsif @input_engine && !matches?(engine_versions, other.engine_gem_version)
98
98
  [:engine_version, versions_string(engine_versions), versions_string(other.engine_versions)]
99
- elsif patchlevel && (!patchlevel.is_a?(String) || !other.patchlevel.is_a?(String) || !matches?(patchlevel, other.patchlevel))
100
- [:patchlevel, patchlevel, other.patchlevel]
101
99
  end
102
100
  end
103
101
 
@@ -13,7 +13,53 @@ require "rubygems" unless defined?(Gem)
13
13
  # `Gem::Source` from the redefined `Gem::Specification#source`.
14
14
  require "rubygems/source"
15
15
 
16
+ # Can be removed once RubyGems 4.0.0 support is dropped
17
+ unless Gem::BasicSpecification.method_defined?(:content_address)
18
+ Gem::BasicSpecification.attr_accessor :content_address
19
+ end
20
+
21
+ # Can be removed once RubyGems 4.0.0 support is dropped
22
+ unless Gem::NameTuple.method_defined?(:content_address)
23
+ Gem::NameTuple.attr_reader :content_address
24
+ end
25
+
16
26
  module Gem
27
+ # Can be removed once RubyGems 4.0.0 support is dropped
28
+ unless defined?(Gem::ContentAddress)
29
+ module ContentAddress
30
+ def self.match?(token)
31
+ false
32
+ end
33
+
34
+ def self.eligible?(spec, validate_ruby_abi: true)
35
+ false
36
+ end
37
+
38
+ def self.content_addressed?(spec, validate_ruby_abi: true)
39
+ false
40
+ end
41
+
42
+ def self.content_addressed_row?(suffix, platform, required_ruby_version = nil, validate_ruby_abi: true)
43
+ false
44
+ end
45
+ end
46
+ end
47
+
48
+ # Can be removed once RubyGems 4.0.0 support is dropped
49
+ class SpecificationRecord
50
+ unless respond_to?(:specification_dir_for)
51
+ def self.specification_dir_for(spec, base_dir)
52
+ File.join(base_dir, "specifications")
53
+ end
54
+ end
55
+
56
+ unless respond_to?(:dirs_from)
57
+ def self.dirs_from(paths)
58
+ paths.map {|path| File.join(path, "specifications") }
59
+ end
60
+ end
61
+ end
62
+
17
63
  # Can be removed once RubyGems 3.5.11 support is dropped
18
64
  unless Gem.respond_to?(:freebsd_platform?)
19
65
  def self.freebsd_platform?
@@ -235,6 +281,20 @@ module Gem
235
281
  end
236
282
  end
237
283
 
284
+ alias_method :rg_build_info_dir, :build_info_dir
285
+ def build_info_dir
286
+ # A git checkout's build logs belong with that checkout's extension build.
287
+ # base_dir points at the directory holding every checkout, so logs keyed by
288
+ # full_name would collide between revisions of the same gem and would sit
289
+ # outside anything `bundle clean` prunes. extension_dir is unique per
290
+ # revision and goes away with the checkout.
291
+ if source.respond_to?(:extension_dir_name)
292
+ extension_dir
293
+ else
294
+ rg_build_info_dir
295
+ end
296
+ end
297
+
238
298
  # Can be removed once RubyGems 3.5.21 support is dropped
239
299
  remove_method :gem_dir if method_defined?(:gem_dir, false)
240
300
 
@@ -417,7 +477,8 @@ module Gem
417
477
  unless Gem::NameTuple.new("a", Gem::Version.new("1"), Gem::Platform.new("x86_64-linux")).platform.is_a?(String)
418
478
  alias_method :initialize_with_platform, :initialize
419
479
 
420
- def initialize(name, version, platform = Gem::Platform::RUBY)
480
+ def initialize(name, version, platform = Gem::Platform::RUBY, content_address = nil)
481
+ @content_address = content_address
421
482
  if Gem::Platform === platform
422
483
  initialize_with_platform(name, version, platform.to_s)
423
484
  else
@@ -426,6 +487,15 @@ module Gem
426
487
  end
427
488
  end
428
489
 
490
+ unless instance_method(:initialize).parameters.any? {|kind, name| kind == :key && name == :content_address }
491
+ alias_method :initialize_without_content_address, :initialize
492
+
493
+ def initialize(name, version, platform = Gem::Platform::RUBY, content_address: nil)
494
+ initialize_without_content_address(name, version, platform)
495
+ @content_address = content_address
496
+ end
497
+ end
498
+
429
499
  def lock_name
430
500
  if platform == Gem::Platform::RUBY
431
501
  "#{name} (#{version})"
@@ -4,6 +4,11 @@ require "rubygems/installer"
4
4
 
5
5
  module Bundler
6
6
  class RubyGemsGemInstaller < Gem::Installer
7
+ # Can be removed once RubyGems 4.0.0 support is dropped
8
+ unless private_method_defined?(:assign_content_address)
9
+ private def assign_content_address; end
10
+ end
11
+
7
12
  # Cap how many jobserver slots a single gem's `make` may grab so that one
8
13
  # gem with many recipes doesn't starve the others sharing the pool. Beyond
9
14
  # a handful of jobs the extra parallelism rarely pays off in practice.
@@ -14,6 +19,8 @@ module Bundler
14
19
  end
15
20
 
16
21
  def install
22
+ assign_content_address
23
+
17
24
  pre_install_checks
18
25
 
19
26
  run_pre_install_hooks
@@ -32,7 +39,11 @@ module Bundler
32
39
  extract_files
33
40
  end
34
41
 
35
- build_extensions if spec.extensions.any?
42
+ if options[:build_extension] == false
43
+ warn_skipped_extensions
44
+ elsif spec.extensions.any?
45
+ build_extensions
46
+ end
36
47
  write_build_info_file
37
48
  run_post_build_hooks
38
49
 
@@ -40,7 +51,12 @@ module Bundler
40
51
  generate_bin
41
52
  end
42
53
 
43
- generate_plugins
54
+ if options[:install_plugin] == false
55
+ remove_stale_plugins
56
+ warn_skipped_plugins
57
+ else
58
+ generate_plugins
59
+ end
44
60
 
45
61
  write_spec
46
62
 
@@ -85,6 +101,29 @@ module Bundler
85
101
  end
86
102
  end
87
103
 
104
+ # Reimplemented from RubyGems, since RubyGems older than 4.1 doesn't
105
+ # provide it
106
+ def remove_stale_plugins
107
+ return unless spec.plugins.empty?
108
+
109
+ ensure_writable_dir @plugins_dir
110
+ remove_plugins_for(spec, @plugins_dir)
111
+ end
112
+
113
+ def warn_skipped_extensions
114
+ return if spec.extensions.empty?
115
+
116
+ Bundler.ui.warn "#{spec.full_name} contains native extensions that were not built.\n" \
117
+ "To build extensions, unset no_build_extension and run `bundle pristine #{spec.name}`."
118
+ end
119
+
120
+ def warn_skipped_plugins
121
+ return if spec.plugins.empty?
122
+
123
+ Bundler.ui.warn "#{spec.full_name} contains plugins that were not installed.\n" \
124
+ "To install plugins, unset no_install_plugin and run `bundle pristine #{spec.name}`."
125
+ end
126
+
88
127
  if Bundler.rubygems.provides?("< 3.5.19")
89
128
  def generate_bin_script(filename, bindir)
90
129
  bin_script_path = File.join bindir, formatted_program_filename(filename)
@@ -111,7 +111,7 @@ module Bundler
111
111
 
112
112
  def spec_cache_dirs
113
113
  @spec_cache_dirs ||= begin
114
- dirs = gem_path.map {|dir| File.join(dir, "specifications") }
114
+ dirs = gem_path.flat_map {|dir| Gem::SpecificationRecord.dirs_from([dir]) }
115
115
  dirs << Gem.spec_cache_dir
116
116
  dirs.uniq.select {|dir| File.directory? dir }
117
117
  end
@@ -144,7 +144,12 @@ module Bundler
144
144
 
145
145
  def spec_from_gem(path)
146
146
  require "rubygems/package"
147
- Gem::Package.new(path).spec
147
+ package = Gem::Package.new(path)
148
+ spec = package.spec
149
+ if package.respond_to?(:content_address)
150
+ spec.content_address = package.content_address
151
+ end
152
+ spec
148
153
  end
149
154
 
150
155
  def build_gem(gem_dir, spec)