bundler 2.2.15 → 2.2.20

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -6
  3. data/bundler.gemspec +2 -3
  4. data/lib/bundler.rb +1 -0
  5. data/lib/bundler/build_metadata.rb +2 -2
  6. data/lib/bundler/cli.rb +16 -35
  7. data/lib/bundler/cli/check.rb +4 -2
  8. data/lib/bundler/cli/common.rb +15 -2
  9. data/lib/bundler/cli/gem.rb +9 -1
  10. data/lib/bundler/cli/outdated.rb +10 -11
  11. data/lib/bundler/compact_index_client/updater.rb +9 -5
  12. data/lib/bundler/current_ruby.rb +1 -0
  13. data/lib/bundler/definition.rb +27 -84
  14. data/lib/bundler/feature_flag.rb +0 -2
  15. data/lib/bundler/fetcher.rb +2 -1
  16. data/lib/bundler/fetcher/downloader.rb +8 -4
  17. data/lib/bundler/fetcher/index.rb +0 -1
  18. data/lib/bundler/friendly_errors.rb +2 -4
  19. data/lib/bundler/gem_helper.rb +16 -0
  20. data/lib/bundler/index.rb +1 -2
  21. data/lib/bundler/injector.rb +2 -2
  22. data/lib/bundler/inline.rb +1 -1
  23. data/lib/bundler/lazy_specification.rb +3 -3
  24. data/lib/bundler/man/bundle-add.1 +1 -1
  25. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  26. data/lib/bundler/man/bundle-cache.1 +1 -1
  27. data/lib/bundler/man/bundle-check.1 +1 -1
  28. data/lib/bundler/man/bundle-clean.1 +1 -1
  29. data/lib/bundler/man/bundle-config.1 +21 -10
  30. data/lib/bundler/man/bundle-config.1.ronn +21 -11
  31. data/lib/bundler/man/bundle-doctor.1 +1 -1
  32. data/lib/bundler/man/bundle-exec.1 +1 -1
  33. data/lib/bundler/man/bundle-gem.1 +1 -1
  34. data/lib/bundler/man/bundle-info.1 +1 -1
  35. data/lib/bundler/man/bundle-init.1 +1 -1
  36. data/lib/bundler/man/bundle-inject.1 +1 -1
  37. data/lib/bundler/man/bundle-install.1 +1 -1
  38. data/lib/bundler/man/bundle-list.1 +1 -1
  39. data/lib/bundler/man/bundle-lock.1 +1 -1
  40. data/lib/bundler/man/bundle-open.1 +1 -1
  41. data/lib/bundler/man/bundle-outdated.1 +1 -1
  42. data/lib/bundler/man/bundle-platform.1 +1 -1
  43. data/lib/bundler/man/bundle-pristine.1 +1 -1
  44. data/lib/bundler/man/bundle-remove.1 +1 -1
  45. data/lib/bundler/man/bundle-show.1 +1 -1
  46. data/lib/bundler/man/bundle-update.1 +1 -1
  47. data/lib/bundler/man/bundle-viz.1 +1 -1
  48. data/lib/bundler/man/bundle.1 +1 -1
  49. data/lib/bundler/man/gemfile.5 +1 -1
  50. data/lib/bundler/plugin.rb +2 -2
  51. data/lib/bundler/plugin/api/source.rb +14 -0
  52. data/lib/bundler/resolver.rb +13 -96
  53. data/lib/bundler/resolver/spec_group.rb +0 -24
  54. data/lib/bundler/retry.rb +1 -1
  55. data/lib/bundler/rubygems_ext.rb +2 -2
  56. data/lib/bundler/rubygems_integration.rb +4 -3
  57. data/lib/bundler/settings.rb +74 -12
  58. data/lib/bundler/source.rb +11 -0
  59. data/lib/bundler/source/rubygems.rb +23 -10
  60. data/lib/bundler/source/rubygems_aggregate.rb +64 -0
  61. data/lib/bundler/source_list.rb +33 -10
  62. data/lib/bundler/source_map.rb +58 -0
  63. data/lib/bundler/spec_set.rb +18 -7
  64. data/lib/bundler/templates/Gemfile +1 -1
  65. data/lib/bundler/templates/gems.rb +1 -1
  66. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +2 -4
  67. data/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
  68. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +1 -1
  69. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +1 -1
  70. data/lib/bundler/vendor/tmpdir/lib/tmpdir.rb +1 -1
  71. data/lib/bundler/version.rb +1 -1
  72. metadata +5 -3
@@ -13,6 +13,7 @@ module Bundler
13
13
  auto_install
14
14
  cache_all
15
15
  cache_all_platforms
16
+ clean
16
17
  default_install_uses_path
17
18
  deployment
18
19
  deployment_means_frozen
@@ -20,20 +21,21 @@ module Bundler
20
21
  disable_exec_load
21
22
  disable_local_branch_check
22
23
  disable_local_revision_check
23
- disable_multisource
24
24
  disable_shared_gems
25
25
  disable_version_check
26
26
  force_ruby_platform
27
27
  forget_cli_options
28
28
  frozen
29
+ gem.changelog
29
30
  gem.coc
30
31
  gem.mit
32
+ git.allow_insecure
31
33
  global_gem_cache
32
34
  ignore_messages
33
35
  init_gems_rb
36
+ inline
34
37
  no_install
35
38
  no_prune
36
- only_update_to_newer_versions
37
39
  path_relative_to_cwd
38
40
  path.system
39
41
  plugins
@@ -61,6 +63,22 @@ module Bundler
61
63
  without
62
64
  ].freeze
63
65
 
66
+ STRING_KEYS = %w[
67
+ bin
68
+ cache_path
69
+ console
70
+ gem.ci
71
+ gem.github_username
72
+ gem.linter
73
+ gem.rubocop
74
+ gem.test
75
+ gemfile
76
+ path
77
+ shebang
78
+ system_bindir
79
+ trust-policy
80
+ ].freeze
81
+
64
82
  DEFAULT_CONFIG = {
65
83
  "BUNDLE_SILENCE_DEPRECATIONS" => false,
66
84
  "BUNDLE_DISABLE_VERSION_CHECK" => true,
@@ -126,8 +144,8 @@ module Bundler
126
144
  keys = @temporary.keys | @global_config.keys | @local_config.keys | @env_config.keys
127
145
 
128
146
  keys.map do |key|
129
- key.sub(/^BUNDLE_/, "").gsub(/__/, ".").downcase
130
- end
147
+ key.sub(/^BUNDLE_/, "").gsub(/___/, "-").gsub(/__/, ".").downcase
148
+ end.sort
131
149
  end
132
150
 
133
151
  def local_overrides
@@ -173,19 +191,19 @@ module Bundler
173
191
  locations = []
174
192
 
175
193
  if value = @temporary[key]
176
- locations << "Set for the current command: #{converted_value(value, exposed_key).inspect}"
194
+ locations << "Set for the current command: #{printable_value(value, exposed_key).inspect}"
177
195
  end
178
196
 
179
197
  if value = @local_config[key]
180
- locations << "Set for your local app (#{local_config_file}): #{converted_value(value, exposed_key).inspect}"
198
+ locations << "Set for your local app (#{local_config_file}): #{printable_value(value, exposed_key).inspect}"
181
199
  end
182
200
 
183
201
  if value = @env_config[key]
184
- locations << "Set via #{key}: #{converted_value(value, exposed_key).inspect}"
202
+ locations << "Set via #{key}: #{printable_value(value, exposed_key).inspect}"
185
203
  end
186
204
 
187
205
  if value = @global_config[key]
188
- locations << "Set for the current user (#{global_config_file}): #{converted_value(value, exposed_key).inspect}"
206
+ locations << "Set for the current user (#{global_config_file}): #{printable_value(value, exposed_key).inspect}"
189
207
  end
190
208
 
191
209
  return ["You have not configured a value for `#{exposed_key}`"] if locations.empty?
@@ -277,9 +295,7 @@ module Bundler
277
295
  end
278
296
 
279
297
  def key_for(key)
280
- key = Settings.normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key
281
- key = key.to_s.gsub(".", "__").upcase
282
- "BUNDLE_#{key}"
298
+ self.class.key_for(key)
283
299
  end
284
300
 
285
301
  private
@@ -314,6 +330,10 @@ module Bundler
314
330
  BOOL_KEYS.include?(name.to_s) || BOOL_KEYS.include?(parent_setting_for(name.to_s))
315
331
  end
316
332
 
333
+ def is_string(name)
334
+ STRING_KEYS.include?(name.to_s) || name.to_s.start_with?("local.") || name.to_s.start_with?("mirror.") || name.to_s.start_with?("build.")
335
+ end
336
+
317
337
  def to_bool(value)
318
338
  case value
319
339
  when nil, /\A(false|f|no|n|0|)\z/i, false
@@ -331,6 +351,14 @@ module Bundler
331
351
  ARRAY_KEYS.include?(key.to_s)
332
352
  end
333
353
 
354
+ def is_credential(key)
355
+ key == "gem.push_key"
356
+ end
357
+
358
+ def is_userinfo(value)
359
+ value.include?(":")
360
+ end
361
+
334
362
  def to_array(value)
335
363
  return [] unless value
336
364
  value.split(":").map(&:to_sym)
@@ -377,6 +405,21 @@ module Bundler
377
405
  end
378
406
  end
379
407
 
408
+ def printable_value(value, key)
409
+ converted = converted_value(value, key)
410
+ return converted unless converted.is_a?(String)
411
+
412
+ if is_string(key)
413
+ converted
414
+ elsif is_credential(key)
415
+ "[REDACTED]"
416
+ elsif is_userinfo(converted)
417
+ converted.gsub(/:.*$/, ":[REDACTED]")
418
+ else
419
+ converted
420
+ end
421
+ end
422
+
380
423
  def global_config_file
381
424
  if ENV["BUNDLE_CONFIG"] && !ENV["BUNDLE_CONFIG"].empty?
382
425
  Pathname.new(ENV["BUNDLE_CONFIG"])
@@ -399,7 +442,20 @@ module Bundler
399
442
  valid_file = file.exist? && !file.size.zero?
400
443
  return {} unless valid_file
401
444
  require_relative "yaml_serializer"
402
- YAMLSerializer.load file.read
445
+ YAMLSerializer.load(file.read).inject({}) do |config, (k, v)|
446
+ new_k = k
447
+
448
+ if k.include?("-")
449
+ Bundler.ui.warn "Your #{file} config includes `#{k}`, which contains the dash character (`-`).\n" \
450
+ "This is deprecated, because configuration through `ENV` should be possible, but `ENV` keys cannot include dashes.\n" \
451
+ "Please edit #{file} and replace any dashes in configuration keys with a triple underscore (`___`)."
452
+
453
+ new_k = k.gsub("-", "___")
454
+ end
455
+
456
+ config[new_k] = v
457
+ config
458
+ end
403
459
  end
404
460
  end
405
461
 
@@ -416,6 +472,12 @@ module Bundler
416
472
  \z
417
473
  /ix.freeze
418
474
 
475
+ def self.key_for(key)
476
+ key = normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key
477
+ key = key.to_s.gsub(".", "__").gsub("-", "___").upcase
478
+ "BUNDLE_#{key}"
479
+ end
480
+
419
481
  # TODO: duplicates Rubygems#normalize_uri
420
482
  # TODO: is this the correct place to validate mirror URIs?
421
483
  def self.normalize_uri(uri)
@@ -7,6 +7,7 @@ module Bundler
7
7
  autoload :Metadata, File.expand_path("source/metadata", __dir__)
8
8
  autoload :Path, File.expand_path("source/path", __dir__)
9
9
  autoload :Rubygems, File.expand_path("source/rubygems", __dir__)
10
+ autoload :RubygemsAggregate, File.expand_path("source/rubygems_aggregate", __dir__)
10
11
 
11
12
  attr_accessor :dependency_names
12
13
 
@@ -35,10 +36,16 @@ module Bundler
35
36
 
36
37
  def local!; end
37
38
 
39
+ def local_only!; end
40
+
38
41
  def cached!; end
39
42
 
40
43
  def remote!; end
41
44
 
45
+ def add_dependency_names(names)
46
+ @dependency_names = Array(dependency_names) | Array(names)
47
+ end
48
+
42
49
  # it's possible that gems from one source depend on gems from some
43
50
  # other source, so now we download gemspecs and iterate over those
44
51
  # dependencies, looking for gems we don't have info on yet.
@@ -48,6 +55,10 @@ module Bundler
48
55
  specs.dependency_names
49
56
  end
50
57
 
58
+ def spec_names
59
+ specs.spec_names
60
+ end
61
+
51
62
  def include?(other)
52
63
  other == self
53
64
  end
@@ -26,6 +26,12 @@ module Bundler
26
26
  Array(options["remotes"]).reverse_each {|r| add_remote(r) }
27
27
  end
28
28
 
29
+ def local_only!
30
+ @specs = nil
31
+ @allow_local = true
32
+ @allow_remote = false
33
+ end
34
+
29
35
  def local!
30
36
  return if @allow_local
31
37
 
@@ -259,8 +265,16 @@ module Bundler
259
265
  !equivalent
260
266
  end
261
267
 
268
+ def spec_names
269
+ if @allow_remote && dependency_api_available?
270
+ remote_specs.spec_names
271
+ else
272
+ []
273
+ end
274
+ end
275
+
262
276
  def unmet_deps
263
- if @allow_remote && api_fetchers.any?
277
+ if @allow_remote && dependency_api_available?
264
278
  remote_specs.unmet_dependency_names
265
279
  else
266
280
  []
@@ -276,7 +290,7 @@ module Bundler
276
290
 
277
291
  def double_check_for(unmet_dependency_names)
278
292
  return unless @allow_remote
279
- return unless api_fetchers.any?
293
+ return unless dependency_api_available?
280
294
 
281
295
  unmet_dependency_names = unmet_dependency_names.call
282
296
  unless unmet_dependency_names.nil?
@@ -298,17 +312,20 @@ module Bundler
298
312
  remote_specs.each do |spec|
299
313
  case spec
300
314
  when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification
301
- names.concat(spec.runtime_dependencies)
315
+ names.concat(spec.runtime_dependencies.map(&:name))
302
316
  when RemoteSpecification # from the full index
303
317
  return nil
304
318
  else
305
319
  raise "unhandled spec type (#{spec.inspect})"
306
320
  end
307
321
  end
308
- names.map!(&:name) if names
309
322
  names
310
323
  end
311
324
 
325
+ def dependency_api_available?
326
+ api_fetchers.any?
327
+ end
328
+
312
329
  protected
313
330
 
314
331
  def credless_remotes
@@ -387,10 +404,6 @@ module Bundler
387
404
  next if gemfile =~ /^bundler\-[\d\.]+?\.gem/
388
405
  s ||= Bundler.rubygems.spec_from_gem(gemfile)
389
406
  s.source = self
390
- if Bundler.rubygems.spec_missing_extensions?(s, false)
391
- Bundler.ui.debug "Source #{self} is ignoring #{s} because it is missing extensions"
392
- next
393
- end
394
407
  idx << s
395
408
  end
396
409
 
@@ -423,11 +436,11 @@ module Bundler
423
436
  def fetch_names(fetchers, dependency_names, index, override_dupes)
424
437
  fetchers.each do |f|
425
438
  if dependency_names
426
- Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug?
439
+ Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug?
427
440
  index.use f.specs_with_retry(dependency_names, self), override_dupes
428
441
  Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
429
442
  else
430
- Bundler.ui.info "Fetching source index from #{f.uri}"
443
+ Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}"
431
444
  index.use f.specs_with_retry(nil, self), override_dupes
432
445
  end
433
446
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ class Source
5
+ class RubygemsAggregate
6
+ attr_reader :source_map, :sources
7
+
8
+ def initialize(sources, source_map)
9
+ @sources = sources
10
+ @source_map = source_map
11
+
12
+ @index = build_index
13
+ end
14
+
15
+ def specs
16
+ @index
17
+ end
18
+
19
+ def to_s
20
+ "any of the sources"
21
+ end
22
+
23
+ private
24
+
25
+ def build_index
26
+ Index.build do |idx|
27
+ dependency_names = source_map.pinned_spec_names
28
+
29
+ sources.all_sources.each do |source|
30
+ source.dependency_names = dependency_names - source_map.pinned_spec_names(source)
31
+ idx.add_source source.specs
32
+ dependency_names.concat(source.unmet_deps).uniq!
33
+ end
34
+
35
+ double_check_for_index(idx, dependency_names)
36
+ end
37
+ end
38
+
39
+ # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both
40
+ # sources A and B. At this point, the API request will have found all the versions of Bar in source A,
41
+ # but will not have found any versions of Bar from source B, which is a problem if the requested version
42
+ # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for
43
+ # each spec we found, we add all possible versions from all sources to the index.
44
+ def double_check_for_index(idx, dependency_names)
45
+ pinned_names = source_map.pinned_spec_names
46
+
47
+ names = :names # do this so we only have to traverse to get dependency_names from the index once
48
+ unmet_dependency_names = lambda do
49
+ return names unless names == :names
50
+ new_names = sources.all_sources.map(&:dependency_names_to_double_check)
51
+ return names = nil if new_names.compact!
52
+ names = new_names.flatten(1).concat(dependency_names)
53
+ names.uniq!
54
+ names -= pinned_names
55
+ names
56
+ end
57
+
58
+ sources.all_sources.each do |source|
59
+ source.double_check_for(unmet_dependency_names)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -21,15 +21,19 @@ module Bundler
21
21
  @rubygems_sources = []
22
22
  @metadata_source = Source::Metadata.new
23
23
 
24
- @disable_multisource = true
24
+ @merged_gem_lockfile_sections = false
25
25
  end
26
26
 
27
- def disable_multisource?
28
- @disable_multisource
27
+ def merged_gem_lockfile_sections?
28
+ @merged_gem_lockfile_sections
29
29
  end
30
30
 
31
31
  def merged_gem_lockfile_sections!
32
- @disable_multisource = false
32
+ @merged_gem_lockfile_sections = true
33
+ end
34
+
35
+ def no_aggregate_global_source?
36
+ global_rubygems_source.remotes.size <= 1
33
37
  end
34
38
 
35
39
  def add_path_source(options = {})
@@ -70,7 +74,11 @@ module Bundler
70
74
  end
71
75
 
72
76
  def rubygems_sources
73
- @rubygems_sources + [global_rubygems_source]
77
+ non_global_rubygems_sources + [global_rubygems_source]
78
+ end
79
+
80
+ def non_global_rubygems_sources
81
+ @rubygems_sources
74
82
  end
75
83
 
76
84
  def rubygems_remotes
@@ -81,16 +89,27 @@ module Bundler
81
89
  path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source]
82
90
  end
83
91
 
92
+ def non_default_explicit_sources
93
+ all_sources - [default_source, metadata_source]
94
+ end
95
+
84
96
  def get(source)
85
97
  source_list_for(source).find {|s| equal_source?(source, s) || equivalent_source?(source, s) }
86
98
  end
87
99
 
88
100
  def lock_sources
89
- lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s)
90
- if disable_multisource?
91
- lock_sources + rubygems_sources.sort_by(&:to_s).uniq
101
+ lock_other_sources + lock_rubygems_sources
102
+ end
103
+
104
+ def lock_other_sources
105
+ (path_sources + git_sources + plugin_sources).sort_by(&:to_s)
106
+ end
107
+
108
+ def lock_rubygems_sources
109
+ if merged_gem_lockfile_sections?
110
+ [combine_rubygems_sources]
92
111
  else
93
- lock_sources << combine_rubygems_sources
112
+ rubygems_sources.sort_by(&:to_s).uniq
94
113
  end
95
114
  end
96
115
 
@@ -104,7 +123,7 @@ module Bundler
104
123
  end
105
124
  end
106
125
 
107
- replacement_rubygems = !disable_multisource? &&
126
+ replacement_rubygems = merged_gem_lockfile_sections? &&
108
127
  replacement_sources.detect {|s| s.is_a?(Source::Rubygems) }
109
128
  @global_rubygems_source = replacement_rubygems if replacement_rubygems
110
129
 
@@ -113,6 +132,10 @@ module Bundler
113
132
  false
114
133
  end
115
134
 
135
+ def local_only!
136
+ all_sources.each(&:local_only!)
137
+ end
138
+
116
139
  def cached!
117
140
  all_sources.each(&:cached!)
118
141
  end