bundler 2.2.3 → 2.3.5

Sign up to get free protection for your applications and to get access to all the features.
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