bundler 2.2.26 → 2.3.26

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 (197) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +501 -1
  3. data/README.md +1 -1
  4. data/bundler.gemspec +6 -8
  5. data/exe/bundle +7 -8
  6. data/exe/bundler +1 -1
  7. data/lib/bundler/.document +1 -0
  8. data/lib/bundler/build_metadata.rb +3 -3
  9. data/lib/bundler/cli/check.rb +1 -1
  10. data/lib/bundler/cli/common.rb +3 -2
  11. data/lib/bundler/cli/config.rb +10 -1
  12. data/lib/bundler/cli/doctor.rb +12 -3
  13. data/lib/bundler/cli/gem.rb +98 -9
  14. data/lib/bundler/cli/info.rb +27 -6
  15. data/lib/bundler/cli/init.rb +5 -1
  16. data/lib/bundler/cli/install.rb +13 -30
  17. data/lib/bundler/cli/issue.rb +4 -3
  18. data/lib/bundler/cli/outdated.rb +12 -3
  19. data/lib/bundler/cli/platform.rb +2 -2
  20. data/lib/bundler/cli/remove.rb +1 -2
  21. data/lib/bundler/cli/show.rb +1 -1
  22. data/lib/bundler/cli/update.rb +8 -4
  23. data/lib/bundler/cli.rb +23 -19
  24. data/lib/bundler/compact_index_client/cache.rb +0 -9
  25. data/lib/bundler/compact_index_client/updater.rb +16 -8
  26. data/lib/bundler/compact_index_client.rb +2 -8
  27. data/lib/bundler/current_ruby.rb +16 -6
  28. data/lib/bundler/definition.rb +204 -217
  29. data/lib/bundler/dependency.rb +23 -71
  30. data/lib/bundler/digest.rb +71 -0
  31. data/lib/bundler/dsl.rb +28 -45
  32. data/lib/bundler/endpoint_specification.rb +19 -13
  33. data/lib/bundler/env.rb +1 -1
  34. data/lib/bundler/environment_preserver.rb +4 -1
  35. data/lib/bundler/errors.rb +28 -2
  36. data/lib/bundler/feature_flag.rb +0 -1
  37. data/lib/bundler/fetcher/base.rb +6 -8
  38. data/lib/bundler/fetcher/compact_index.rb +9 -14
  39. data/lib/bundler/fetcher/index.rb +0 -26
  40. data/lib/bundler/fetcher.rb +20 -22
  41. data/lib/bundler/friendly_errors.rb +26 -34
  42. data/lib/bundler/gem_helper.rb +7 -18
  43. data/lib/bundler/gem_helpers.rb +9 -2
  44. data/lib/bundler/gem_version_promoter.rb +14 -25
  45. data/lib/bundler/index.rb +10 -40
  46. data/lib/bundler/injector.rb +16 -2
  47. data/lib/bundler/inline.rb +2 -12
  48. data/lib/bundler/installer/gem_installer.rb +13 -5
  49. data/lib/bundler/installer/standalone.rb +30 -3
  50. data/lib/bundler/installer.rb +18 -29
  51. data/lib/bundler/lazy_specification.rb +52 -35
  52. data/lib/bundler/lockfile_generator.rb +2 -2
  53. data/lib/bundler/lockfile_parser.rb +12 -10
  54. data/lib/bundler/man/bundle-add.1 +21 -5
  55. data/lib/bundler/man/bundle-add.1.ronn +16 -4
  56. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  57. data/lib/bundler/man/bundle-cache.1 +7 -1
  58. data/lib/bundler/man/bundle-cache.1.ronn +7 -0
  59. data/lib/bundler/man/bundle-check.1 +1 -1
  60. data/lib/bundler/man/bundle-clean.1 +2 -2
  61. data/lib/bundler/man/bundle-clean.1.ronn +1 -1
  62. data/lib/bundler/man/bundle-config.1 +33 -14
  63. data/lib/bundler/man/bundle-config.1.ronn +30 -18
  64. data/lib/bundler/man/bundle-console.1 +53 -0
  65. data/lib/bundler/man/bundle-console.1.ronn +44 -0
  66. data/lib/bundler/man/bundle-doctor.1 +1 -1
  67. data/lib/bundler/man/bundle-exec.1 +2 -2
  68. data/lib/bundler/man/bundle-exec.1.ronn +1 -1
  69. data/lib/bundler/man/bundle-gem.1 +14 -1
  70. data/lib/bundler/man/bundle-gem.1.ronn +16 -0
  71. data/lib/bundler/man/bundle-help.1 +13 -0
  72. data/lib/bundler/man/bundle-help.1.ronn +12 -0
  73. data/lib/bundler/man/bundle-info.1 +1 -1
  74. data/lib/bundler/man/bundle-init.1 +1 -1
  75. data/lib/bundler/man/bundle-inject.1 +5 -2
  76. data/lib/bundler/man/bundle-inject.1.ronn +3 -1
  77. data/lib/bundler/man/bundle-install.1 +6 -2
  78. data/lib/bundler/man/bundle-install.1.ronn +8 -2
  79. data/lib/bundler/man/bundle-list.1 +1 -1
  80. data/lib/bundler/man/bundle-lock.1 +1 -1
  81. data/lib/bundler/man/bundle-open.1 +1 -1
  82. data/lib/bundler/man/bundle-outdated.1 +3 -10
  83. data/lib/bundler/man/bundle-outdated.1.ronn +1 -10
  84. data/lib/bundler/man/bundle-platform.1 +16 -6
  85. data/lib/bundler/man/bundle-platform.1.ronn +14 -7
  86. data/lib/bundler/man/bundle-plugin.1 +81 -0
  87. data/lib/bundler/man/bundle-plugin.1.ronn +59 -0
  88. data/lib/bundler/man/bundle-pristine.1 +1 -1
  89. data/lib/bundler/man/bundle-remove.1 +1 -1
  90. data/lib/bundler/man/bundle-show.1 +1 -1
  91. data/lib/bundler/man/bundle-update.1 +2 -2
  92. data/lib/bundler/man/bundle-update.1.ronn +2 -1
  93. data/lib/bundler/man/bundle-version.1 +35 -0
  94. data/lib/bundler/man/bundle-version.1.ronn +24 -0
  95. data/lib/bundler/man/bundle-viz.1 +4 -1
  96. data/lib/bundler/man/bundle-viz.1.ronn +2 -0
  97. data/lib/bundler/man/bundle.1 +15 -10
  98. data/lib/bundler/man/bundle.1.ronn +12 -7
  99. data/lib/bundler/man/gemfile.5 +117 -80
  100. data/lib/bundler/man/gemfile.5.ronn +105 -84
  101. data/lib/bundler/man/index.txt +4 -0
  102. data/lib/bundler/match_metadata.rb +13 -0
  103. data/lib/bundler/match_platform.rb +0 -1
  104. data/lib/bundler/match_remote_metadata.rb +29 -0
  105. data/lib/bundler/plugin/api/source.rb +4 -9
  106. data/lib/bundler/plugin/installer/git.rb +0 -4
  107. data/lib/bundler/plugin/installer/rubygems.rb +0 -4
  108. data/lib/bundler/plugin/installer.rb +3 -1
  109. data/lib/bundler/plugin.rb +25 -6
  110. data/lib/bundler/process_lock.rb +1 -1
  111. data/lib/bundler/remote_specification.rb +10 -4
  112. data/lib/bundler/resolver/base.rb +50 -0
  113. data/lib/bundler/resolver/spec_group.rb +31 -49
  114. data/lib/bundler/resolver.rb +183 -192
  115. data/lib/bundler/ruby_dsl.rb +1 -1
  116. data/lib/bundler/ruby_version.rb +5 -18
  117. data/lib/bundler/rubygems_ext.rb +138 -20
  118. data/lib/bundler/rubygems_gem_installer.rb +42 -16
  119. data/lib/bundler/rubygems_integration.rb +42 -90
  120. data/lib/bundler/runtime.rb +2 -3
  121. data/lib/bundler/self_manager.rb +168 -0
  122. data/lib/bundler/settings.rb +13 -4
  123. data/lib/bundler/shared_helpers.rb +15 -24
  124. data/lib/bundler/source/git/git_proxy.rb +7 -4
  125. data/lib/bundler/source/git.rb +29 -13
  126. data/lib/bundler/source/metadata.rb +3 -3
  127. data/lib/bundler/source/path.rb +1 -1
  128. data/lib/bundler/source/rubygems.rb +148 -161
  129. data/lib/bundler/source/rubygems_aggregate.rb +1 -1
  130. data/lib/bundler/source.rb +6 -5
  131. data/lib/bundler/source_list.rb +15 -29
  132. data/lib/bundler/source_map.rb +15 -2
  133. data/lib/bundler/spec_set.rb +52 -32
  134. data/lib/bundler/stub_specification.rb +5 -3
  135. data/lib/bundler/templates/Executable +2 -4
  136. data/lib/bundler/templates/Executable.bundler +2 -2
  137. data/lib/bundler/templates/Executable.standalone +2 -4
  138. data/lib/bundler/templates/Gemfile +0 -2
  139. data/lib/bundler/templates/gems.rb +0 -3
  140. data/lib/bundler/templates/newgem/Gemfile.tt +5 -2
  141. data/lib/bundler/templates/newgem/README.md.tt +3 -9
  142. data/lib/bundler/templates/newgem/Rakefile.tt +15 -2
  143. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +5 -4
  144. data/lib/bundler/templates/newgem/gitlab-ci.yml.tt +5 -4
  145. data/lib/bundler/templates/newgem/newgem.gemspec.tt +16 -16
  146. data/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  147. data/lib/bundler/templates/newgem/standard.yml.tt +3 -0
  148. data/lib/bundler/templates/newgem/test/minitest/{newgem_test.rb.tt → test_newgem.rb.tt} +1 -1
  149. data/lib/bundler/ui/shell.rb +1 -1
  150. data/lib/bundler/vendor/.document +1 -0
  151. data/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  152. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +19 -21
  153. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  154. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +57 -0
  155. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +39 -74
  156. data/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  157. data/lib/bundler/vendor/molinillo/LICENSE +9 -0
  158. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +3 -3
  159. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +32 -26
  160. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  161. data/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  162. data/lib/bundler/vendor/thor/LICENSE.md +20 -0
  163. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +6 -6
  164. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +1 -2
  165. data/lib/bundler/vendor/thor/lib/thor/actions.rb +6 -2
  166. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +6 -0
  167. data/lib/bundler/vendor/thor/lib/thor/error.rb +9 -4
  168. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +19 -1
  169. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +22 -4
  170. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  171. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  172. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  173. data/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  174. data/lib/bundler/vendor/tsort/lib/tsort.rb +452 -0
  175. data/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  176. data/lib/bundler/vendor/uri/lib/uri/common.rb +17 -80
  177. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +0 -1
  178. data/lib/bundler/vendor/uri/lib/uri/generic.rb +5 -6
  179. data/lib/bundler/vendor/uri/lib/uri/http.rb +0 -1
  180. data/lib/bundler/vendor/uri/lib/uri/https.rb +0 -1
  181. data/lib/bundler/vendor/uri/lib/uri/ldap.rb +1 -1
  182. data/lib/bundler/vendor/uri/lib/uri/mailto.rb +0 -1
  183. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +1 -14
  184. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -12
  185. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  186. data/lib/bundler/vendor/uri/lib/uri/ws.rb +84 -0
  187. data/lib/bundler/vendor/uri/lib/uri/wss.rb +22 -0
  188. data/lib/bundler/vendor/uri/lib/uri.rb +0 -1
  189. data/lib/bundler/vendored_tsort.rb +4 -0
  190. data/lib/bundler/version.rb +1 -1
  191. data/lib/bundler/worker.rb +2 -2
  192. data/lib/bundler.rb +40 -29
  193. metadata +37 -12
  194. data/lib/bundler/dep_proxy.rb +0 -55
  195. data/lib/bundler/gemdeps.rb +0 -29
  196. data/lib/bundler/psyched_yaml.rb +0 -22
  197. data/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb +0 -66
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ class Resolver
5
+ class Base
6
+ def initialize(base, additional_base_requirements)
7
+ @base = base
8
+ @additional_base_requirements = additional_base_requirements
9
+ end
10
+
11
+ def [](name)
12
+ @base[name]
13
+ end
14
+
15
+ def delete(spec)
16
+ @base.delete(spec)
17
+ end
18
+
19
+ def base_requirements
20
+ @base_requirements ||= build_base_requirements
21
+ end
22
+
23
+ def unlock_deps(deps)
24
+ exact, lower_bound = deps.partition(&:specific?)
25
+
26
+ exact.each do |exact_dep|
27
+ @base.delete_by_name_and_version(exact_dep.name, exact_dep.requirement.requirements.first.last)
28
+ end
29
+
30
+ lower_bound.each do |lower_bound_dep|
31
+ @additional_base_requirements.delete(lower_bound_dep)
32
+ end
33
+
34
+ @base_requirements = nil
35
+ end
36
+
37
+ private
38
+
39
+ def build_base_requirements
40
+ base_requirements = {}
41
+ @base.each do |ls|
42
+ dep = Dependency.new(ls.name, ls.version)
43
+ base_requirements[ls.name] = dep
44
+ end
45
+ @additional_base_requirements.each {|d| base_requirements[d.name] = d }
46
+ base_requirements
47
+ end
48
+ end
49
+ end
50
+ end
@@ -4,41 +4,25 @@ module Bundler
4
4
  class Resolver
5
5
  class SpecGroup
6
6
  attr_accessor :name, :version, :source
7
- attr_accessor :activated_platforms
7
+ attr_accessor :activated_platforms, :force_ruby_platform
8
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
17
-
18
- def initialize(exemplary_spec, specs, relevant_platforms)
19
- @exemplary_spec = exemplary_spec
20
- @name = exemplary_spec.name
21
- @version = exemplary_spec.version
22
- @source = exemplary_spec.source
9
+ def initialize(specs, relevant_platforms)
10
+ @exemplary_spec = specs.first
11
+ @name = @exemplary_spec.name
12
+ @version = @exemplary_spec.version
13
+ @source = @exemplary_spec.source
23
14
 
24
15
  @activated_platforms = relevant_platforms
25
- @dependencies = Hash.new do |dependencies, platforms|
26
- dependencies[platforms] = dependencies_for(platforms)
27
- end
28
16
  @specs = specs
29
17
  end
30
18
 
31
19
  def to_specs
32
- activated_platforms.map do |p|
33
- specs = @specs[p]
34
- next unless specs.any?
35
-
36
- specs.map do |s|
37
- lazy_spec = LazySpecification.new(name, version, s.platform, source)
38
- lazy_spec.dependencies.replace s.dependencies
39
- lazy_spec
40
- end
41
- end.flatten.compact.uniq
20
+ @specs.map do |s|
21
+ lazy_spec = LazySpecification.new(name, version, s.platform, source)
22
+ lazy_spec.force_ruby_platform = force_ruby_platform
23
+ lazy_spec.dependencies.replace s.dependencies
24
+ lazy_spec
25
+ end
42
26
  end
43
27
 
44
28
  def to_s
@@ -47,7 +31,9 @@ module Bundler
47
31
  end
48
32
 
49
33
  def dependencies_for_activated_platforms
50
- @dependencies[activated_platforms]
34
+ @dependencies_for_activated_platforms ||= @specs.map do |spec|
35
+ __dependencies(spec) + metadata_dependencies(spec)
36
+ end.flatten.uniq
51
37
  end
52
38
 
53
39
  def ==(other)
@@ -78,32 +64,28 @@ module Bundler
78
64
 
79
65
  private
80
66
 
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)
67
+ def __dependencies(spec)
88
68
  dependencies = []
89
- @specs[platform].first.dependencies.each do |dep|
69
+ spec.dependencies.each do |dep|
90
70
  next if dep.type == :development
91
- dependencies << DepProxy.get_proxy(dep, platform)
71
+ dependencies << Dependency.new(dep.name, dep.requirement)
92
72
  end
93
73
  dependencies
94
74
  end
95
75
 
96
- def metadata_dependencies(platform)
97
- spec = @specs[platform].first
98
- return [] unless spec.is_a?(Gem::Specification)
99
- dependencies = []
100
- if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
101
- dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
102
- end
103
- if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
104
- dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform)
105
- end
106
- dependencies
76
+ def metadata_dependencies(spec)
77
+ return [] if spec.is_a?(LazySpecification)
78
+
79
+ [
80
+ metadata_dependency("Ruby", spec.required_ruby_version),
81
+ metadata_dependency("RubyGems", spec.required_rubygems_version),
82
+ ].compact
83
+ end
84
+
85
+ def metadata_dependency(name, requirement)
86
+ return if requirement.nil? || requirement.none?
87
+
88
+ Dependency.new("#{name}\0", requirement)
107
89
  end
108
90
  end
109
91
  end
@@ -3,60 +3,54 @@
3
3
  module Bundler
4
4
  class Resolver
5
5
  require_relative "vendored_molinillo"
6
+ require_relative "resolver/base"
6
7
  require_relative "resolver/spec_group"
7
8
 
8
9
  include GemHelpers
9
10
 
10
- # Figures out the best possible configuration of gems that satisfies
11
- # the list of passed dependencies and any child dependencies without
12
- # causing any gem activation errors.
13
- #
14
- # ==== Parameters
15
- # *dependencies<Gem::Dependency>:: The list of dependencies to resolve
16
- #
17
- # ==== Returns
18
- # <GemBundle>,nil:: If the list of dependencies can be resolved, a
19
- # collection of gemspecs is returned. Otherwise, nil is returned.
20
- def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
21
- base = SpecSet.new(base) unless base.is_a?(SpecSet)
22
- resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
23
- result = resolver.start(requirements)
24
- SpecSet.new(SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") }))
25
- end
26
-
27
11
  def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
28
12
  @source_requirements = source_requirements
29
- @base = base
13
+ @base = Resolver::Base.new(base, additional_base_requirements)
30
14
  @resolver = Molinillo::Resolver.new(self, self)
15
+ @results_for = {}
31
16
  @search_for = {}
32
- @base_dg = Molinillo::DependencyGraph.new
33
- aggregate_global_source = @source_requirements[:default].is_a?(Source::RubygemsAggregate)
34
- @base.each do |ls|
35
- dep = Dependency.new(ls.name, ls.version)
36
- ls.source = source_for(ls.name) unless aggregate_global_source
37
- @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
38
- end
39
- additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
40
- @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } }
17
+ @platforms = platforms
41
18
  @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY]
42
19
  @gem_version_promoter = gem_version_promoter
43
- @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major?
44
20
  end
45
21
 
46
- def start(requirements)
47
- @gem_version_promoter.prerelease_specified = @prerelease_specified = {}
48
- requirements.each {|dep| @prerelease_specified[dep.name] ||= dep.prerelease? }
22
+ def start(requirements, exclude_specs: [])
23
+ @metadata_requirements, regular_requirements = requirements.partition {|dep| dep.name.end_with?("\0") }
24
+
25
+ exclude_specs.each do |spec|
26
+ remove_from_candidates(spec)
27
+ end
28
+
29
+ requirements.each {|dep| prerelease_specified[dep.name] ||= dep.prerelease? }
49
30
 
50
31
  verify_gemfile_dependencies_are_found!(requirements)
51
- dg = @resolver.resolve(requirements, @base_dg)
52
- dg.
32
+ result = @resolver.resolve(requirements).
53
33
  map(&:payload).
54
34
  reject {|sg| sg.name.end_with?("\0") }.
55
35
  map(&:to_specs).
56
36
  flatten
37
+
38
+ SpecSet.new(SpecSet.new(result).for(regular_requirements, false, @platforms))
57
39
  rescue Molinillo::VersionConflict => e
40
+ conflicts = e.conflicts
41
+
42
+ deps_to_unlock = conflicts.values.inject([]) do |deps, conflict|
43
+ deps |= conflict.requirement_trees.flatten.map {|req| base_requirements[req.name] }.compact
44
+ end
45
+
46
+ if deps_to_unlock.any?
47
+ @base.unlock_deps(deps_to_unlock)
48
+ reset_spec_cache
49
+ retry
50
+ end
51
+
58
52
  message = version_conflict_message(e)
59
- raise VersionConflict.new(e.conflicts.keys.uniq, message)
53
+ raise VersionConflict.new(conflicts.keys.uniq, message)
60
54
  rescue Molinillo::CircularDependencyError => e
61
55
  names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" }
62
56
  raise CyclicDependencyError, "Your bundle requires gems that depend" \
@@ -106,60 +100,35 @@ module Bundler
106
100
  specification.dependencies_for_activated_platforms
107
101
  end
108
102
 
109
- def search_for(dependency_proxy)
110
- platform = dependency_proxy.__platform
111
- dependency = dependency_proxy.dep
112
- name = dependency.name
113
- @search_for[dependency_proxy] ||= begin
114
- results = results_for(dependency, @base[name])
115
-
116
- if vertex = @base_dg.vertex_named(name)
117
- locked_requirement = vertex.payload.requirement
118
- end
119
-
120
- if !@prerelease_specified[name] && (!@use_gvp || locked_requirement.nil?)
121
- # Move prereleases to the beginning of the list, so they're considered
122
- # last during resolution.
123
- pre, results = results.partition {|spec| spec.version.prerelease? }
124
- results = pre + results
125
- end
126
-
127
- spec_groups = if results.any?
128
- nested = []
129
- results.each do |spec|
130
- version, specs = nested.last
131
- if version == spec.version
132
- specs << spec
133
- else
134
- nested << [spec.version, [spec]]
135
- end
103
+ def search_for(dependency)
104
+ @search_for[dependency] ||= begin
105
+ name = dependency.name
106
+ locked_results = @base[name].select {|spec| requirement_satisfied_by?(dependency, nil, spec) }
107
+ locked_requirement = base_requirements[name]
108
+ results = results_for(dependency) + locked_results
109
+ results = results.select {|spec| requirement_satisfied_by?(locked_requirement, nil, spec) } if locked_requirement
110
+ dep_platforms = dependency.gem_platforms(@platforms)
111
+
112
+ @gem_version_promoter.sort_versions(dependency, results).group_by(&:version).reduce([]) do |groups, (_, specs)|
113
+ relevant_platforms = dep_platforms.select {|platform| specs.any? {|spec| spec.match_platform(platform) } }
114
+ next groups unless relevant_platforms.any?
115
+
116
+ ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY)
117
+ if ruby_specs.any?
118
+ spec_group_ruby = SpecGroup.new(ruby_specs, [Gem::Platform::RUBY])
119
+ spec_group_ruby.force_ruby_platform = dependency.force_ruby_platform
120
+ groups << spec_group_ruby
136
121
  end
137
- nested.reduce([]) do |groups, (version, specs)|
138
- next groups if locked_requirement && !locked_requirement.satisfied_by?(version)
139
-
140
- specs_by_platform = Hash.new do |current_specs, current_platform|
141
- current_specs[current_platform] = select_best_platform_match(specs, current_platform)
142
- end
143
122
 
144
- spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY)
145
- groups << spec_group_ruby if spec_group_ruby
123
+ next groups if @resolving_only_for_ruby || dependency.force_ruby_platform
146
124
 
147
- next groups if @resolving_only_for_ruby
125
+ platform_specs = relevant_platforms.flat_map {|platform| select_best_platform_match(specs, platform) }
126
+ next groups if platform_specs == ruby_specs
148
127
 
149
- spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform)
150
- groups << spec_group if spec_group
128
+ spec_group = SpecGroup.new(platform_specs, relevant_platforms)
129
+ groups << spec_group
151
130
 
152
- groups
153
- end
154
- else
155
- []
156
- end
157
- # GVP handles major itself, but it's still a bit risky to trust it with it
158
- # until we get it settled with new behavior. For 2.x it can take over all cases.
159
- if !@use_gvp
160
- spec_groups
161
- else
162
- @gem_version_promoter.sort_versions(dependency, spec_groups)
131
+ groups
163
132
  end
164
133
  end
165
134
  end
@@ -172,8 +141,8 @@ module Bundler
172
141
  @source_requirements[name] || @source_requirements[:default]
173
142
  end
174
143
 
175
- def results_for(dependency, base)
176
- index_for(dependency).search(dependency, base)
144
+ def results_for(dependency)
145
+ @results_for[dependency] ||= index_for(dependency).search(dependency)
177
146
  end
178
147
 
179
148
  def name_for(dependency)
@@ -186,43 +155,51 @@ module Bundler
186
155
  "Gemfile"
187
156
  end
188
157
 
189
- def name_for_locking_dependency_source
190
- Bundler.default_lockfile.basename.to_s
191
- rescue StandardError
192
- "Gemfile.lock"
193
- end
194
-
195
158
  def requirement_satisfied_by?(requirement, activated, spec)
196
159
  requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
197
160
  end
198
161
 
199
- def dependencies_equal?(dependencies, other_dependencies)
200
- dependencies.map(&:dep) == other_dependencies.map(&:dep)
201
- end
202
-
203
162
  def sort_dependencies(dependencies, activated, conflicts)
204
163
  dependencies.sort_by do |dependency|
205
164
  name = name_for(dependency)
206
165
  vertex = activated.vertex_named(name)
207
166
  [
208
- @base_dg.vertex_named(name) ? 0 : 1,
167
+ @base[name].any? ? 0 : 1,
209
168
  vertex.payload ? 0 : 1,
210
169
  vertex.root? ? 0 : 1,
211
170
  amount_constrained(dependency),
212
171
  conflicts[name] ? 0 : 1,
213
172
  vertex.payload ? 0 : search_for(dependency).count,
214
- self.class.platform_sort_key(dependency.__platform),
215
173
  ]
216
174
  end
217
175
  end
218
176
 
219
- def self.platform_sort_key(platform)
220
- # Prefer specific platform to not specific platform
221
- return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform
222
- ["00", *platform.to_a.map {|part| part || "" }]
177
+ private
178
+
179
+ def base_requirements
180
+ @base.base_requirements
223
181
  end
224
182
 
225
- private
183
+ def prerelease_specified
184
+ @gem_version_promoter.prerelease_specified
185
+ end
186
+
187
+ def remove_from_candidates(spec)
188
+ @base.delete(spec)
189
+
190
+ @results_for.keys.each do |dep|
191
+ next unless dep.name == spec.name
192
+
193
+ @results_for[dep].reject {|s| s.name == spec.name && s.version == spec.version }
194
+ end
195
+
196
+ reset_spec_cache
197
+ end
198
+
199
+ def reset_spec_cache
200
+ @search_for = {}
201
+ @gem_version_promoter.reset
202
+ end
226
203
 
227
204
  # returns an integer \in (-\infty, 0]
228
205
  # a number closer to 0 means the dependency is less constraining
@@ -232,62 +209,60 @@ module Bundler
232
209
  # before dependencies that are unconstrained
233
210
  def amount_constrained(dependency)
234
211
  @amount_constrained ||= {}
235
- @amount_constrained[dependency.name] ||= begin
236
- if (base = @base[dependency.name]) && !base.empty?
237
- dependency.requirement.satisfied_by?(base.first.version) ? 0 : 1
238
- else
239
- all = index_for(dependency).search(dependency.name).size
212
+ @amount_constrained[dependency.name] ||= if (base = @base[dependency.name]) && !base.empty?
213
+ dependency.requirement.satisfied_by?(base.first.version) ? 0 : 1
214
+ else
215
+ all = index_for(dependency).search(dependency.name).size
240
216
 
241
- if all <= 1
242
- all - 1_000_000
243
- else
244
- search = search_for(dependency)
245
- search = @prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? }
246
- search - all
247
- end
217
+ if all <= 1
218
+ all - 1_000_000
219
+ else
220
+ search = search_for(dependency)
221
+ search = prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? }
222
+ search - all
248
223
  end
249
224
  end
250
225
  end
251
226
 
252
227
  def verify_gemfile_dependencies_are_found!(requirements)
253
- requirements.each do |requirement|
228
+ requirements.map! do |requirement|
254
229
  name = requirement.name
255
- next if name == "bundler"
256
- next unless search_for(requirement).empty?
257
-
258
- if (base = @base[name]) && !base.empty?
259
- version = base.first.version
260
- message = "You have requested:\n" \
261
- " #{name} #{requirement.requirement}\n\n" \
262
- "The bundle currently has #{name} locked at #{version}.\n" \
263
- "Try running `bundle update #{name}`\n\n" \
264
- "If you are updating multiple gems in your Gemfile at once,\n" \
265
- "try passing them all to `bundle update`"
266
- else
267
- source = source_for(name)
268
- specs = source.specs.search(name)
269
- versions_with_platforms = specs.map {|s| [s.version, s.platform] }
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?
277
- end
278
- raise GemNotFound, message
279
- end
230
+ next requirement if name == "bundler"
231
+ next if requirement.gem_platforms(@platforms).empty?
232
+ next requirement unless search_for(requirement).empty?
233
+ next unless requirement.current_platform?
234
+
235
+ raise GemNotFound, gem_not_found_message(name, requirement, source_for(name))
236
+ end.compact!
280
237
  end
281
238
 
282
- def formatted_versions_with_platforms(versions_with_platforms)
283
- version_platform_strs = versions_with_platforms.map do |vwp|
284
- version = vwp.first
285
- platform = vwp.last
286
- version_platform_str = String.new(version.to_s)
287
- version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY
288
- version_platform_str
239
+ def gem_not_found_message(name, requirement, source, extra_message = "")
240
+ specs = source.specs.search(name).sort_by {|s| [s.version, s.platform.to_s] }
241
+ matching_part = name
242
+ requirement_label = SharedHelpers.pretty_dependency(requirement)
243
+ cache_message = begin
244
+ " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
245
+ rescue GemfileNotFound
246
+ nil
247
+ end
248
+ specs_matching_requirement = specs.select {| spec| requirement.matches_spec?(spec) }
249
+
250
+ if specs_matching_requirement.any?
251
+ specs = specs_matching_requirement
252
+ matching_part = requirement_label
253
+ platforms = requirement.gem_platforms(@platforms)
254
+ platform_label = platforms.size == 1 ? "platform '#{platforms.first}" : "platforms '#{platforms.join("', '")}"
255
+ requirement_label = "#{requirement_label}' with #{platform_label}"
256
+ end
257
+
258
+ message = String.new("Could not find gem '#{requirement_label}'#{extra_message} in #{source}#{cache_message}.\n")
259
+
260
+ if specs.any?
261
+ message << "\nThe source contains the following gems matching '#{matching_part}':\n"
262
+ message << specs.map {|s| " * #{s.full_name}" }.join("\n")
289
263
  end
290
- version_platform_strs.join(", ")
264
+
265
+ message
291
266
  end
292
267
 
293
268
  def version_conflict_message(e)
@@ -305,29 +280,62 @@ module Bundler
305
280
 
306
281
  e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty?
307
282
 
308
- solver_name = "Bundler"
309
- possibility_type = "gem"
310
283
  e.message_with_trees(
311
- :solver_name => solver_name,
312
- :possibility_type => possibility_type,
313
- :reduce_trees => lambda do |trees|
284
+ :full_message_for_conflict => lambda do |name, conflict|
285
+ trees = conflict.requirement_trees
286
+
314
287
  # called first, because we want to reduce the amount of work required to find maximal empty sets
315
288
  trees = trees.uniq {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } }
316
289
 
317
290
  # bail out if tree size is too big for Array#combination to make any sense
318
- return trees if trees.size > 15
319
- maximal = 1.upto(trees.size).map do |size|
320
- trees.map(&:last).flatten(1).combination(size).to_a
321
- end.flatten(1).select do |deps|
322
- Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
323
- end.min_by(&:size)
324
-
325
- trees.reject! {|t| !maximal.include?(t.last) } if maximal
326
-
327
- trees.sort_by {|t| t.reverse.map(&:name) }
328
- end,
329
- :printable_requirement => lambda {|req| SharedHelpers.pretty_dependency(req) },
330
- :additional_message_for_conflict => lambda do |o, name, conflict|
291
+ if trees.size <= 15
292
+ maximal = 1.upto(trees.size).map do |size|
293
+ trees.map(&:last).flatten(1).combination(size).to_a
294
+ end.flatten(1).select do |deps|
295
+ Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
296
+ end.min_by(&:size)
297
+
298
+ trees.reject! {|t| !maximal.include?(t.last) } if maximal
299
+
300
+ trees.sort_by! {|t| t.reverse.map(&:name) }
301
+ end
302
+
303
+ if trees.size > 1 || name == "bundler"
304
+ o = if name.end_with?("\0")
305
+ String.new("Bundler found conflicting requirements for the #{name} version:")
306
+ else
307
+ String.new("Bundler could not find compatible versions for gem \"#{name}\":")
308
+ end
309
+ o << %(\n)
310
+ o << %( In #{name_for_explicit_dependency_source}:\n)
311
+ o << trees.map do |tree|
312
+ t = "".dup
313
+ depth = 2
314
+
315
+ base_tree = tree.first
316
+ base_tree_name = base_tree.name
317
+
318
+ if base_tree_name.end_with?("\0")
319
+ t = nil
320
+ else
321
+ tree.each do |req|
322
+ t << " " * depth << SharedHelpers.pretty_dependency(req)
323
+ unless tree.last == req
324
+ if spec = conflict.activated_by_name[req.name]
325
+ t << %( was resolved to #{spec.version}, which)
326
+ end
327
+ t << %( depends on)
328
+ end
329
+ t << %(\n)
330
+ depth += 1
331
+ end
332
+ end
333
+ t
334
+ end.compact.join("\n")
335
+ else
336
+ o = String.new
337
+ end
338
+
331
339
  if name == "bundler"
332
340
  o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
333
341
 
@@ -348,40 +356,23 @@ module Bundler
348
356
  o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n"
349
357
  end
350
358
  end
351
- elsif conflict.locked_requirement
352
- o << "\n"
353
- o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
354
- o << %(the gems in your Gemfile, which may resolve the conflict.\n)
359
+ elsif name.end_with?("\0")
360
+ o << %(\n Current #{name} version:\n #{SharedHelpers.pretty_dependency(@metadata_requirements.find {|req| req.name == name })}\n\n)
355
361
  elsif !conflict.existing
356
362
  o << "\n"
357
363
 
358
364
  relevant_source = conflict.requirement.source || source_for(name)
359
365
 
360
- metadata_requirement = name.end_with?("\0")
361
-
362
- o << "Could not find gem '" unless metadata_requirement
363
- o << SharedHelpers.pretty_dependency(conflict.requirement)
364
- o << "'" unless metadata_requirement
365
- if conflict.requirement_trees.first.size > 1
366
- o << ", which is required by "
367
- o << "gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}',"
368
- end
369
- o << " "
370
-
371
- o << if metadata_requirement
372
- "is not available in #{relevant_source}"
366
+ extra_message = if trees.first.size > 1
367
+ ", which is required by gem '#{SharedHelpers.pretty_dependency(trees.first[-2])}',"
373
368
  else
374
- "in #{relevant_source.to_err}.\n"
369
+ ""
375
370
  end
371
+
372
+ o << gem_not_found_message(name, conflict.requirement, relevant_source, extra_message)
376
373
  end
377
- end,
378
- :version_for_spec => lambda {|spec| spec.version },
379
- :incompatible_version_message_for_conflict => lambda do |name, _conflict|
380
- if name.end_with?("\0")
381
- %(#{solver_name} found conflicting requirements for the #{name} version:)
382
- else
383
- %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
384
- end
374
+
375
+ o
385
376
  end
386
377
  )
387
378
  end
@@ -9,7 +9,7 @@ module Bundler
9
9
  raise GemfileError, "Please define :engine" if options[:engine_version] && options[:engine].nil?
10
10
 
11
11
  if options[:engine] == "ruby" && options[:engine_version] &&
12
- ruby_version != Array(options[:engine_version])
12
+ ruby_version != Array(options[:engine_version])
13
13
  raise GemfileEvalError, "ruby_version must match the :engine_version for MRI"
14
14
  end
15
15
  @ruby_version = RubyVersion.new(ruby_version, options[:patchlevel], options[:engine], options[:engine_version])