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
@@ -7,12 +7,13 @@ module Bundler
7
7
  class Git < Path
8
8
  autoload :GitProxy, File.expand_path("git/git_proxy", __dir__)
9
9
 
10
- attr_reader :uri, :ref, :branch, :options, :glob, :submodules
10
+ attr_reader :uri, :ref, :branch, :options, :glob, :submodules, :sparse_checkout
11
11
 
12
12
  def initialize(options)
13
13
  @options = options
14
14
  @checksum_store = Checksum::Store.new
15
- @glob = options["glob"] || DEFAULT_GLOB
15
+ @sparse_checkout = normalize_sparse_checkout(options)
16
+ @glob = options["glob"] || sparse_checkout_glob || DEFAULT_GLOB
16
17
 
17
18
  @allow_cached = false
18
19
  @allow_remote = false
@@ -30,6 +31,7 @@ module Bundler
30
31
 
31
32
  @copied = false
32
33
  @local = false
34
+ @cached_app_cache_path = nil
33
35
  end
34
36
 
35
37
  def remote!
@@ -57,12 +59,13 @@ module Bundler
57
59
  %w[ref branch tag submodules].each do |opt|
58
60
  out << " #{opt}: #{options[opt]}\n" if options[opt]
59
61
  end
62
+ @sparse_checkout&.each {|dir| out << " sparse_checkout: #{dir}\n" }
60
63
  out << " glob: #{@glob}\n" unless default_glob?
61
64
  out << " specs:\n"
62
65
  end
63
66
 
64
67
  def to_gemfile
65
- specifiers = %w[ref branch tag submodules glob].map do |opt|
68
+ specifiers = %w[ref branch tag submodules glob sparse_checkout].map do |opt|
66
69
  "#{opt}: #{options[opt]}" if options[opt]
67
70
  end
68
71
 
@@ -70,14 +73,15 @@ module Bundler
70
73
  end
71
74
 
72
75
  def hash
73
- [self.class, uri, ref, branch, name, glob, submodules].hash
76
+ [self.class, uri, ref, branch, name, glob, submodules, sparse_checkout].hash
74
77
  end
75
78
 
76
79
  def eql?(other)
77
80
  other.is_a?(Git) && uri == other.uri && ref == other.ref &&
78
81
  branch == other.branch && name == other.name &&
79
82
  glob == other.glob &&
80
- submodules == other.submodules
83
+ submodules == other.submodules &&
84
+ sparse_checkout == other.sparse_checkout
81
85
  end
82
86
 
83
87
  alias_method :==, :eql?
@@ -86,7 +90,8 @@ module Bundler
86
90
  other.is_a?(Git) && uri == other.uri &&
87
91
  name == other.name &&
88
92
  glob == other.glob &&
89
- submodules == other.submodules
93
+ submodules == other.submodules &&
94
+ sparse_checkout == other.sparse_checkout
90
95
  end
91
96
 
92
97
  def to_s
@@ -191,8 +196,13 @@ module Bundler
191
196
  set_cache_path!(app_cache_path) if use_app_cache?
192
197
 
193
198
  if requires_checkout? && !@copied
194
- fetch unless use_app_cache?
195
- checkout
199
+ Plugin.hook(Plugin::Events::GIT_BEFORE_FETCH, self)
200
+ begin
201
+ fetch unless use_app_cache?
202
+ checkout
203
+ ensure
204
+ Plugin.hook(Plugin::Events::GIT_AFTER_FETCH, self)
205
+ end
196
206
  end
197
207
 
198
208
  local_specs
@@ -272,6 +282,11 @@ module Bundler
272
282
 
273
283
  app_cache_path = app_cache_path(custom_path)
274
284
 
285
+ # When several gems share a single git source, this is called once per
286
+ # gem. Copying the repository is expensive for large repos, so skip it
287
+ # if we already populated this cache during the same command.
288
+ return if @cached_app_cache_path == app_cache_path
289
+
275
290
  migrate = try_migrate ? bare_repo?(app_cache_path) : false
276
291
 
277
292
  set_cache_path!(nil) if migrate
@@ -283,6 +298,8 @@ module Bundler
283
298
  git_proxy.checkout if migrate || requires_checkout?
284
299
  git_proxy.copy_to(app_cache_path, @submodules)
285
300
  serialize_gemspecs_in(app_cache_path)
301
+
302
+ @cached_app_cache_path = app_cache_path
286
303
  end
287
304
 
288
305
  def checkout
@@ -376,7 +393,30 @@ module Bundler
376
393
  end
377
394
 
378
395
  def shortref_for_path(ref)
379
- ref[0..11]
396
+ shortref = ref[0..11]
397
+ return shortref unless @sparse_checkout
398
+
399
+ # Checkouts of the same revision with different cones hold different files
400
+ "#{shortref}-#{Bundler::Digest.sha1(@sparse_checkout.join("\n"))[0..7]}"
401
+ end
402
+
403
+ def normalize_sparse_checkout(options)
404
+ return unless options["sparse_checkout"]
405
+
406
+ dirs = Array(options["sparse_checkout"])
407
+ unless dirs.any? && dirs.all? {|dir| dir.is_a?(String) && !dir.empty? }
408
+ raise GemfileError, "The :sparse_checkout option must be a directory or an array of directories, " \
409
+ "but #{options["sparse_checkout"].inspect} was given"
410
+ end
411
+
412
+ options["sparse_checkout"] = dirs
413
+ end
414
+
415
+ def sparse_checkout_glob
416
+ return unless @sparse_checkout
417
+
418
+ dirs = @sparse_checkout.size == 1 ? @sparse_checkout.first : "{#{@sparse_checkout.join(",")}}"
419
+ "#{dirs}/#{DEFAULT_GLOB}"
380
420
  end
381
421
 
382
422
  def glob_for_display
@@ -405,10 +445,6 @@ module Bundler
405
445
  options["revision"]
406
446
  end
407
447
 
408
- def cached?
409
- cache_path.exist?
410
- end
411
-
412
448
  def git_proxy
413
449
  @git_proxy ||= GitProxy.new(cache_path, uri, options, locked_revision, self)
414
450
  end
@@ -24,7 +24,7 @@ module Bundler
24
24
  def post_install
25
25
  run_hooks(:pre_install)
26
26
 
27
- unless @disable_extensions
27
+ unless @disable_extensions || Bundler.settings[:no_build_extension]
28
28
  build_extensions
29
29
  run_hooks(:post_build)
30
30
  end
@@ -18,12 +18,17 @@ module Bundler
18
18
  end
19
19
 
20
20
  # Returns the cooldown days that apply to this remote, resolving the
21
- # precedence CLI > config > Gemfile per-source. Returns nil if no
22
- # cooldown applies.
21
+ # precedence CLI > config > Gemfile per-source and then raising the
22
+ # result to RubyGems' own setting. Returns nil if no cooldown applies.
23
+ #
24
+ # The resolver asks once per candidate spec, so the settings lookup is
25
+ # memoized. That snapshots the value: a Remote created before a
26
+ # settings change keeps the old one. Nothing in Bundler changes the
27
+ # cooldown setting after the sources are built (the CLI flag is applied
28
+ # before the Definition exists), so build a new Remote if you need to.
23
29
  def effective_cooldown
24
- override = Bundler.settings[:cooldown]
25
- return override if override
26
- @cooldown
30
+ return @effective_cooldown if defined?(@effective_cooldown)
31
+ @effective_cooldown = Bundler.settings.cooldown_for(@cooldown)
27
32
  end
28
33
 
29
34
  MAX_CACHE_SLUG_HOST_SIZE = 255 - 1 - 32 # 255 minus dot minus MD5 length
@@ -25,6 +25,7 @@ module Bundler
25
25
  @checksum_store = Checksum::Store.new
26
26
  @gem_installers = {}
27
27
  @gem_installers_mutex = Mutex.new
28
+ @remote_spec_for_mutex = Mutex.new
28
29
  @remote_specs_mutex = Mutex.new
29
30
 
30
31
  cooldown = options["cooldown"]
@@ -196,6 +197,8 @@ module Bundler
196
197
  "the security policy didn't allow it, with the message: #{e.message}"
197
198
  end
198
199
 
200
+ s.content_address = spec.content_address if spec.content_address
201
+
199
202
  spec.__swap__(s)
200
203
  end
201
204
 
@@ -230,8 +233,12 @@ module Bundler
230
233
  spec.post_install_message
231
234
  end
232
235
 
236
+ def uncached?(spec)
237
+ caches.none? {|cache| File.exist?(package_path(cache, spec)) }
238
+ end
239
+
233
240
  def cache(spec, custom_path = nil)
234
- cached_path = Bundler.settings[:cache_all_platforms] ? fetch_gem_if_possible(spec) : cached_gem(spec)
241
+ cached_path = fetch_gem_if_possible(spec)
235
242
  raise GemNotFound, "Missing gem file '#{spec.file_name}'." unless cached_path
236
243
  return if File.dirname(cached_path) == Bundler.app_cache.to_s
237
244
  Bundler.ui.info " * #{File.basename(cached_path)}"
@@ -437,12 +444,14 @@ module Bundler
437
444
  # Looks up a single spec in the remote sources, fetching only its own
438
445
  # name when the full remote index is not already materialized.
439
446
  def remote_spec_for(spec)
440
- return remote_specs.search(spec).first if @remote_specs || api_fetchers.empty?
447
+ @remote_spec_for_mutex.synchronize do
448
+ return remote_specs.search(spec).first if @remote_specs || api_fetchers.empty?
441
449
 
442
- index = Index.build do |idx|
443
- fetch_names(api_fetchers, [spec.name], idx)
450
+ index = Index.build do |idx|
451
+ fetch_names(api_fetchers, [spec.name], idx)
452
+ end
453
+ index.search(spec).first
444
454
  end
445
- index.search(spec).first
446
455
  end
447
456
 
448
457
  def fetch_names(fetchers, dependency_names, index)
@@ -462,10 +471,24 @@ module Bundler
462
471
  if spec.remote
463
472
  fetch_gem(spec, previous_spec)
464
473
  else
465
- cached_gem(spec)
474
+ cached_gem(spec) || refetch_gem(spec, previous_spec)
466
475
  end
467
476
  end
468
477
 
478
+ # An installed gem materializes without a remote, so a reinstall forced by
479
+ # `--redownload` has to look the gem up in the remote index again before it
480
+ # can download the archive that the cache no longer holds.
481
+ def refetch_gem(spec, previous_spec = nil)
482
+ return unless @allow_remote
483
+
484
+ remote_spec = remote_spec_for(spec)
485
+ return unless remote_spec && remote_spec.full_name == spec.full_name
486
+
487
+ path = fetch_gem(remote_spec, previous_spec)
488
+ spec.remote = remote_spec.remote
489
+ path
490
+ end
491
+
469
492
  def fetch_gem(spec, previous_spec = nil)
470
493
  spec.fetch_platform
471
494
 
@@ -545,8 +568,13 @@ module Bundler
545
568
  Bundler.ui.confirm("Fetching #{version_message(spec, previous_spec)}")
546
569
  gem_remote_fetcher = remote_fetchers.fetch(spec.remote).gem_remote_fetcher
547
570
 
548
- Gem.time("Downloaded #{spec.name} in", 0, true) do
549
- Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher)
571
+ Plugin.hook(Plugin::Events::GEM_BEFORE_FETCH, spec)
572
+ begin
573
+ Gem.time("Downloaded #{spec.name} in", 0, true) do
574
+ Bundler.rubygems.download_gem(spec, uri, download_cache_path, gem_remote_fetcher)
575
+ end
576
+ ensure
577
+ Plugin.hook(Plugin::Events::GEM_AFTER_FETCH, spec)
550
578
  end
551
579
  end
552
580
 
@@ -566,7 +594,12 @@ module Bundler
566
594
  return unless remote = spec.remote
567
595
  return unless cache_slug = remote.cache_slug
568
596
 
569
- Bundler.user_cache.join("gems", cache_slug)
597
+ if Gem.respond_to?(:global_gem_cache_path)
598
+ Pathname.new(Gem.global_gem_cache_path).join(cache_slug)
599
+ else
600
+ # Fall back to old location for older RubyGems versions
601
+ Bundler.user_cache.join("gems", cache_slug)
602
+ end
570
603
  end
571
604
 
572
605
  def extension_cache_slug(spec)
@@ -574,11 +607,11 @@ module Bundler
574
607
  remote.cache_slug
575
608
  end
576
609
 
577
- # We are using a mutex to reaed and write from/to the hash.
610
+ # We are using a mutex to read and write from/to the hash.
578
611
  # The reason this double synchronization was added is for performance
579
612
  # and to lock the mutex for the shortest possible amount of time. Otherwise,
580
613
  # all threads are fighting over this mutex and when it gets acquired it gets locked
581
- # until a threads finishes downloading a gem, leaving the other threads waiting
614
+ # until a thread finishes downloading a gem, leaving the other threads waiting
582
615
  # doing nothing.
583
616
  def rubygems_gem_installer(spec, options)
584
617
  @gem_installers_mutex.synchronize { @gem_installers[spec.name] } || begin
@@ -589,6 +622,7 @@ module Bundler
589
622
 
590
623
  installer = Bundler::RubyGemsGemInstaller.at(
591
624
  path,
625
+ content_address: (spec.content_address if Gem::ContentAddress.content_addressed?(spec, validate_ruby_abi: false)),
592
626
  security_policy: Bundler.rubygems.security_policies[Bundler.settings["trust-policy"]],
593
627
  install_dir: rubygems_dir.to_s,
594
628
  bin_dir: Bundler.system_bindir.to_s,
@@ -596,7 +630,9 @@ module Bundler
596
630
  wrappers: true,
597
631
  env_shebang: true,
598
632
  build_args: options[:build_args],
599
- bundler_extension_cache_path: extension_cache_path(spec)
633
+ bundler_extension_cache_path: extension_cache_path(spec),
634
+ build_extension: Bundler.settings[:no_build_extension] ? false : nil,
635
+ install_plugin: Bundler.settings[:no_install_plugin] ? false : nil
600
636
  )
601
637
  @gem_installers_mutex.synchronize { @gem_installers[spec.name] ||= installer }
602
638
  end
@@ -29,7 +29,7 @@ module Bundler
29
29
 
30
30
  def build_index
31
31
  Index.build do |idx|
32
- dependency_names = source_map.pinned_spec_names
32
+ dependency_names = source_map.pinned_spec_names | source_map.replacement_names
33
33
 
34
34
  sources.all_sources.each do |source|
35
35
  next if @excluded_sources.include?(source)
@@ -2,12 +2,15 @@
2
2
 
3
3
  module Bundler
4
4
  class SourceMap
5
- attr_reader :sources, :dependencies, :locked_specs
5
+ attr_reader :sources, :dependencies, :locked_specs, :replacement_names
6
6
 
7
- def initialize(sources, dependencies, locked_specs)
7
+ def initialize(sources, dependencies, locked_specs, replacement_names = [])
8
8
  @sources = sources
9
9
  @dependencies = dependencies
10
10
  @locked_specs = locked_specs
11
+ # No gemspec names a gem that a `from:`/`to:` override substitutes, so
12
+ # the dependency API never fetches it unless asked.
13
+ @replacement_names = replacement_names
11
14
  end
12
15
 
13
16
  def pinned_spec_names(skip = nil)
@@ -22,6 +25,7 @@ module Bundler
22
25
  end
23
26
 
24
27
  unmet_deps = explicit_sources.map do |source|
28
+ source.add_dependency_names(replacement_names)
25
29
  (source.spec_names - pinned_spec_names).each do |indirect_dependency_name|
26
30
  previous_source = requirements[indirect_dependency_name]
27
31
  if previous_source.nil?
@@ -39,7 +43,7 @@ module Bundler
39
43
  source.unmet_deps
40
44
  end
41
45
 
42
- sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys)
46
+ sources.default_source.add_dependency_names(unmet_deps.flatten + replacement_names - requirements.keys)
43
47
 
44
48
  requirements
45
49
  end
@@ -84,11 +84,14 @@ module Bundler
84
84
  platforms.delete(Bundler.local_platform) if less_specific_platform
85
85
  end
86
86
 
87
- def validate_deps(s)
88
- s.runtime_dependencies.each do |dep|
87
+ def validate_deps(s, overrides = s.is_a?(LazySpecification) ? Array(s.overrides) : [])
88
+ Override.rewrite_dependencies(overrides, s.name, s.runtime_dependencies).each do |dep|
89
89
  next if dep.name == "bundler"
90
90
 
91
91
  return :missing unless names.include?(dep.name)
92
+
93
+ override = Override.find_for(overrides, dep.name, :version)
94
+ dep = Gem::Dependency.new(dep.name, override.apply_to(dep.requirement)) if override
92
95
  return :invalid if none? {|spec| dep.matches_spec?(spec) }
93
96
  end
94
97
 
@@ -178,7 +181,7 @@ module Bundler
178
181
  end
179
182
 
180
183
  def find_by_name_and_platform(name, platform)
181
- @specs.detect {|spec| spec.name == name && spec.installable_on_platform?(platform) }
184
+ lookup[name]&.detect {|spec| spec.installable_on_platform?(platform) }
182
185
  end
183
186
 
184
187
  def specs_with_additional_variants_from(other)
@@ -274,13 +277,25 @@ module Bundler
274
277
 
275
278
  valid_platform = lookup.all? do |_, specs|
276
279
  spec = specs.first
280
+ # The matching candidates returned by source.specs.search are remote
281
+ # specs that do not carry the override list themselves. Borrow it from
282
+ # the LazySpec we are validating so platform-variant validation honors
283
+ # the same overrides the install/resolve path already applies.
284
+ overrides = spec.is_a?(LazySpecification) ? Array(spec.overrides) : []
277
285
  matching_specs = spec.source.specs.search([spec.name, spec.version])
278
286
  platform_spec = MatchPlatform.select_best_platform_match(matching_specs, platform).find do |s|
279
- valid?(s)
287
+ s.matches_current_metadata_with_overrides?(overrides) && validate_deps(s, overrides) == :valid
280
288
  end
281
289
 
282
290
  if platform_spec
283
- new_specs << LazySpecification.from_spec(platform_spec) unless specs.include?(platform_spec)
291
+ unless specs.include?(platform_spec)
292
+ new_lazy = LazySpecification.from_spec(platform_spec)
293
+ # Carry the overrides forward so a follow-up complete_platform
294
+ # call that picks this synthesized variant as its exemplar still
295
+ # honors the user's override list.
296
+ new_lazy.overrides = overrides if overrides.any?
297
+ new_specs << new_lazy
298
+ end
284
299
  true
285
300
  else
286
301
  false
@@ -314,7 +329,7 @@ module Bundler
314
329
  end
315
330
 
316
331
  def sorted
317
- @sorted ||= ([@specs.find {|s| s.name == "rake" }] + tsort).compact.uniq
332
+ @sorted ||= ([lookup["rake"]&.first] + tsort).compact.uniq
318
333
  rescue Gem::TSort::Cyclic => error
319
334
  cgems = extract_circular_gems(error)
320
335
  raise CyclicDependencyError, "Your bundle requires gems that depend" \
@@ -342,7 +357,8 @@ module Bundler
342
357
  end
343
358
 
344
359
  def tsort_each_child(s)
345
- s.dependencies.sort_by(&:name).each do |d|
360
+ dependencies = s.is_a?(LazySpecification) ? Override.rewrite_dependencies(s.overrides, s.name, s.dependencies) : s.dependencies
361
+ dependencies.sort_by(&:name).each do |d|
346
362
  next if d.type == :development
347
363
 
348
364
  specs_for_name = lookup[d.name]
@@ -4,7 +4,8 @@ module Bundler
4
4
  class StubSpecification < RemoteSpecification
5
5
  def self.from_stub(stub)
6
6
  return stub if stub.is_a?(Bundler::StubSpecification)
7
- spec = new(stub.name, stub.version, stub.platform, nil)
7
+ content_address = stub.content_address
8
+ spec = new(stub.name, stub.version, stub.platform, nil, content_address: content_address)
8
9
  spec.stub = stub
9
10
  spec
10
11
  end
@@ -6,19 +6,19 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "irb"
9
- gem "rake", "~> 13.0"
9
+ gem "rake", ">= 13.0"
10
10
  <%- if config[:ext] -%>
11
11
 
12
12
  gem "rake-compiler"
13
13
  <%- end -%>
14
14
  <%- if config[:test] -%>
15
15
 
16
- gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>"
16
+ gem "<%= config[:test] %>"
17
17
  <%- end -%>
18
18
  <%- if config[:linter] == "rubocop" -%>
19
19
 
20
- gem "rubocop", "~> <%= config[:linter_version] %>"
20
+ gem "rubocop"
21
21
  <%- elsif config[:linter] == "standard" -%>
22
22
 
23
- gem "standard", "~> <%= config[:linter_version] %>"
23
+ gem "standard"
24
24
  <%- end -%>
@@ -45,12 +45,12 @@ Gem::Specification.new do |spec|
45
45
  <%- end -%>
46
46
 
47
47
  # Uncomment to register a new dependency of your gem
48
- # spec.add_dependency "example-gem", "~> 1.0"
48
+ # spec.add_dependency "example-gem", ">= 1.0"
49
49
  <%- if config[:ext] == 'rust' -%>
50
- spec.add_dependency "rb_sys", "~> 0.9.128"
50
+ spec.add_dependency "rb_sys", ">= 0.9.128"
51
51
  <%- end -%>
52
52
  <%- if config[:ext] == 'go' -%>
53
- spec.add_dependency "go_gem", "~> 0.2"
53
+ spec.add_dependency "go_gem", ">= 0.2"
54
54
  <%- end -%>
55
55
 
56
56
  # For more information and examples about making a new gem, check out our
@@ -9,7 +9,7 @@ RSpec.describe <%= config[:constant_name] %> do
9
9
  it "can call into Rust" do
10
10
  result = <%= config[:constant_name] %>.hello("world")
11
11
 
12
- expect(result).to be("Hello earth, from Rust!")
12
+ expect(result).to eq("Hello world, from Rust!")
13
13
  end
14
14
  <%- else -%>
15
15
  it "does something useful" do
@@ -9,7 +9,7 @@ class <%= config[:minitest_constant_name] %> < Minitest::Test
9
9
 
10
10
  <%- if config[:ext] == 'rust' -%>
11
11
  def test_hello_world
12
- assert_equal "Hello earth, from Rust!", <%= config[:constant_name] %>.hello("world")
12
+ assert_equal "Hello world, from Rust!", <%= config[:constant_name] %>.hello("world")
13
13
  end
14
14
  <%- else -%>
15
15
  def test_it_does_something_useful
@@ -76,10 +76,6 @@ module Bundler
76
76
  level("debug")
77
77
  end
78
78
 
79
- def quiet?
80
- level("quiet")
81
- end
82
-
83
79
  def ask(msg)
84
80
  @shell.ask(msg, :green)
85
81
  end
@@ -45,10 +45,6 @@ module Bundler
45
45
  false
46
46
  end
47
47
 
48
- def quiet?
49
- false
50
- end
51
-
52
48
  def warn?
53
49
  false
54
50
  end
@@ -2,6 +2,38 @@ require_relative "empty_directory"
2
2
 
3
3
  class Bundler::Thor
4
4
  module Actions
5
+ WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
6
+
7
+ # Injects the given content into a file, raising an error if the contents of
8
+ # the file are not changed. Different from gsub_file, this method is reversible.
9
+ #
10
+ # ==== Parameters
11
+ # destination<String>:: Relative path to the destination root
12
+ # data<String>:: Data to add to the file. Can be given as a block.
13
+ # config<Hash>:: give :verbose => false to not log the status and the flag
14
+ # for injection (:after or :before) or :force => true for
15
+ # insert two or more times the same content.
16
+ #
17
+ # ==== Examples
18
+ #
19
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
20
+ #
21
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
22
+ # gems = ask "Which gems would you like to add?"
23
+ # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
24
+ # end
25
+ #
26
+ def insert_into_file!(destination, *args, &block)
27
+ data = block_given? ? block : args.shift
28
+
29
+ config = args.shift || {}
30
+ config[:after] = /\z/ unless config.key?(:before) || config.key?(:after)
31
+ config = config.merge({error_on_no_change: true})
32
+
33
+ action InjectIntoFile.new(self, destination, data, config)
34
+ end
35
+ alias_method :inject_into_file!, :insert_into_file!
36
+
5
37
  # Injects the given content into a file. Different from gsub_file, this
6
38
  # method is reversible.
7
39
  #
@@ -21,8 +53,6 @@ class Bundler::Thor
21
53
  # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
22
54
  # end
23
55
  #
24
- WARNINGS = {unchanged_no_flag: "File unchanged! Either the supplied flag value not found or the content has already been inserted!"}
25
-
26
56
  def insert_into_file(destination, *args, &block)
27
57
  data = block_given? ? block : args.shift
28
58
 
@@ -47,6 +77,7 @@ class Bundler::Thor
47
77
 
48
78
  @replacement = data.is_a?(Proc) ? data.call : data
49
79
  @flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
80
+ @error_on_no_change = @config.fetch(:error_on_no_change, false)
50
81
  end
51
82
 
52
83
  def invoke!
@@ -59,6 +90,8 @@ class Bundler::Thor
59
90
  if exists?
60
91
  if replace!(/#{flag}/, content, config[:force])
61
92
  say_status(:invoke)
93
+ elsif @error_on_no_change
94
+ raise Bundler::Thor::Error, "The content of #{destination} did not change"
62
95
  elsif replacement_present?
63
96
  say_status(:unchanged, color: :blue)
64
97
  else
@@ -13,8 +13,9 @@ class Bundler::Thor
13
13
  autoload :RakeCompat, File.expand_path("rake_compat", __dir__)
14
14
  autoload :Group, File.expand_path("group", __dir__)
15
15
 
16
- # Shortcuts for help.
16
+ # Shortcuts for help and tree commands.
17
17
  HELP_MAPPINGS = %w(-h -? --help -D)
18
+ TREE_MAPPINGS = %w(-t --tree)
18
19
 
19
20
  # Bundler::Thor methods that should not be overwritten by the user.
20
21
  THOR_RESERVED_WORDS = %w(invoke shell options behavior root destination_root relative_root
@@ -311,13 +311,11 @@ class Bundler::Thor
311
311
  end
312
312
 
313
313
  def show_diff(destination, content) #:nodoc:
314
- diff_cmd = ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u"
315
-
316
314
  require "tempfile"
317
315
  Tempfile.open(File.basename(destination), File.dirname(destination), binmode: true) do |temp|
318
316
  temp.write content
319
317
  temp.rewind
320
- system %(#{diff_cmd} "#{destination}" "#{temp.path}")
318
+ system(*diff_tool, destination, temp.path)
321
319
  end
322
320
  end
323
321
 
@@ -369,15 +367,25 @@ class Bundler::Thor
369
367
 
370
368
  def merge(destination, content) #:nodoc:
371
369
  require "tempfile"
372
- Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination)) do |temp|
370
+ Tempfile.open([File.basename(destination), File.extname(destination)], File.dirname(destination), binmode: true) do |temp|
373
371
  temp.write content
374
372
  temp.rewind
375
- system(merge_tool, temp.path, destination)
373
+ system(*merge_tool, temp.path, destination)
376
374
  end
377
375
  end
378
376
 
379
377
  def merge_tool #:nodoc:
380
- @merge_tool ||= ENV["THOR_MERGE"] || "git difftool --no-index"
378
+ @merge_tool ||= begin
379
+ require "shellwords"
380
+ Shellwords.split(ENV["THOR_MERGE"] || "git difftool --no-index")
381
+ end
382
+ end
383
+
384
+ def diff_tool #:nodoc:
385
+ @diff_cmd ||= begin
386
+ require "shellwords"
387
+ Shellwords.split(ENV["THOR_DIFF"] || ENV["RAILS_DIFF"] || "diff -u")
388
+ end
381
389
  end
382
390
  end
383
391
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "basic"
2
4
 
3
5
  class Bundler::Thor
@@ -1,3 +1,3 @@
1
1
  class Bundler::Thor
2
- VERSION = "1.4.0"
2
+ VERSION = "1.5.0"
3
3
  end