bundler 2.2.23 → 2.2.27

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +68 -0
  3. data/lib/bundler/build_metadata.rb +2 -2
  4. data/lib/bundler/cli/cache.rb +1 -1
  5. data/lib/bundler/cli/doctor.rb +1 -1
  6. data/lib/bundler/cli/exec.rb +1 -6
  7. data/lib/bundler/cli/gem.rb +3 -2
  8. data/lib/bundler/cli/install.rb +4 -17
  9. data/lib/bundler/cli/list.rb +7 -1
  10. data/lib/bundler/cli/open.rb +1 -2
  11. data/lib/bundler/cli/update.rb +1 -1
  12. data/lib/bundler/cli.rb +12 -9
  13. data/lib/bundler/definition.rb +38 -47
  14. data/lib/bundler/dsl.rb +40 -26
  15. data/lib/bundler/errors.rb +1 -1
  16. data/lib/bundler/installer/gem_installer.rb +3 -16
  17. data/lib/bundler/installer/standalone.rb +14 -9
  18. data/lib/bundler/installer.rb +0 -1
  19. data/lib/bundler/lockfile_parser.rb +1 -0
  20. data/lib/bundler/plugin/index.rb +4 -1
  21. data/lib/bundler/plugin/installer.rb +2 -0
  22. data/lib/bundler/plugin.rb +25 -6
  23. data/lib/bundler/resolver.rb +10 -17
  24. data/lib/bundler/rubygems_gem_installer.rb +5 -1
  25. data/lib/bundler/rubygems_integration.rb +2 -0
  26. data/lib/bundler/runtime.rb +16 -9
  27. data/lib/bundler/settings.rb +13 -1
  28. data/lib/bundler/setup.rb +2 -2
  29. data/lib/bundler/shared_helpers.rb +0 -7
  30. data/lib/bundler/source/git/git_proxy.rb +1 -2
  31. data/lib/bundler/source/rubygems.rb +23 -2
  32. data/lib/bundler/source/rubygems_aggregate.rb +4 -0
  33. data/lib/bundler/source.rb +4 -0
  34. data/lib/bundler/source_list.rb +16 -3
  35. data/lib/bundler/spec_set.rb +14 -37
  36. data/lib/bundler/templates/Executable.bundler +6 -6
  37. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +13 -2
  38. data/lib/bundler/templates/newgem/newgem.gemspec.tt +3 -1
  39. data/lib/bundler/version.rb +1 -1
  40. data/lib/bundler/worker.rb +17 -2
  41. data/lib/bundler.rb +11 -21
  42. metadata +3 -3
data/lib/bundler/dsl.rb CHANGED
@@ -102,38 +102,39 @@ module Bundler
102
102
  # if there's already a dependency with this name we try to prefer one
103
103
  if current = @dependencies.find {|d| d.name == dep.name }
104
104
  deleted_dep = @dependencies.delete(current) if current.type == :development
105
- return if deleted_dep
106
105
 
107
- if current.requirement != dep.requirement
108
- return if dep.type == :development
106
+ unless deleted_dep
107
+ if current.requirement != dep.requirement
108
+ return if dep.type == :development
109
109
 
110
- update_prompt = ""
110
+ update_prompt = ""
111
111
 
112
- if File.basename(@gemfile) == Injector::INJECTED_GEMS
113
- if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0")
114
- update_prompt = ". Gem already added"
115
- else
116
- update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`"
112
+ if File.basename(@gemfile) == Injector::INJECTED_GEMS
113
+ if dep.requirements_list.include?(">= 0") && !current.requirements_list.include?(">= 0")
114
+ update_prompt = ". Gem already added"
115
+ else
116
+ update_prompt = ". If you want to update the gem version, run `bundle update #{current.name}`"
117
117
 
118
- update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0")
118
+ update_prompt += ". You may also need to change the version requirement specified in the Gemfile if it's too restrictive." unless current.requirements_list.include?(">= 0")
119
+ end
119
120
  end
120
- end
121
121
 
122
- raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \
123
- "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
124
- "#{update_prompt}"
125
- else
126
- Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
127
- "You should probably keep only one of them.\n" \
128
- "Remove any duplicate entries and specify the gem only once.\n" \
129
- "While it's not a problem now, it could cause errors if you change the version of one of them later."
130
- end
122
+ raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \
123
+ "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \
124
+ "#{update_prompt}"
125
+ else
126
+ Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \
127
+ "You should probably keep only one of them.\n" \
128
+ "Remove any duplicate entries and specify the gem only once.\n" \
129
+ "While it's not a problem now, it could cause errors if you change the version of one of them later."
130
+ end
131
131
 
132
- if current.source != dep.source
133
- return if dep.type == :development
134
- raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
135
- "You specified that #{dep.name} (#{dep.requirement}) should come from " \
136
- "#{current.source || "an unspecified source"} and #{dep.source}\n"
132
+ if current.source != dep.source
133
+ return if dep.type == :development
134
+ raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \
135
+ "You specified that #{dep.name} (#{dep.requirement}) should come from " \
136
+ "#{current.source || "an unspecified source"} and #{dep.source}\n"
137
+ end
137
138
  end
138
139
  end
139
140
 
@@ -446,8 +447,21 @@ repo_name ||= user_name
446
447
  end
447
448
 
448
449
  def check_rubygems_source_safety
449
- return unless @sources.aggregate_global_source?
450
+ if @sources.implicit_global_source?
451
+ implicit_global_source_warning
452
+ elsif @sources.aggregate_global_source?
453
+ multiple_global_source_warning
454
+ end
455
+ end
456
+
457
+ def implicit_global_source_warning
458
+ Bundler::SharedHelpers.major_deprecation 2, "This Gemfile does not include an explicit global source. " \
459
+ "Not using an explicit global source may result in a different lockfile being generated depending on " \
460
+ "the gems you have installed locally before bundler is run. " \
461
+ "Instead, define a global source in your Gemfile like this: source \"https://rubygems.org\"."
462
+ end
450
463
 
464
+ def multiple_global_source_warning
451
465
  if Bundler.feature_flag.bundler_3_mode?
452
466
  msg = "This Gemfile contains multiple primary sources. " \
453
467
  "Each source after the first must include a block to indicate which gems " \
@@ -122,7 +122,7 @@ module Bundler
122
122
 
123
123
  class VirtualProtocolError < BundlerError
124
124
  def message
125
- "There was an error relating to virtualization and file access." \
125
+ "There was an error relating to virtualization and file access. " \
126
126
  "It is likely that you need to grant access to or mount some file system correctly."
127
127
  end
128
128
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "shellwords"
4
-
5
3
  module Bundler
6
4
  class GemInstaller
7
5
  attr_reader :spec, :standalone, :worker, :force, :installer
@@ -31,34 +29,23 @@ module Bundler
31
29
 
32
30
  def specific_failure_message(e)
33
31
  message = "#{e.class}: #{e.message}\n"
34
- message += " " + e.backtrace.join("\n ") + "\n\n" if Bundler.ui.debug?
32
+ message += " " + e.backtrace.join("\n ") + "\n\n"
35
33
  message = message.lines.first + Bundler.ui.add_color(message.lines.drop(1).join, :clear)
36
34
  message + Bundler.ui.add_color(failure_message, :red)
37
35
  end
38
36
 
39
37
  def failure_message
40
- return install_error_message if spec.source.options["git"]
41
- "#{install_error_message}\n#{gem_install_message}"
38
+ install_error_message
42
39
  end
43
40
 
44
41
  def install_error_message
45
42
  "An error occurred while installing #{spec.name} (#{spec.version}), and Bundler cannot continue."
46
43
  end
47
44
 
48
- def gem_install_message
49
- source = spec.source
50
- return unless source.respond_to?(:remotes)
51
-
52
- if source.remotes.size == 1
53
- "Make sure that `gem install #{spec.name} -v '#{spec.version}' --source '#{source.remotes.first}'` succeeds before bundling."
54
- else
55
- "Make sure that `gem install #{spec.name} -v '#{spec.version}'` succeeds before bundling."
56
- end
57
- end
58
-
59
45
  def spec_settings
60
46
  # Fetch the build settings, if there are any
61
47
  if settings = Bundler.settings["build.#{spec.name}"]
48
+ require "shellwords"
62
49
  Shellwords.shellsplit(settings)
63
50
  end
64
51
  end
@@ -3,7 +3,7 @@
3
3
  module Bundler
4
4
  class Standalone
5
5
  def initialize(groups, definition)
6
- @specs = groups.empty? ? definition.requested_specs : definition.specs_for(groups.map(&:to_sym))
6
+ @specs = definition.specs_for(groups)
7
7
  end
8
8
 
9
9
  def generate
@@ -12,12 +12,13 @@ module Bundler
12
12
  end
13
13
  File.open File.join(bundler_path, "setup.rb"), "w" do |file|
14
14
  file.puts "require 'rbconfig'"
15
- file.puts "ruby_engine = RUBY_ENGINE"
16
- file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]"
17
- file.puts "path = File.expand_path('..', __FILE__)"
18
15
  file.puts reverse_rubygems_kernel_mixin
19
16
  paths.each do |path|
20
- file.puts %($:.unshift File.expand_path("\#{path}/#{path}"))
17
+ if Pathname.new(path).absolute?
18
+ file.puts %($:.unshift "#{path}")
19
+ else
20
+ file.puts %($:.unshift File.expand_path("\#{__dir__}/#{path}"))
21
+ end
21
22
  end
22
23
  end
23
24
  end
@@ -28,14 +29,14 @@ module Bundler
28
29
  @specs.map do |spec|
29
30
  next if spec.name == "bundler"
30
31
  Array(spec.require_paths).map do |path|
31
- gem_path(path, spec).sub(version_dir, '#{ruby_engine}/#{ruby_version}')
32
+ gem_path(path, spec).sub(version_dir, '#{RUBY_ENGINE}/#{RbConfig::CONFIG["ruby_version"]}')
32
33
  # This is a static string intentionally. It's interpolated at a later time.
33
34
  end
34
- end.flatten
35
+ end.flatten.compact
35
36
  end
36
37
 
37
38
  def version_dir
38
- "#{Bundler::RubyVersion.system.engine}/#{RbConfig::CONFIG["ruby_version"]}"
39
+ "#{RUBY_ENGINE}/#{RbConfig::CONFIG["ruby_version"]}"
39
40
  end
40
41
 
41
42
  def bundler_path
@@ -44,7 +45,11 @@ module Bundler
44
45
 
45
46
  def gem_path(path, spec)
46
47
  full_path = Pathname.new(path).absolute? ? path : File.join(spec.full_gem_path, path)
47
- Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s
48
+ if spec.source.instance_of?(Source::Path)
49
+ full_path
50
+ else
51
+ Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path)).to_s
52
+ end
48
53
  rescue TypeError
49
54
  error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
50
55
  raise Gem::InvalidSpecificationException.new(error_message)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rubygems/dependency_installer"
4
3
  require_relative "worker"
5
4
  require_relative "installer/parallel_installer"
6
5
  require_relative "installer/standalone"
@@ -195,6 +195,7 @@ module Bundler
195
195
  platform = platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY
196
196
  @current_spec = LazySpecification.new(name, version, platform)
197
197
  @current_spec.source = @current_source
198
+ @current_source.add_dependency_names(name)
198
199
 
199
200
  @specs[@current_spec.identifier] = @current_spec
200
201
  elsif spaces.size == 6
@@ -74,7 +74,10 @@ module Bundler
74
74
  def unregister_plugin(name)
75
75
  @commands.delete_if {|_, v| v == name }
76
76
  @sources.delete_if {|_, v| v == name }
77
- @hooks.each {|_, plugin_names| plugin_names.delete(name) }
77
+ @hooks.each do |hook, names|
78
+ names.delete(name)
79
+ @hooks.delete(hook) if names.empty?
80
+ end
78
81
  @plugin_paths.delete(name)
79
82
  @load_paths.delete(name)
80
83
  save_index
@@ -81,6 +81,8 @@ module Bundler
81
81
 
82
82
  deps = names.map {|name| Dependency.new name, version }
83
83
 
84
+ Bundler.configure_gem_home_and_path(Plugin.root)
85
+
84
86
  definition = Definition.new(nil, deps, source_list, true)
85
87
  install_definition(definition)
86
88
  end
@@ -13,6 +13,7 @@ module Bundler
13
13
  class MalformattedPlugin < PluginError; end
14
14
  class UndefinedCommandError < PluginError; end
15
15
  class UnknownSourceError < PluginError; end
16
+ class PluginInstallError < PluginError; end
16
17
 
17
18
  PLUGIN_FILE_NAME = "plugins.rb".freeze
18
19
 
@@ -38,12 +39,11 @@ module Bundler
38
39
  specs = Installer.new.install(names, options)
39
40
 
40
41
  save_plugins names, specs
41
- rescue PluginError => e
42
+ rescue PluginError
42
43
  specs_to_delete = specs.select {|k, _v| names.include?(k) && !index.commands.values.include?(k) }
43
44
  specs_to_delete.each_value {|spec| Bundler.rm_rf(spec.full_gem_path) }
44
45
 
45
- names_list = names.map {|name| "`#{name}`" }.join(", ")
46
- Bundler.ui.error "Failed to install the following plugins: #{names_list}. The underlying error was: #{e.message}.\n #{e.backtrace.join("\n ")}"
46
+ raise
47
47
  end
48
48
 
49
49
  # Uninstalls plugins by the given names
@@ -245,10 +245,11 @@ module Bundler
245
245
  # @param [Array<String>] names of inferred source plugins that can be ignored
246
246
  def save_plugins(plugins, specs, optional_plugins = [])
247
247
  plugins.each do |name|
248
+ next if index.installed?(name)
249
+
248
250
  spec = specs[name]
249
- validate_plugin! Pathname.new(spec.full_gem_path)
250
- installed = register_plugin(name, spec, optional_plugins.include?(name))
251
- Bundler.ui.info "Installed plugin #{name}" if installed
251
+
252
+ save_plugin(name, spec, optional_plugins.include?(name))
252
253
  end
253
254
  end
254
255
 
@@ -263,6 +264,22 @@ module Bundler
263
264
  raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file?
264
265
  end
265
266
 
267
+ # Validates and registers a plugin.
268
+ #
269
+ # @param [String] name the name of the plugin
270
+ # @param [Specification] spec of installed plugin
271
+ # @param [Boolean] optional_plugin, removed if there is conflict with any
272
+ # other plugin (used for default source plugins)
273
+ #
274
+ # @raise [PluginInstallError] if validation or registration raises any error
275
+ def save_plugin(name, spec, optional_plugin = false)
276
+ validate_plugin! Pathname.new(spec.full_gem_path)
277
+ installed = register_plugin(name, spec, optional_plugin)
278
+ Bundler.ui.info "Installed plugin #{name}" if installed
279
+ rescue PluginError => e
280
+ raise PluginInstallError, "Failed to install plugin `#{spec.name}`, due to #{e.class} (#{e.message})"
281
+ end
282
+
266
283
  # Runs the plugins.rb file in an isolated namespace, records the plugin
267
284
  # actions it registers for and then passes the data to index to be stored.
268
285
  #
@@ -309,6 +326,8 @@ module Bundler
309
326
  #
310
327
  # @param [String] name of the plugin
311
328
  def load_plugin(name)
329
+ return unless name && !name.empty?
330
+
312
331
  # Need to ensure before this that plugin root where the rest of gems
313
332
  # are installed to be on load path to support plugin deps. Currently not
314
333
  # done to avoid conflicts
@@ -255,12 +255,6 @@ module Bundler
255
255
  next if name == "bundler"
256
256
  next unless search_for(requirement).empty?
257
257
 
258
- cache_message = begin
259
- " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
260
- rescue GemfileNotFound
261
- nil
262
- end
263
-
264
258
  if (base = @base[name]) && !base.empty?
265
259
  version = base.first.version
266
260
  message = "You have requested:\n" \
@@ -269,18 +263,17 @@ module Bundler
269
263
  "Try running `bundle update #{name}`\n\n" \
270
264
  "If you are updating multiple gems in your Gemfile at once,\n" \
271
265
  "try passing them all to `bundle update`"
272
- elsif source = @source_requirements[name]
266
+ else
267
+ source = source_for(name)
273
268
  specs = source.specs.search(name)
274
269
  versions_with_platforms = specs.map {|s| [s.version, s.platform] }
275
- message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n")
276
- message << if versions_with_platforms.any?
277
- "The source contains the following versions of '#{name}': #{formatted_versions_with_platforms(versions_with_platforms)}"
278
- else
279
- "The source does not contain any versions of '#{name}'"
280
- end
281
- else
282
- message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \
283
- "listed in your Gemfile#{cache_message}."
270
+ cache_message = begin
271
+ " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
272
+ rescue GemfileNotFound
273
+ nil
274
+ end
275
+ message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source.to_err}#{cache_message}.\n")
276
+ message << "The source contains the following versions of '#{name}': #{formatted_versions_with_platforms(versions_with_platforms)}" if versions_with_platforms.any?
284
277
  end
285
278
  raise GemNotFound, message
286
279
  end
@@ -378,7 +371,7 @@ module Bundler
378
371
  o << if metadata_requirement
379
372
  "is not available in #{relevant_source}"
380
373
  else
381
- "in #{relevant_source}.\n"
374
+ "in #{relevant_source.to_err}.\n"
382
375
  end
383
376
  end
384
377
  end,
@@ -61,7 +61,10 @@ module Bundler
61
61
 
62
62
  def build_extensions
63
63
  extension_cache_path = options[:bundler_extension_cache_path]
64
- return super unless extension_cache_path && extension_dir = spec.extension_dir
64
+ unless extension_cache_path && extension_dir = spec.extension_dir
65
+ require "shellwords" # compensate missing require in rubygems before version 3.2.25
66
+ return super
67
+ end
65
68
 
66
69
  extension_dir = Pathname.new(extension_dir)
67
70
  build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?)
@@ -71,6 +74,7 @@ module Bundler
71
74
  FileUtils.cp_r extension_cache_path, spec.extension_dir
72
75
  end
73
76
  else
77
+ require "shellwords" # compensate missing require in rubygems before version 3.2.25
74
78
  super
75
79
  if extension_dir.directory? # not made for gems without extensions
76
80
  SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath)
@@ -34,10 +34,12 @@ module Bundler
34
34
  end
35
35
 
36
36
  def build_args
37
+ require "rubygems/command"
37
38
  Gem::Command.build_args
38
39
  end
39
40
 
40
41
  def build_args=(args)
42
+ require "rubygems/command"
41
43
  Gem::Command.build_args = args
42
44
  end
43
45
 
@@ -12,22 +12,16 @@ module Bundler
12
12
  def setup(*groups)
13
13
  @definition.ensure_equivalent_gemfile_and_lockfile if Bundler.frozen_bundle?
14
14
 
15
- groups.map!(&:to_sym)
16
-
17
15
  # Has to happen first
18
16
  clean_load_path
19
17
 
20
- specs = groups.any? ? @definition.specs_for(groups) : requested_specs
18
+ specs = @definition.specs_for(groups)
21
19
 
22
20
  SharedHelpers.set_bundle_environment
23
21
  Bundler.rubygems.replace_entrypoints(specs)
24
22
 
25
23
  # Activate the specs
26
24
  load_paths = specs.map do |spec|
27
- unless spec.loaded_from
28
- raise GemNotFound, "#{spec.full_name} is missing. Run `bundle install` to get it."
29
- end
30
-
31
25
  check_for_activated_spec!(spec)
32
26
 
33
27
  Bundler.rubygems.mark_loaded(spec)
@@ -106,7 +100,7 @@ module Bundler
106
100
 
107
101
  alias_method :gems, :specs
108
102
 
109
- def cache(custom_path = nil)
103
+ def cache(custom_path = nil, local = false)
110
104
  cache_path = Bundler.app_cache(custom_path)
111
105
  SharedHelpers.filesystem_access(cache_path) do |p|
112
106
  FileUtils.mkdir_p(p)
@@ -114,7 +108,20 @@ module Bundler
114
108
 
115
109
  Bundler.ui.info "Updating files in #{Bundler.settings.app_cache_path}"
116
110
 
117
- specs_to_cache = Bundler.settings[:cache_all_platforms] ? @definition.resolve.materialized_for_all_platforms : specs
111
+ specs_to_cache = if Bundler.settings[:cache_all_platforms]
112
+ @definition.resolve.materialized_for_all_platforms
113
+ else
114
+ begin
115
+ specs
116
+ rescue GemNotFound
117
+ if local
118
+ Bundler.ui.warn "Some gems seem to be missing from your #{Bundler.settings.app_cache_path} directory."
119
+ end
120
+
121
+ raise
122
+ end
123
+ end
124
+
118
125
  specs_to_cache.each do |spec|
119
126
  next if spec.name == "bundler"
120
127
  next if spec.source.is_a?(Source::Gemspec)