bundler 2.2.14 → 2.2.19

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 +81 -5
  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/common.rb +15 -2
  8. data/lib/bundler/cli/gem.rb +9 -1
  9. data/lib/bundler/cli/outdated.rb +8 -11
  10. data/lib/bundler/compact_index_client/updater.rb +9 -5
  11. data/lib/bundler/current_ruby.rb +1 -0
  12. data/lib/bundler/definition.rb +21 -84
  13. data/lib/bundler/feature_flag.rb +0 -2
  14. data/lib/bundler/fetcher.rb +2 -1
  15. data/lib/bundler/fetcher/downloader.rb +8 -4
  16. data/lib/bundler/friendly_errors.rb +1 -1
  17. data/lib/bundler/gem_helper.rb +16 -0
  18. data/lib/bundler/index.rb +1 -2
  19. data/lib/bundler/injector.rb +2 -2
  20. data/lib/bundler/inline.rb +1 -1
  21. data/lib/bundler/installer/parallel_installer.rb +30 -7
  22. data/lib/bundler/lazy_specification.rb +6 -1
  23. data/lib/bundler/man/bundle-add.1 +1 -1
  24. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  25. data/lib/bundler/man/bundle-cache.1 +1 -1
  26. data/lib/bundler/man/bundle-check.1 +1 -1
  27. data/lib/bundler/man/bundle-clean.1 +1 -1
  28. data/lib/bundler/man/bundle-config.1 +21 -10
  29. data/lib/bundler/man/bundle-config.1.ronn +21 -11
  30. data/lib/bundler/man/bundle-doctor.1 +1 -1
  31. data/lib/bundler/man/bundle-exec.1 +1 -1
  32. data/lib/bundler/man/bundle-gem.1 +1 -1
  33. data/lib/bundler/man/bundle-info.1 +1 -1
  34. data/lib/bundler/man/bundle-init.1 +1 -1
  35. data/lib/bundler/man/bundle-inject.1 +1 -1
  36. data/lib/bundler/man/bundle-install.1 +1 -1
  37. data/lib/bundler/man/bundle-list.1 +1 -1
  38. data/lib/bundler/man/bundle-lock.1 +1 -1
  39. data/lib/bundler/man/bundle-open.1 +1 -1
  40. data/lib/bundler/man/bundle-outdated.1 +1 -1
  41. data/lib/bundler/man/bundle-platform.1 +1 -1
  42. data/lib/bundler/man/bundle-pristine.1 +1 -1
  43. data/lib/bundler/man/bundle-remove.1 +1 -1
  44. data/lib/bundler/man/bundle-show.1 +1 -1
  45. data/lib/bundler/man/bundle-update.1 +1 -1
  46. data/lib/bundler/man/bundle-viz.1 +1 -1
  47. data/lib/bundler/man/bundle.1 +1 -1
  48. data/lib/bundler/man/gemfile.5 +1 -1
  49. data/lib/bundler/plugin.rb +2 -2
  50. data/lib/bundler/plugin/api/source.rb +14 -0
  51. data/lib/bundler/resolver.rb +13 -96
  52. data/lib/bundler/resolver/spec_group.rb +0 -24
  53. data/lib/bundler/retry.rb +1 -1
  54. data/lib/bundler/rubygems_ext.rb +2 -2
  55. data/lib/bundler/settings.rb +74 -12
  56. data/lib/bundler/source.rb +9 -0
  57. data/lib/bundler/source/path.rb +3 -1
  58. data/lib/bundler/source/path/installer.rb +1 -1
  59. data/lib/bundler/source/rubygems.rb +17 -10
  60. data/lib/bundler/source/rubygems_aggregate.rb +64 -0
  61. data/lib/bundler/source_list.rb +29 -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 +9 -4
data/lib/bundler/retry.rb CHANGED
@@ -49,7 +49,7 @@ module Bundler
49
49
  raise e
50
50
  end
51
51
  return true unless name
52
- Bundler.ui.info "" unless Bundler.ui.debug? # Add new line incase dots preceded this
52
+ Bundler.ui.info "" unless Bundler.ui.debug? # Add new line in case dots preceded this
53
53
  Bundler.ui.warn "Retrying #{name} due to error (#{current_run.next}/#{total_runs}): #{e.class} #{e.message}", Bundler.ui.debug?
54
54
  end
55
55
 
@@ -105,7 +105,7 @@ module Gem
105
105
  end
106
106
 
107
107
  class Dependency
108
- attr_accessor :source, :groups, :all_sources
108
+ attr_accessor :source, :groups
109
109
 
110
110
  alias_method :eql?, :==
111
111
 
@@ -116,7 +116,7 @@ module Gem
116
116
  end
117
117
 
118
118
  def to_yaml_properties
119
- instance_variables.reject {|p| ["@source", "@groups", "@all_sources"].include?(p.to_s) }
119
+ instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) }
120
120
  end
121
121
 
122
122
  def to_lock
@@ -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
 
@@ -39,6 +40,10 @@ module Bundler
39
40
 
40
41
  def remote!; end
41
42
 
43
+ def add_dependency_names(names)
44
+ @dependency_names = Array(dependency_names) | Array(names)
45
+ end
46
+
42
47
  # it's possible that gems from one source depend on gems from some
43
48
  # other source, so now we download gemspecs and iterate over those
44
49
  # dependencies, looking for gems we don't have info on yet.
@@ -48,6 +53,10 @@ module Bundler
48
53
  specs.dependency_names
49
54
  end
50
55
 
56
+ def spec_names
57
+ specs.spec_names
58
+ end
59
+
51
60
  def include?(other)
52
61
  other == self
53
62
  end
@@ -82,7 +82,9 @@ module Bundler
82
82
  end
83
83
 
84
84
  def install(spec, options = {})
85
- print_using_message "Using #{version_message(spec)} from #{self}"
85
+ using_message = "Using #{version_message(spec)} from #{self}"
86
+ using_message += " and installing its executables" unless spec.executables.empty?
87
+ print_using_message using_message
86
88
  generate_bin(spec, :disable_extensions => true)
87
89
  nil # no post-install message
88
90
  end
@@ -35,7 +35,7 @@ module Bundler
35
35
  run_hooks(:post_build)
36
36
  end
37
37
 
38
- generate_bin unless spec.executables.nil? || spec.executables.empty?
38
+ generate_bin unless spec.executables.empty?
39
39
 
40
40
  run_hooks(:post_install)
41
41
  ensure
@@ -259,8 +259,16 @@ module Bundler
259
259
  !equivalent
260
260
  end
261
261
 
262
+ def spec_names
263
+ if @allow_remote && dependency_api_available?
264
+ remote_specs.spec_names
265
+ else
266
+ []
267
+ end
268
+ end
269
+
262
270
  def unmet_deps
263
- if @allow_remote && api_fetchers.any?
271
+ if @allow_remote && dependency_api_available?
264
272
  remote_specs.unmet_dependency_names
265
273
  else
266
274
  []
@@ -276,7 +284,7 @@ module Bundler
276
284
 
277
285
  def double_check_for(unmet_dependency_names)
278
286
  return unless @allow_remote
279
- return unless api_fetchers.any?
287
+ return unless dependency_api_available?
280
288
 
281
289
  unmet_dependency_names = unmet_dependency_names.call
282
290
  unless unmet_dependency_names.nil?
@@ -298,17 +306,20 @@ module Bundler
298
306
  remote_specs.each do |spec|
299
307
  case spec
300
308
  when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification
301
- names.concat(spec.runtime_dependencies)
309
+ names.concat(spec.runtime_dependencies.map(&:name))
302
310
  when RemoteSpecification # from the full index
303
311
  return nil
304
312
  else
305
313
  raise "unhandled spec type (#{spec.inspect})"
306
314
  end
307
315
  end
308
- names.map!(&:name) if names
309
316
  names
310
317
  end
311
318
 
319
+ def dependency_api_available?
320
+ api_fetchers.any?
321
+ end
322
+
312
323
  protected
313
324
 
314
325
  def credless_remotes
@@ -387,10 +398,6 @@ module Bundler
387
398
  next if gemfile =~ /^bundler\-[\d\.]+?\.gem/
388
399
  s ||= Bundler.rubygems.spec_from_gem(gemfile)
389
400
  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
401
  idx << s
395
402
  end
396
403
 
@@ -423,11 +430,11 @@ module Bundler
423
430
  def fetch_names(fetchers, dependency_names, index, override_dupes)
424
431
  fetchers.each do |f|
425
432
  if dependency_names
426
- Bundler.ui.info "Fetching gem metadata from #{f.uri}", Bundler.ui.debug?
433
+ Bundler.ui.info "Fetching gem metadata from #{URICredentialsFilter.credential_filtered_uri(f.uri)}", Bundler.ui.debug?
427
434
  index.use f.specs_with_retry(dependency_names, self), override_dupes
428
435
  Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
429
436
  else
430
- Bundler.ui.info "Fetching source index from #{f.uri}"
437
+ Bundler.ui.info "Fetching source index from #{URICredentialsFilter.credential_filtered_uri(f.uri)}"
431
438
  index.use f.specs_with_retry(nil, self), override_dupes
432
439
  end
433
440
  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)
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