bundler 2.2.3 → 2.3.5

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 (183) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +503 -7
  3. data/README.md +1 -1
  4. data/bundler.gemspec +2 -3
  5. data/exe/bundle +7 -8
  6. data/lib/bundler/.document +1 -0
  7. data/lib/bundler/build_metadata.rb +2 -2
  8. data/lib/bundler/cli/cache.rb +2 -1
  9. data/lib/bundler/cli/check.rb +4 -2
  10. data/lib/bundler/cli/common.rb +15 -2
  11. data/lib/bundler/cli/doctor.rb +15 -4
  12. data/lib/bundler/cli/exec.rb +1 -6
  13. data/lib/bundler/cli/gem.rb +132 -24
  14. data/lib/bundler/cli/info.rb +16 -4
  15. data/lib/bundler/cli/install.rb +12 -27
  16. data/lib/bundler/cli/issue.rb +4 -3
  17. data/lib/bundler/cli/list.rb +7 -1
  18. data/lib/bundler/cli/lock.rb +5 -1
  19. data/lib/bundler/cli/open.rb +1 -2
  20. data/lib/bundler/cli/outdated.rb +10 -11
  21. data/lib/bundler/cli/remove.rb +1 -2
  22. data/lib/bundler/cli/update.rb +17 -8
  23. data/lib/bundler/cli.rb +44 -60
  24. data/lib/bundler/compact_index_client/cache.rb +0 -9
  25. data/lib/bundler/compact_index_client/updater.rb +10 -19
  26. data/lib/bundler/compact_index_client.rb +2 -8
  27. data/lib/bundler/current_ruby.rb +5 -4
  28. data/lib/bundler/definition.rb +158 -316
  29. data/lib/bundler/dep_proxy.rb +15 -8
  30. data/lib/bundler/dependency.rb +5 -7
  31. data/lib/bundler/digest.rb +71 -0
  32. data/lib/bundler/dsl.rb +67 -66
  33. data/lib/bundler/endpoint_specification.rb +21 -11
  34. data/lib/bundler/environment_preserver.rb +4 -1
  35. data/lib/bundler/errors.rb +19 -3
  36. data/lib/bundler/feature_flag.rb +0 -5
  37. data/lib/bundler/fetcher/compact_index.rb +10 -15
  38. data/lib/bundler/fetcher/downloader.rb +9 -6
  39. data/lib/bundler/fetcher/index.rb +0 -27
  40. data/lib/bundler/fetcher.rb +10 -17
  41. data/lib/bundler/friendly_errors.rb +5 -32
  42. data/lib/bundler/gem_helper.rb +28 -21
  43. data/lib/bundler/gem_version_promoter.rb +2 -2
  44. data/lib/bundler/index.rb +8 -12
  45. data/lib/bundler/injector.rb +12 -3
  46. data/lib/bundler/inline.rb +2 -1
  47. data/lib/bundler/installer/gem_installer.rb +4 -22
  48. data/lib/bundler/installer/parallel_installer.rb +36 -15
  49. data/lib/bundler/installer/standalone.rb +29 -9
  50. data/lib/bundler/installer.rb +8 -34
  51. data/lib/bundler/lazy_specification.rb +32 -20
  52. data/lib/bundler/lockfile_generator.rb +1 -1
  53. data/lib/bundler/lockfile_parser.rb +16 -45
  54. data/{man → lib/bundler/man}/bundle-add.1 +10 -2
  55. data/lib/bundler/man/bundle-add.1.ronn +7 -1
  56. data/{man → lib/bundler/man}/bundle-binstubs.1 +1 -1
  57. data/{man → lib/bundler/man}/bundle-cache.1 +1 -1
  58. data/{man → lib/bundler/man}/bundle-check.1 +1 -1
  59. data/{man → lib/bundler/man}/bundle-clean.1 +1 -1
  60. data/{man → lib/bundler/man}/bundle-config.1 +27 -19
  61. data/lib/bundler/man/bundle-config.1.ronn +33 -25
  62. data/{man → lib/bundler/man}/bundle-doctor.1 +1 -1
  63. data/{man → lib/bundler/man}/bundle-exec.1 +1 -1
  64. data/{man → lib/bundler/man}/bundle-gem.1 +14 -1
  65. data/lib/bundler/man/bundle-gem.1.ronn +16 -0
  66. data/{man → lib/bundler/man}/bundle-info.1 +1 -1
  67. data/{man → lib/bundler/man}/bundle-init.1 +1 -1
  68. data/{man → lib/bundler/man}/bundle-inject.1 +1 -1
  69. data/{man → lib/bundler/man}/bundle-install.1 +2 -2
  70. data/lib/bundler/man/bundle-install.1.ronn +2 -2
  71. data/{man → lib/bundler/man}/bundle-list.1 +1 -1
  72. data/{man → lib/bundler/man}/bundle-lock.1 +1 -1
  73. data/{man → lib/bundler/man}/bundle-open.1 +1 -1
  74. data/{man → lib/bundler/man}/bundle-outdated.1 +1 -1
  75. data/{man → lib/bundler/man}/bundle-platform.1 +1 -1
  76. data/{man → lib/bundler/man}/bundle-pristine.1 +1 -1
  77. data/{man → lib/bundler/man}/bundle-remove.1 +1 -1
  78. data/{man → lib/bundler/man}/bundle-show.1 +1 -1
  79. data/{man → lib/bundler/man}/bundle-update.1 +5 -5
  80. data/lib/bundler/man/bundle-update.1.ronn +5 -4
  81. data/{man → lib/bundler/man}/bundle-viz.1 +1 -1
  82. data/{man → lib/bundler/man}/bundle.1 +1 -1
  83. data/{man → lib/bundler/man}/gemfile.5 +28 -2
  84. data/lib/bundler/man/gemfile.5.ronn +9 -1
  85. data/{man → lib/bundler/man}/index.txt +0 -0
  86. data/lib/bundler/plugin/api/source.rb +22 -0
  87. data/lib/bundler/plugin/index.rb +4 -1
  88. data/lib/bundler/plugin/installer.rb +10 -10
  89. data/lib/bundler/plugin/source_list.rb +4 -0
  90. data/lib/bundler/plugin.rb +28 -8
  91. data/lib/bundler/process_lock.rb +1 -1
  92. data/lib/bundler/psyched_yaml.rb +1 -13
  93. data/lib/bundler/resolver/spec_group.rb +36 -48
  94. data/lib/bundler/resolver.rb +97 -151
  95. data/lib/bundler/retry.rb +1 -1
  96. data/lib/bundler/ruby_version.rb +1 -1
  97. data/lib/bundler/rubygems_ext.rb +46 -8
  98. data/lib/bundler/rubygems_gem_installer.rb +68 -1
  99. data/lib/bundler/rubygems_integration.rb +43 -60
  100. data/lib/bundler/runtime.rb +18 -11
  101. data/lib/bundler/self_manager.rb +168 -0
  102. data/lib/bundler/settings.rb +97 -21
  103. data/lib/bundler/setup.rb +2 -2
  104. data/lib/bundler/shared_helpers.rb +6 -21
  105. data/lib/bundler/source/git/git_proxy.rb +60 -53
  106. data/lib/bundler/source/git.rb +38 -18
  107. data/lib/bundler/source/metadata.rb +1 -5
  108. data/lib/bundler/source/path/installer.rb +3 -1
  109. data/lib/bundler/source/path.rb +3 -1
  110. data/lib/bundler/source/rubygems.rb +113 -100
  111. data/lib/bundler/source/rubygems_aggregate.rb +68 -0
  112. data/lib/bundler/source.rb +21 -0
  113. data/lib/bundler/source_list.rb +100 -62
  114. data/lib/bundler/source_map.rb +58 -0
  115. data/lib/bundler/spec_set.rb +21 -34
  116. data/lib/bundler/stub_specification.rb +8 -0
  117. data/lib/bundler/templates/Executable.bundler +7 -7
  118. data/lib/bundler/templates/Gemfile +0 -2
  119. data/lib/bundler/templates/gems.rb +0 -3
  120. data/lib/bundler/templates/newgem/CHANGELOG.md.tt +5 -0
  121. data/lib/bundler/templates/newgem/Gemfile.tt +5 -2
  122. data/lib/bundler/templates/newgem/README.md.tt +5 -3
  123. data/lib/bundler/templates/newgem/Rakefile.tt +15 -2
  124. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +15 -6
  125. data/lib/bundler/templates/newgem/newgem.gemspec.tt +18 -16
  126. data/lib/bundler/templates/newgem/rubocop.yml.tt +3 -0
  127. data/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  128. data/lib/bundler/templates/newgem/standard.yml.tt +2 -0
  129. data/lib/bundler/templates/newgem/test/minitest/{newgem_test.rb.tt → test_newgem.rb.tt} +1 -1
  130. data/lib/bundler/ui/shell.rb +1 -1
  131. data/lib/bundler/vendor/.document +1 -0
  132. data/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  133. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +19 -21
  134. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  135. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +57 -0
  136. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +39 -74
  137. data/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  138. data/lib/bundler/vendor/molinillo/LICENSE +9 -0
  139. data/lib/bundler/vendor/molinillo/lib/molinillo/delegates/specification_provider.rb +7 -0
  140. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +11 -5
  141. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +2 -3
  142. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +2 -2
  143. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +12 -1
  144. data/lib/bundler/vendor/molinillo/lib/molinillo/resolution.rb +11 -7
  145. data/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  146. data/lib/bundler/vendor/thor/LICENSE.md +20 -0
  147. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +9 -7
  148. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +1 -2
  149. data/lib/bundler/vendor/thor/lib/thor/actions.rb +7 -3
  150. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +6 -0
  151. data/lib/bundler/vendor/thor/lib/thor/error.rb +10 -5
  152. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +5 -1
  153. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +28 -9
  154. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +27 -6
  155. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +5 -1
  156. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  157. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  158. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  159. data/lib/bundler/vendor/thor/lib/thor.rb +5 -6
  160. data/lib/bundler/vendor/tmpdir/lib/tmpdir.rb +1 -1
  161. data/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  162. data/lib/bundler/vendor/tsort/lib/tsort.rb +453 -0
  163. data/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  164. data/lib/bundler/vendor/uri/lib/uri/common.rb +17 -80
  165. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +0 -1
  166. data/lib/bundler/vendor/uri/lib/uri/generic.rb +5 -6
  167. data/lib/bundler/vendor/uri/lib/uri/http.rb +0 -1
  168. data/lib/bundler/vendor/uri/lib/uri/https.rb +0 -1
  169. data/lib/bundler/vendor/uri/lib/uri/ldap.rb +1 -1
  170. data/lib/bundler/vendor/uri/lib/uri/mailto.rb +0 -1
  171. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +1 -14
  172. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -12
  173. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  174. data/lib/bundler/vendor/uri/lib/uri/ws.rb +84 -0
  175. data/lib/bundler/vendor/uri/lib/uri/wss.rb +22 -0
  176. data/lib/bundler/vendor/uri/lib/uri.rb +0 -1
  177. data/lib/bundler/vendored_tsort.rb +4 -0
  178. data/lib/bundler/version.rb +1 -1
  179. data/lib/bundler/worker.rb +19 -4
  180. data/lib/bundler.rb +29 -33
  181. metadata +54 -35
  182. data/lib/bundler/gemdeps.rb +0 -29
  183. data/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb +0 -66
@@ -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
@@ -105,6 +105,7 @@ module Bundler
105
105
  else
106
106
  builder.eval_gemfile(gemfile)
107
107
  end
108
+ builder.check_primary_source_safety
108
109
  definition = builder.to_definition(nil, true)
109
110
 
110
111
  return if definition.dependencies.empty?
@@ -163,7 +164,7 @@ module Bundler
163
164
  end
164
165
 
165
166
  # To be called from Cli class to pass the command and argument to
166
- # approriate plugin class
167
+ # appropriate plugin class
167
168
  def exec_command(command, args)
168
169
  raise UndefinedCommandError, "Command `#{command}` not found" unless command? command
169
170
 
@@ -182,7 +183,7 @@ module Bundler
182
183
  !index.source_plugin(name.to_s).nil?
183
184
  end
184
185
 
185
- # @return [Class] that handles the source. The calss includes API::Source
186
+ # @return [Class] that handles the source. The class includes API::Source
186
187
  def source(name)
187
188
  raise UnknownSourceError, "Source #{name} not found" unless source? name
188
189
 
@@ -244,10 +245,11 @@ module Bundler
244
245
  # @param [Array<String>] names of inferred source plugins that can be ignored
245
246
  def save_plugins(plugins, specs, optional_plugins = [])
246
247
  plugins.each do |name|
248
+ next if index.installed?(name)
249
+
247
250
  spec = specs[name]
248
- validate_plugin! Pathname.new(spec.full_gem_path)
249
- installed = register_plugin(name, spec, optional_plugins.include?(name))
250
- Bundler.ui.info "Installed plugin #{name}" if installed
251
+
252
+ save_plugin(name, spec, optional_plugins.include?(name))
251
253
  end
252
254
  end
253
255
 
@@ -262,6 +264,22 @@ module Bundler
262
264
  raise MalformattedPlugin, "#{PLUGIN_FILE_NAME} was not found in the plugin." unless plugin_file.file?
263
265
  end
264
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
+
265
283
  # Runs the plugins.rb file in an isolated namespace, records the plugin
266
284
  # actions it registers for and then passes the data to index to be stored.
267
285
  #
@@ -308,6 +326,8 @@ module Bundler
308
326
  #
309
327
  # @param [String] name of the plugin
310
328
  def load_plugin(name)
329
+ return unless name && !name.empty?
330
+
311
331
  # Need to ensure before this that plugin root where the rest of gems
312
332
  # are installed to be on load path to support plugin deps. Currently not
313
333
  # done to avoid conflicts
@@ -12,7 +12,7 @@ module Bundler
12
12
  yield
13
13
  f.flock(File::LOCK_UN)
14
14
  end
15
- rescue Errno::EACCES, Errno::ENOLCK, *[SharedHelpers.const_get_safely(:ENOTSUP, Errno)].compact
15
+ rescue Errno::EACCES, Errno::ENOLCK, Errno::ENOTSUP
16
16
  # In the case the user does not have access to
17
17
  # create the lock file or is using NFS where
18
18
  # locks are not available we skip locking.
@@ -1,22 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Psych could be in the stdlib
4
- # but it's too late if Syck is already loaded
5
3
  begin
6
- require "psych" unless defined?(Syck)
4
+ require "psych"
7
5
  rescue LoadError
8
6
  # Apparently Psych wasn't available. Oh well.
9
7
  end
10
8
 
11
9
  # At least load the YAML stdlib, whatever that may be
12
10
  require "yaml" unless defined?(YAML.dump)
13
-
14
- module Bundler
15
- # On encountering invalid YAML,
16
- # Psych raises Psych::SyntaxError
17
- if defined?(::Psych::SyntaxError)
18
- YamlLibrarySyntaxError = ::Psych::SyntaxError
19
- else # Syck raises ArgumentError
20
- YamlLibrarySyntaxError = ::ArgumentError
21
- end
22
- end
@@ -3,28 +3,33 @@
3
3
  module Bundler
4
4
  class Resolver
5
5
  class SpecGroup
6
- include GemHelpers
7
-
8
6
  attr_accessor :name, :version, :source
9
- attr_accessor :ignores_bundler_dependencies, :activated_platforms
7
+ attr_accessor :activated_platforms
8
+
9
+ def self.create_for(specs, all_platforms, specific_platform)
10
+ specific_platform_specs = specs[specific_platform]
11
+ return unless specific_platform_specs.any?
12
+
13
+ platforms = all_platforms.select {|p| specs[p].any? }
14
+
15
+ new(specific_platform_specs.first, specs, platforms)
16
+ end
10
17
 
11
- def initialize(all_specs)
12
- @all_specs = all_specs
13
- raise ArgumentError, "cannot initialize with an empty value" unless exemplary_spec = all_specs.first
18
+ def initialize(exemplary_spec, specs, relevant_platforms)
19
+ @exemplary_spec = exemplary_spec
14
20
  @name = exemplary_spec.name
15
21
  @version = exemplary_spec.version
16
22
  @source = exemplary_spec.source
17
23
 
18
- @activated_platforms = []
19
- @dependencies = nil
20
- @specs = Hash.new do |specs, platform|
21
- specs[platform] = select_best_platform_match(all_specs, platform)
24
+ @activated_platforms = relevant_platforms
25
+ @dependencies = Hash.new do |dependencies, platforms|
26
+ dependencies[platforms] = dependencies_for(platforms)
22
27
  end
23
- @ignores_bundler_dependencies = true
28
+ @specs = specs
24
29
  end
25
30
 
26
31
  def to_specs
27
- @activated_platforms.map do |p|
32
+ activated_platforms.map do |p|
28
33
  specs = @specs[p]
29
34
  next unless specs.any?
30
35
 
@@ -36,31 +41,13 @@ module Bundler
36
41
  end.flatten.compact.uniq
37
42
  end
38
43
 
39
- def copy_for(platforms)
40
- platforms.select! {|p| for?(p) }
41
- return unless platforms.any?
42
-
43
- copied_sg = self.class.new(@all_specs)
44
- copied_sg.ignores_bundler_dependencies = @ignores_bundler_dependencies
45
- copied_sg.activated_platforms = platforms
46
- copied_sg
47
- end
48
-
49
- def for?(platform)
50
- @specs[platform].any?
51
- end
52
-
53
44
  def to_s
54
45
  activated_platforms_string = sorted_activated_platforms.join(", ")
55
46
  "#{name} (#{version}) (#{activated_platforms_string})"
56
47
  end
57
48
 
58
49
  def dependencies_for_activated_platforms
59
- dependencies = @activated_platforms.map {|p| __dependencies[p] }
60
- metadata_dependencies = @activated_platforms.map do |platform|
61
- metadata_dependencies(@specs[platform].first, platform)
62
- end
63
- dependencies.concat(metadata_dependencies).flatten
50
+ @dependencies[activated_platforms]
64
51
  end
65
52
 
66
53
  def ==(other)
@@ -86,34 +73,35 @@ module Bundler
86
73
  protected
87
74
 
88
75
  def sorted_activated_platforms
89
- @activated_platforms.sort_by(&:to_s)
76
+ activated_platforms.sort_by(&:to_s)
90
77
  end
91
78
 
92
79
  private
93
80
 
94
- def __dependencies
95
- @dependencies = Hash.new do |dependencies, platform|
96
- dependencies[platform] = []
97
- specs = @specs[platform]
98
- if spec = specs.first
99
- spec.dependencies.each do |dep|
100
- next if dep.type == :development
101
- next if @ignores_bundler_dependencies && dep.name == "bundler".freeze
102
- dependencies[platform] << DepProxy.new(dep, platform)
103
- end
104
- end
105
- dependencies[platform]
81
+ def dependencies_for(platforms)
82
+ platforms.map do |platform|
83
+ __dependencies(platform) + metadata_dependencies(platform)
84
+ end.flatten
85
+ end
86
+
87
+ def __dependencies(platform)
88
+ dependencies = []
89
+ @specs[platform].first.dependencies.each do |dep|
90
+ next if dep.type == :development
91
+ dependencies << DepProxy.get_proxy(dep, platform)
106
92
  end
93
+ dependencies
107
94
  end
108
95
 
109
- def metadata_dependencies(spec, platform)
110
- return [] unless spec && spec.is_a?(Gem::Specification)
96
+ def metadata_dependencies(platform)
97
+ spec = @specs[platform].first
98
+ return [] if spec.is_a?(LazySpecification)
111
99
  dependencies = []
112
100
  if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
113
- dependencies << DepProxy.new(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
101
+ dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
114
102
  end
115
103
  if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
116
- dependencies << DepProxy.new(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform)
104
+ dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform)
117
105
  end
118
106
  dependencies
119
107
  end
@@ -5,6 +5,8 @@ module Bundler
5
5
  require_relative "vendored_molinillo"
6
6
  require_relative "resolver/spec_group"
7
7
 
8
+ include GemHelpers
9
+
8
10
  # Figures out the best possible configuration of gems that satisfies
9
11
  # the list of passed dependencies and any child dependencies without
10
12
  # causing any gem activation errors.
@@ -15,16 +17,14 @@ module Bundler
15
17
  # ==== Returns
16
18
  # <GemBundle>,nil:: If the list of dependencies can be resolved, a
17
19
  # collection of gemspecs is returned. Otherwise, nil is returned.
18
- def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
19
- platforms = Set.new(platforms) if platforms
20
+ def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
20
21
  base = SpecSet.new(base) unless base.is_a?(SpecSet)
21
- resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
22
+ resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
22
23
  result = resolver.start(requirements)
23
- SpecSet.new(result)
24
+ SpecSet.new(SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") }))
24
25
  end
25
26
 
26
- def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
27
- @index = index
27
+ def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
28
28
  @source_requirements = source_requirements
29
29
  @base = base
30
30
  @resolver = Molinillo::Resolver.new(self, self)
@@ -32,14 +32,13 @@ module Bundler
32
32
  @base_dg = Molinillo::DependencyGraph.new
33
33
  @base.each do |ls|
34
34
  dep = Dependency.new(ls.name, ls.version)
35
- @base_dg.add_vertex(ls.name, DepProxy.new(dep, ls.platform), true)
35
+ @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
36
36
  end
37
37
  additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
38
- @platforms = platforms
38
+ @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } }
39
+ @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY]
39
40
  @gem_version_promoter = gem_version_promoter
40
- @allow_bundler_dependency_conflicts = Bundler.feature_flag.allow_bundler_dependency_conflicts?
41
41
  @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major?
42
- @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource?
43
42
  end
44
43
 
45
44
  def start(requirements)
@@ -49,7 +48,6 @@ module Bundler
49
48
  verify_gemfile_dependencies_are_found!(requirements)
50
49
  dg = @resolver.resolve(requirements, @base_dg)
51
50
  dg.
52
- tap {|resolved| validate_resolved_specs!(resolved) }.
53
51
  map(&:payload).
54
52
  reject {|sg| sg.name.end_with?("\0") }.
55
53
  map(&:to_specs).
@@ -75,7 +73,7 @@ module Bundler
75
73
  return unless debug?
76
74
  debug_info = yield
77
75
  debug_info = debug_info.inspect unless debug_info.is_a?(String)
78
- puts debug_info.split("\n").map {|s| "BUNDLER: " + " " * depth + s }
76
+ puts debug_info.split("\n").map {|s| depth == 0 ? "BUNDLER: #{s}" : "BUNDLER(#{depth}): #{s}" }
79
77
  end
80
78
 
81
79
  def debug?
@@ -109,10 +107,9 @@ module Bundler
109
107
  def search_for(dependency_proxy)
110
108
  platform = dependency_proxy.__platform
111
109
  dependency = dependency_proxy.dep
110
+ name = dependency.name
112
111
  @search_for[dependency_proxy] ||= begin
113
- name = dependency.name
114
- index = index_for(dependency)
115
- results = index.search(dependency, @base[name])
112
+ results = results_for(dependency, @base[name])
116
113
 
117
114
  if vertex = @base_dg.vertex_named(name)
118
115
  locked_requirement = vertex.payload.requirement
@@ -137,53 +134,45 @@ module Bundler
137
134
  end
138
135
  nested.reduce([]) do |groups, (version, specs)|
139
136
  next groups if locked_requirement && !locked_requirement.satisfied_by?(version)
140
- spec_group = SpecGroup.new(specs)
141
- spec_group.ignores_bundler_dependencies = @allow_bundler_dependency_conflicts
137
+ next groups unless specs.any? {|spec| spec.match_platform(platform) }
138
+
139
+ specs_by_platform = Hash.new do |current_specs, current_platform|
140
+ current_specs[current_platform] = select_best_platform_match(specs, current_platform)
141
+ end
142
+
143
+ spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY)
144
+ groups << spec_group_ruby if spec_group_ruby
145
+
146
+ next groups if @resolving_only_for_ruby
147
+
148
+ spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform)
142
149
  groups << spec_group
150
+
151
+ groups
143
152
  end
144
153
  else
145
154
  []
146
155
  end
147
156
  # GVP handles major itself, but it's still a bit risky to trust it with it
148
157
  # until we get it settled with new behavior. For 2.x it can take over all cases.
149
- search = if !@use_gvp
158
+ if !@use_gvp
150
159
  spec_groups
151
160
  else
152
161
  @gem_version_promoter.sort_versions(dependency, spec_groups)
153
162
  end
154
- selected_sgs = []
155
- search.each do |sg|
156
- next unless sg.for?(platform)
157
- sg_all_platforms = sg.copy_for(self.class.sort_platforms(@platforms).reverse)
158
- next unless sg_all_platforms
159
-
160
- selected_sgs << sg_all_platforms
161
-
162
- next if sg_all_platforms.activated_platforms == [Gem::Platform::RUBY]
163
- # Add a spec group for "non platform specific spec" as the fallback
164
- # spec group.
165
- sg_ruby = sg.copy_for([Gem::Platform::RUBY])
166
- selected_sgs.insert(-2, sg_ruby) if sg_ruby
167
- end
168
- selected_sgs
169
163
  end
170
164
  end
171
165
 
172
166
  def index_for(dependency)
173
- source = @source_requirements[dependency.name]
174
- if source
175
- source.specs
176
- elsif @lockfile_uses_separate_rubygems_sources
177
- Index.build do |idx|
178
- if dependency.all_sources
179
- dependency.all_sources.each {|s| idx.add_source(s.specs) if s }
180
- else
181
- idx.add_source @source_requirements[:default].specs
182
- end
183
- end
184
- else
185
- @index
186
- end
167
+ source_for(dependency.name).specs
168
+ end
169
+
170
+ def source_for(name)
171
+ @source_requirements[name] || @source_requirements[:default]
172
+ end
173
+
174
+ def results_for(dependency, base)
175
+ index_for(dependency).search(dependency, base)
187
176
  end
188
177
 
189
178
  def name_for(dependency)
@@ -206,19 +195,12 @@ module Bundler
206
195
  requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
207
196
  end
208
197
 
209
- def relevant_sources_for_vertex(vertex)
210
- if vertex.root?
211
- [@source_requirements[vertex.name]]
212
- elsif @lockfile_uses_separate_rubygems_sources
213
- vertex.recursive_predecessors.map do |v|
214
- @source_requirements[v.name]
215
- end << @source_requirements[:default]
216
- end
198
+ def dependencies_equal?(dependencies, other_dependencies)
199
+ dependencies.map(&:dep) == other_dependencies.map(&:dep)
217
200
  end
218
201
 
219
202
  def sort_dependencies(dependencies, activated, conflicts)
220
203
  dependencies.sort_by do |dependency|
221
- dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name))
222
204
  name = name_for(dependency)
223
205
  vertex = activated.vertex_named(name)
224
206
  [
@@ -233,13 +215,6 @@ module Bundler
233
215
  end
234
216
  end
235
217
 
236
- # Sort platforms from most general to most specific
237
- def self.sort_platforms(platforms)
238
- platforms.sort_by do |platform|
239
- platform_sort_key(platform)
240
- end
241
- end
242
-
243
218
  def self.platform_sort_key(platform)
244
219
  # Prefer specific platform to not specific platform
245
220
  return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform
@@ -279,12 +254,6 @@ module Bundler
279
254
  next if name == "bundler"
280
255
  next unless search_for(requirement).empty?
281
256
 
282
- cache_message = begin
283
- " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
284
- rescue GemfileNotFound
285
- nil
286
- end
287
-
288
257
  if (base = @base[name]) && !base.empty?
289
258
  version = base.first.version
290
259
  message = "You have requested:\n" \
@@ -293,41 +262,53 @@ module Bundler
293
262
  "Try running `bundle update #{name}`\n\n" \
294
263
  "If you are updating multiple gems in your Gemfile at once,\n" \
295
264
  "try passing them all to `bundle update`"
296
- elsif source = @source_requirements[name]
297
- specs = source.specs[name]
298
- versions_with_platforms = specs.map {|s| [s.version, s.platform] }
299
- message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n")
300
- message << if versions_with_platforms.any?
301
- "The source contains the following versions of '#{name}': #{formatted_versions_with_platforms(versions_with_platforms)}"
302
- else
303
- "The source does not contain any versions of '#{name}'"
304
- end
305
265
  else
306
- message = "Could not find gem '#{requirement}' in any of the gem sources " \
307
- "listed in your Gemfile#{cache_message}."
266
+ message = gem_not_found_message(name, requirement, source_for(name))
308
267
  end
309
268
  raise GemNotFound, message
310
269
  end
311
270
  end
312
271
 
313
- def formatted_versions_with_platforms(versions_with_platforms)
314
- version_platform_strs = versions_with_platforms.map do |vwp|
315
- version = vwp.first
316
- platform = vwp.last
317
- version_platform_str = String.new(version.to_s)
318
- version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY
319
- version_platform_str
272
+ def gem_not_found_message(name, requirement, source, extra_message = "")
273
+ specs = source.specs.search(name)
274
+ matching_part = name
275
+ requirement_label = SharedHelpers.pretty_dependency(requirement)
276
+ cache_message = begin
277
+ " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
278
+ rescue GemfileNotFound
279
+ nil
280
+ end
281
+ specs_matching_requirement = specs.select {| spec| requirement.matches_spec?(spec) }
282
+
283
+ if specs_matching_requirement.any?
284
+ specs = specs_matching_requirement
285
+ matching_part = requirement_label
286
+ requirement_label = "#{requirement_label} #{requirement.__platform}"
320
287
  end
321
- version_platform_strs.join(", ")
288
+
289
+ message = String.new("Could not find gem '#{requirement_label}'#{extra_message} in #{source}#{cache_message}.\n")
290
+
291
+ if specs.any?
292
+ message << "\nThe source contains the following gems matching '#{matching_part}':\n"
293
+ message << specs.map {|s| " * #{s.full_name}" }.join("\n")
294
+ end
295
+
296
+ message
322
297
  end
323
298
 
324
299
  def version_conflict_message(e)
325
300
  # only show essential conflicts, if possible
326
301
  conflicts = e.conflicts.dup
327
- conflicts.delete_if do |_name, conflict|
328
- deps = conflict.requirement_trees.map(&:last).flatten(1)
329
- !Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
302
+
303
+ if conflicts["bundler"]
304
+ conflicts.replace("bundler" => conflicts["bundler"])
305
+ else
306
+ conflicts.delete_if do |_name, conflict|
307
+ deps = conflict.requirement_trees.map(&:last).flatten(1)
308
+ !Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
309
+ end
330
310
  end
311
+
331
312
  e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty?
332
313
 
333
314
  solver_name = "Bundler"
@@ -355,51 +336,40 @@ module Bundler
355
336
  :additional_message_for_conflict => lambda do |o, name, conflict|
356
337
  if name == "bundler"
357
338
  o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
358
- other_bundler_required = !conflict.requirement.requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION))
359
- end
360
339
 
361
- if name == "bundler" && other_bundler_required
362
- o << "\n"
363
- o << "This Gemfile requires a different version of Bundler.\n"
364
- o << "Perhaps you need to update Bundler by running `gem install bundler`?\n"
365
- end
366
- if conflict.locked_requirement
340
+ conflict_dependency = conflict.requirement
341
+ conflict_requirement = conflict_dependency.requirement
342
+ other_bundler_required = !conflict_requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION))
343
+
344
+ if other_bundler_required
345
+ o << "\n\n"
346
+
347
+ candidate_specs = source_for(:default_bundler).specs.search(conflict_dependency)
348
+ if candidate_specs.any?
349
+ target_version = candidate_specs.last.version
350
+ new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ")
351
+ o << "Your bundle requires a different version of Bundler than the one you're running.\n"
352
+ o << "Install the necessary version with `gem install bundler:#{target_version}` and rerun bundler using `#{new_command}`\n"
353
+ else
354
+ o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n"
355
+ end
356
+ end
357
+ elsif conflict.locked_requirement
367
358
  o << "\n"
368
359
  o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
369
360
  o << %(the gems in your Gemfile, which may resolve the conflict.\n)
370
- elsif !conflict.existing
361
+ elsif !conflict.existing && !name.end_with?("\0")
371
362
  o << "\n"
372
363
 
373
- relevant_sources = if conflict.requirement.source
374
- [conflict.requirement.source]
375
- elsif conflict.requirement.all_sources
376
- conflict.requirement.all_sources
377
- elsif @lockfile_uses_separate_rubygems_sources
378
- # every conflict should have an explicit group of sources when we
379
- # enforce strict pinning
380
- raise "no source set for #{conflict}"
381
- else
382
- []
383
- end.compact.map(&:to_s).uniq.sort
384
-
385
- metadata_requirement = name.end_with?("\0")
386
-
387
- o << "Could not find gem '" unless metadata_requirement
388
- o << SharedHelpers.pretty_dependency(conflict.requirement)
389
- o << "'" unless metadata_requirement
390
- if conflict.requirement_trees.first.size > 1
391
- o << ", which is required by "
392
- o << "gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}',"
393
- end
394
- o << " "
364
+ relevant_source = conflict.requirement.source || source_for(name)
395
365
 
396
- o << if relevant_sources.empty?
397
- "in any of the sources.\n"
398
- elsif metadata_requirement
399
- "is not available in #{relevant_sources.join(" or ")}"
366
+ extra_message = if conflict.requirement_trees.first.size > 1
367
+ ", which is required by gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}',"
400
368
  else
401
- "in any of the relevant sources:\n #{relevant_sources * "\n "}\n"
369
+ ""
402
370
  end
371
+
372
+ o << gem_not_found_message(name, conflict.requirement, relevant_source, extra_message)
403
373
  end
404
374
  end,
405
375
  :version_for_spec => lambda {|spec| spec.version },
@@ -412,29 +382,5 @@ module Bundler
412
382
  end
413
383
  )
414
384
  end
415
-
416
- def validate_resolved_specs!(resolved_specs)
417
- resolved_specs.each do |v|
418
- name = v.name
419
- next unless sources = relevant_sources_for_vertex(v)
420
- sources.compact!
421
- if default_index = sources.index(@source_requirements[:default])
422
- sources.delete_at(default_index)
423
- end
424
- sources.reject! {|s| s.specs[name].empty? }
425
- sources.uniq!
426
- next if sources.size <= 1
427
-
428
- multisource_disabled = Bundler.feature_flag.disable_multisource?
429
-
430
- msg = ["The gem '#{name}' was found in multiple relevant sources."]
431
- msg.concat sources.map {|s| " * #{s}" }.sort
432
- msg << "You #{multisource_disabled ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
433
- msg = msg.join("\n")
434
-
435
- raise SecurityError, msg if multisource_disabled
436
- Bundler.ui.warn "Warning: #{msg}"
437
- end
438
- end
439
385
  end
440
386
  end
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
 
@@ -103,7 +103,7 @@ module Bundler
103
103
 
104
104
  def self.system
105
105
  ruby_engine = RUBY_ENGINE.dup
106
- ruby_version = ENV.fetch("BUNDLER_SPEC_RUBY_VERSION") { RUBY_VERSION }.dup
106
+ ruby_version = RUBY_VERSION.dup
107
107
  ruby_engine_version = RUBY_ENGINE_VERSION.dup
108
108
  patchlevel = RUBY_PATCHLEVEL.to_s
109
109