bundler 2.2.11 → 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 (211) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +721 -5
  3. data/README.md +1 -1
  4. data/bundler.gemspec +8 -11
  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/cache.rb +1 -1
  10. data/lib/bundler/cli/check.rb +4 -2
  11. data/lib/bundler/cli/common.rb +17 -3
  12. data/lib/bundler/cli/config.rb +10 -1
  13. data/lib/bundler/cli/doctor.rb +24 -5
  14. data/lib/bundler/cli/exec.rb +1 -6
  15. data/lib/bundler/cli/gem.rb +130 -26
  16. data/lib/bundler/cli/info.rb +27 -6
  17. data/lib/bundler/cli/init.rb +5 -1
  18. data/lib/bundler/cli/install.rb +23 -54
  19. data/lib/bundler/cli/issue.rb +4 -3
  20. data/lib/bundler/cli/list.rb +7 -1
  21. data/lib/bundler/cli/lock.rb +5 -1
  22. data/lib/bundler/cli/open.rb +1 -2
  23. data/lib/bundler/cli/outdated.rb +22 -14
  24. data/lib/bundler/cli/platform.rb +2 -2
  25. data/lib/bundler/cli/remove.rb +1 -2
  26. data/lib/bundler/cli/show.rb +1 -1
  27. data/lib/bundler/cli/update.rb +17 -8
  28. data/lib/bundler/cli.rb +51 -63
  29. data/lib/bundler/compact_index_client/cache.rb +0 -9
  30. data/lib/bundler/compact_index_client/updater.rb +26 -14
  31. data/lib/bundler/compact_index_client.rb +2 -8
  32. data/lib/bundler/current_ruby.rb +17 -6
  33. data/lib/bundler/definition.rb +260 -362
  34. data/lib/bundler/dependency.rb +23 -71
  35. data/lib/bundler/digest.rb +71 -0
  36. data/lib/bundler/dsl.rb +72 -76
  37. data/lib/bundler/endpoint_specification.rb +19 -13
  38. data/lib/bundler/env.rb +1 -1
  39. data/lib/bundler/environment_preserver.rb +4 -1
  40. data/lib/bundler/errors.rb +29 -3
  41. data/lib/bundler/feature_flag.rb +0 -5
  42. data/lib/bundler/fetcher/base.rb +6 -8
  43. data/lib/bundler/fetcher/compact_index.rb +10 -15
  44. data/lib/bundler/fetcher/downloader.rb +9 -6
  45. data/lib/bundler/fetcher/index.rb +0 -27
  46. data/lib/bundler/fetcher.rb +22 -23
  47. data/lib/bundler/friendly_errors.rb +26 -36
  48. data/lib/bundler/gem_helper.rb +21 -16
  49. data/lib/bundler/gem_helpers.rb +9 -2
  50. data/lib/bundler/gem_version_promoter.rb +14 -25
  51. data/lib/bundler/index.rb +11 -46
  52. data/lib/bundler/injector.rb +18 -4
  53. data/lib/bundler/inline.rb +4 -13
  54. data/lib/bundler/installer/gem_installer.rb +16 -21
  55. data/lib/bundler/installer/parallel_installer.rb +36 -15
  56. data/lib/bundler/installer/standalone.rb +42 -10
  57. data/lib/bundler/installer.rb +25 -41
  58. data/lib/bundler/lazy_specification.rb +52 -30
  59. data/lib/bundler/lockfile_generator.rb +2 -2
  60. data/lib/bundler/lockfile_parser.rb +18 -43
  61. data/lib/bundler/man/bundle-add.1 +21 -5
  62. data/lib/bundler/man/bundle-add.1.ronn +16 -4
  63. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  64. data/lib/bundler/man/bundle-cache.1 +7 -1
  65. data/lib/bundler/man/bundle-cache.1.ronn +7 -0
  66. data/lib/bundler/man/bundle-check.1 +1 -1
  67. data/lib/bundler/man/bundle-clean.1 +2 -2
  68. data/lib/bundler/man/bundle-clean.1.ronn +1 -1
  69. data/lib/bundler/man/bundle-config.1 +49 -22
  70. data/lib/bundler/man/bundle-config.1.ronn +49 -30
  71. data/lib/bundler/man/bundle-console.1 +53 -0
  72. data/lib/bundler/man/bundle-console.1.ronn +44 -0
  73. data/lib/bundler/man/bundle-doctor.1 +1 -1
  74. data/lib/bundler/man/bundle-exec.1 +2 -2
  75. data/lib/bundler/man/bundle-exec.1.ronn +1 -1
  76. data/lib/bundler/man/bundle-gem.1 +14 -1
  77. data/lib/bundler/man/bundle-gem.1.ronn +16 -0
  78. data/lib/bundler/man/bundle-help.1 +13 -0
  79. data/lib/bundler/man/bundle-help.1.ronn +12 -0
  80. data/lib/bundler/man/bundle-info.1 +1 -1
  81. data/lib/bundler/man/bundle-init.1 +1 -1
  82. data/lib/bundler/man/bundle-inject.1 +5 -2
  83. data/lib/bundler/man/bundle-inject.1.ronn +3 -1
  84. data/lib/bundler/man/bundle-install.1 +6 -2
  85. data/lib/bundler/man/bundle-install.1.ronn +8 -2
  86. data/lib/bundler/man/bundle-list.1 +1 -1
  87. data/lib/bundler/man/bundle-lock.1 +1 -1
  88. data/lib/bundler/man/bundle-open.1 +1 -1
  89. data/lib/bundler/man/bundle-outdated.1 +3 -10
  90. data/lib/bundler/man/bundle-outdated.1.ronn +1 -10
  91. data/lib/bundler/man/bundle-platform.1 +16 -6
  92. data/lib/bundler/man/bundle-platform.1.ronn +14 -7
  93. data/lib/bundler/man/bundle-plugin.1 +81 -0
  94. data/lib/bundler/man/bundle-plugin.1.ronn +59 -0
  95. data/lib/bundler/man/bundle-pristine.1 +1 -1
  96. data/lib/bundler/man/bundle-remove.1 +1 -1
  97. data/lib/bundler/man/bundle-show.1 +1 -1
  98. data/lib/bundler/man/bundle-update.1 +5 -5
  99. data/lib/bundler/man/bundle-update.1.ronn +5 -4
  100. data/lib/bundler/man/bundle-version.1 +35 -0
  101. data/lib/bundler/man/bundle-version.1.ronn +24 -0
  102. data/lib/bundler/man/bundle-viz.1 +4 -1
  103. data/lib/bundler/man/bundle-viz.1.ronn +2 -0
  104. data/lib/bundler/man/bundle.1 +15 -10
  105. data/lib/bundler/man/bundle.1.ronn +12 -7
  106. data/lib/bundler/man/gemfile.5 +117 -80
  107. data/lib/bundler/man/gemfile.5.ronn +105 -84
  108. data/lib/bundler/man/index.txt +4 -0
  109. data/lib/bundler/match_metadata.rb +13 -0
  110. data/lib/bundler/match_platform.rb +0 -1
  111. data/lib/bundler/match_remote_metadata.rb +29 -0
  112. data/lib/bundler/plugin/api/source.rb +24 -8
  113. data/lib/bundler/plugin/index.rb +4 -1
  114. data/lib/bundler/plugin/installer/git.rb +0 -4
  115. data/lib/bundler/plugin/installer/rubygems.rb +0 -4
  116. data/lib/bundler/plugin/installer.rb +10 -10
  117. data/lib/bundler/plugin/source_list.rb +4 -0
  118. data/lib/bundler/plugin.rb +30 -8
  119. data/lib/bundler/process_lock.rb +1 -1
  120. data/lib/bundler/remote_specification.rb +10 -4
  121. data/lib/bundler/resolver/base.rb +50 -0
  122. data/lib/bundler/resolver/spec_group.rb +31 -73
  123. data/lib/bundler/resolver.rb +193 -292
  124. data/lib/bundler/retry.rb +1 -1
  125. data/lib/bundler/ruby_dsl.rb +1 -1
  126. data/lib/bundler/ruby_version.rb +5 -18
  127. data/lib/bundler/rubygems_ext.rb +160 -26
  128. data/lib/bundler/rubygems_gem_installer.rb +86 -9
  129. data/lib/bundler/rubygems_integration.rb +46 -93
  130. data/lib/bundler/runtime.rb +18 -12
  131. data/lib/bundler/self_manager.rb +168 -0
  132. data/lib/bundler/settings.rb +98 -22
  133. data/lib/bundler/setup.rb +2 -2
  134. data/lib/bundler/shared_helpers.rb +15 -31
  135. data/lib/bundler/source/git/git_proxy.rb +8 -6
  136. data/lib/bundler/source/git.rb +29 -13
  137. data/lib/bundler/source/metadata.rb +3 -7
  138. data/lib/bundler/source/path/installer.rb +1 -1
  139. data/lib/bundler/source/path.rb +3 -1
  140. data/lib/bundler/source/rubygems.rb +199 -182
  141. data/lib/bundler/source/rubygems_aggregate.rb +68 -0
  142. data/lib/bundler/source.rb +24 -4
  143. data/lib/bundler/source_list.rb +104 -60
  144. data/lib/bundler/source_map.rb +71 -0
  145. data/lib/bundler/spec_set.rb +58 -52
  146. data/lib/bundler/stub_specification.rb +13 -3
  147. data/lib/bundler/templates/Executable +2 -4
  148. data/lib/bundler/templates/Executable.bundler +8 -8
  149. data/lib/bundler/templates/Executable.standalone +2 -4
  150. data/lib/bundler/templates/Gemfile +0 -2
  151. data/lib/bundler/templates/gems.rb +0 -3
  152. data/lib/bundler/templates/newgem/Gemfile.tt +5 -2
  153. data/lib/bundler/templates/newgem/README.md.tt +8 -12
  154. data/lib/bundler/templates/newgem/Rakefile.tt +15 -2
  155. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +16 -7
  156. data/lib/bundler/templates/newgem/gitlab-ci.yml.tt +5 -4
  157. data/lib/bundler/templates/newgem/newgem.gemspec.tt +19 -17
  158. data/lib/bundler/templates/newgem/sig/newgem.rbs.tt +8 -0
  159. data/lib/bundler/templates/newgem/standard.yml.tt +3 -0
  160. data/lib/bundler/templates/newgem/test/minitest/{newgem_test.rb.tt → test_newgem.rb.tt} +1 -1
  161. data/lib/bundler/ui/shell.rb +1 -1
  162. data/lib/bundler/vendor/.document +1 -0
  163. data/lib/bundler/vendor/connection_pool/LICENSE +20 -0
  164. data/lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb +19 -21
  165. data/lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb +1 -1
  166. data/lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb +57 -0
  167. data/lib/bundler/vendor/connection_pool/lib/connection_pool.rb +39 -74
  168. data/lib/bundler/vendor/fileutils/LICENSE.txt +22 -0
  169. data/lib/bundler/vendor/molinillo/LICENSE +9 -0
  170. data/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +3 -3
  171. data/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +32 -26
  172. data/lib/bundler/vendor/molinillo/lib/molinillo/gem_metadata.rb +1 -1
  173. data/lib/bundler/vendor/molinillo/lib/molinillo/modules/specification_provider.rb +1 -1
  174. data/lib/bundler/vendor/net-http-persistent/README.rdoc +82 -0
  175. data/lib/bundler/vendor/thor/LICENSE.md +20 -0
  176. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +5 -5
  177. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +1 -2
  178. data/lib/bundler/vendor/thor/lib/thor/actions.rb +6 -2
  179. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +6 -0
  180. data/lib/bundler/vendor/thor/lib/thor/error.rb +9 -4
  181. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +19 -1
  182. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +22 -4
  183. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  184. data/lib/bundler/vendor/thor/lib/thor/util.rb +1 -1
  185. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  186. data/lib/bundler/vendor/tmpdir/lib/tmpdir.rb +1 -1
  187. data/lib/bundler/vendor/tsort/LICENSE.txt +22 -0
  188. data/lib/bundler/vendor/tsort/lib/tsort.rb +452 -0
  189. data/lib/bundler/vendor/uri/LICENSE.txt +22 -0
  190. data/lib/bundler/vendor/uri/lib/uri/common.rb +17 -80
  191. data/lib/bundler/vendor/uri/lib/uri/ftp.rb +0 -1
  192. data/lib/bundler/vendor/uri/lib/uri/generic.rb +5 -6
  193. data/lib/bundler/vendor/uri/lib/uri/http.rb +0 -1
  194. data/lib/bundler/vendor/uri/lib/uri/https.rb +0 -1
  195. data/lib/bundler/vendor/uri/lib/uri/ldap.rb +1 -1
  196. data/lib/bundler/vendor/uri/lib/uri/mailto.rb +0 -1
  197. data/lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb +1 -14
  198. data/lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb +1 -12
  199. data/lib/bundler/vendor/uri/lib/uri/version.rb +1 -1
  200. data/lib/bundler/vendor/uri/lib/uri/ws.rb +84 -0
  201. data/lib/bundler/vendor/uri/lib/uri/wss.rb +22 -0
  202. data/lib/bundler/vendor/uri/lib/uri.rb +0 -1
  203. data/lib/bundler/vendored_tsort.rb +4 -0
  204. data/lib/bundler/version.rb +1 -1
  205. data/lib/bundler/worker.rb +19 -4
  206. data/lib/bundler.rb +46 -39
  207. metadata +39 -12
  208. data/lib/bundler/dep_proxy.rb +0 -55
  209. data/lib/bundler/gemdeps.rb +0 -29
  210. data/lib/bundler/psyched_yaml.rb +0 -22
  211. data/lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb +0 -66
@@ -3,64 +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, index, 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(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
23
- result = resolver.start(requirements)
24
- SpecSet.new(result)
25
- end
26
-
27
- def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
28
- @index = index
11
+ def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
29
12
  @source_requirements = source_requirements
30
- @base = base
13
+ @base = Resolver::Base.new(base, additional_base_requirements)
31
14
  @resolver = Molinillo::Resolver.new(self, self)
15
+ @results_for = {}
32
16
  @search_for = {}
33
- @base_dg = Molinillo::DependencyGraph.new
34
- @base.each do |ls|
35
- dep = Dependency.new(ls.name, ls.version)
36
- @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
37
- end
38
- additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
39
- @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } }
17
+ @platforms = platforms
40
18
  @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY]
41
19
  @gem_version_promoter = gem_version_promoter
42
- @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major?
43
- @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource?
44
-
45
- @variant_specific_names = []
46
- @generic_names = ["Ruby\0", "RubyGems\0"]
47
20
  end
48
21
 
49
- def start(requirements)
50
- @gem_version_promoter.prerelease_specified = @prerelease_specified = {}
51
- 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? }
52
30
 
53
31
  verify_gemfile_dependencies_are_found!(requirements)
54
- dg = @resolver.resolve(requirements, @base_dg)
55
- dg.
56
- tap {|resolved| validate_resolved_specs!(resolved) }.
32
+ result = @resolver.resolve(requirements).
57
33
  map(&:payload).
58
34
  reject {|sg| sg.name.end_with?("\0") }.
59
35
  map(&:to_specs).
60
36
  flatten
37
+
38
+ SpecSet.new(SpecSet.new(result).for(regular_requirements, false, @platforms))
61
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
+
62
52
  message = version_conflict_message(e)
63
- raise VersionConflict.new(e.conflicts.keys.uniq, message)
53
+ raise VersionConflict.new(conflicts.keys.uniq, message)
64
54
  rescue Molinillo::CircularDependencyError => e
65
55
  names = e.dependencies.sort_by(&:name).map {|d| "gem '#{d.name}'" }
66
56
  raise CyclicDependencyError, "Your bundle requires gems that depend" \
@@ -107,109 +97,52 @@ module Bundler
107
97
  include Molinillo::SpecificationProvider
108
98
 
109
99
  def dependencies_for(specification)
110
- all_dependencies = specification.dependencies_for_activated_platforms
111
-
112
- if @variant_specific_names.include?(specification.name)
113
- @variant_specific_names |= all_dependencies.map(&:name) - @generic_names
114
- else
115
- generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms
116
- @variant_specific_names |= variant_specific_names - @generic_names
117
- @generic_names |= generic_names
118
- end
119
-
120
- all_dependencies
100
+ specification.dependencies_for_activated_platforms
121
101
  end
122
102
 
123
- def search_for(dependency_proxy)
124
- platform = dependency_proxy.__platform
125
- dependency = dependency_proxy.dep
126
- name = dependency.name
127
- search_result = @search_for[dependency_proxy] ||= begin
128
- index = index_for(dependency)
129
- results = index.search(dependency, @base[name])
130
-
131
- if vertex = @base_dg.vertex_named(name)
132
- locked_requirement = vertex.payload.requirement
133
- end
134
-
135
- if !@prerelease_specified[name] && (!@use_gvp || locked_requirement.nil?)
136
- # Move prereleases to the beginning of the list, so they're considered
137
- # last during resolution.
138
- pre, results = results.partition {|spec| spec.version.prerelease? }
139
- results = pre + results
140
- end
141
-
142
- spec_groups = if results.any?
143
- nested = []
144
- results.each do |spec|
145
- version, specs = nested.last
146
- if version == spec.version
147
- specs << spec
148
- else
149
- nested << [spec.version, [spec]]
150
- 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
151
121
  end
152
- nested.reduce([]) do |groups, (version, specs)|
153
- next groups if locked_requirement && !locked_requirement.satisfied_by?(version)
154
-
155
- specs_by_platform = Hash.new do |current_specs, current_platform|
156
- current_specs[current_platform] = select_best_platform_match(specs, current_platform)
157
- end
158
122
 
159
- spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY)
160
- groups << spec_group_ruby if spec_group_ruby
123
+ next groups if @resolving_only_for_ruby || dependency.force_ruby_platform
161
124
 
162
- 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
163
127
 
164
- spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform)
165
- groups << spec_group if spec_group
128
+ spec_group = SpecGroup.new(platform_specs, relevant_platforms)
129
+ groups << spec_group
166
130
 
167
- groups
168
- end
169
- else
170
- []
171
- end
172
- # GVP handles major itself, but it's still a bit risky to trust it with it
173
- # until we get it settled with new behavior. For 2.x it can take over all cases.
174
- if !@use_gvp
175
- spec_groups
176
- else
177
- @gem_version_promoter.sort_versions(dependency, spec_groups)
131
+ groups
178
132
  end
179
133
  end
134
+ end
180
135
 
181
- unless search_result.empty?
182
- specific_dependency = @variant_specific_names.include?(name)
183
- return search_result unless specific_dependency
184
-
185
- search_result.each do |sg|
186
- if @generic_names.include?(name)
187
- @variant_specific_names -= [name]
188
- sg.activate_all_platforms!
189
- else
190
- sg.activate_platform!(platform)
191
- end
192
- end
193
- end
136
+ def index_for(dependency)
137
+ source_for(dependency.name).specs
138
+ end
194
139
 
195
- search_result
140
+ def source_for(name)
141
+ @source_requirements[name] || @source_requirements[:default]
196
142
  end
197
143
 
198
- def index_for(dependency)
199
- source = @source_requirements[dependency.name]
200
- if source
201
- source.specs
202
- elsif @lockfile_uses_separate_rubygems_sources
203
- Index.build do |idx|
204
- if dependency.all_sources
205
- dependency.all_sources.each {|s| idx.add_source(s.specs) if s }
206
- else
207
- idx.add_source @source_requirements[:default].specs
208
- end
209
- end
210
- else
211
- @index
212
- end
144
+ def results_for(dependency)
145
+ @results_for[dependency] ||= index_for(dependency).search(dependency)
213
146
  end
214
147
 
215
148
  def name_for(dependency)
@@ -222,54 +155,51 @@ module Bundler
222
155
  "Gemfile"
223
156
  end
224
157
 
225
- def name_for_locking_dependency_source
226
- Bundler.default_lockfile.basename.to_s
227
- rescue StandardError
228
- "Gemfile.lock"
229
- end
230
-
231
158
  def requirement_satisfied_by?(requirement, activated, spec)
232
159
  requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
233
160
  end
234
161
 
235
- def dependencies_equal?(dependencies, other_dependencies)
236
- dependencies.map(&:dep) == other_dependencies.map(&:dep)
237
- end
238
-
239
- def relevant_sources_for_vertex(vertex)
240
- if vertex.root?
241
- [@source_requirements[vertex.name]]
242
- elsif @lockfile_uses_separate_rubygems_sources
243
- vertex.recursive_predecessors.map do |v|
244
- @source_requirements[v.name]
245
- end << @source_requirements[:default]
246
- end
247
- end
248
-
249
162
  def sort_dependencies(dependencies, activated, conflicts)
250
163
  dependencies.sort_by do |dependency|
251
- dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name))
252
164
  name = name_for(dependency)
253
165
  vertex = activated.vertex_named(name)
254
166
  [
255
- @base_dg.vertex_named(name) ? 0 : 1,
167
+ @base[name].any? ? 0 : 1,
256
168
  vertex.payload ? 0 : 1,
257
169
  vertex.root? ? 0 : 1,
258
170
  amount_constrained(dependency),
259
171
  conflicts[name] ? 0 : 1,
260
172
  vertex.payload ? 0 : search_for(dependency).count,
261
- self.class.platform_sort_key(dependency.__platform),
262
173
  ]
263
174
  end
264
175
  end
265
176
 
266
- def self.platform_sort_key(platform)
267
- # Prefer specific platform to not specific platform
268
- return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform
269
- ["00", *platform.to_a.map {|part| part || "" }]
177
+ private
178
+
179
+ def base_requirements
180
+ @base.base_requirements
181
+ end
182
+
183
+ def prerelease_specified
184
+ @gem_version_promoter.prerelease_specified
270
185
  end
271
186
 
272
- private
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
273
203
 
274
204
  # returns an integer \in (-\infty, 0]
275
205
  # a number closer to 0 means the dependency is less constraining
@@ -279,69 +209,60 @@ module Bundler
279
209
  # before dependencies that are unconstrained
280
210
  def amount_constrained(dependency)
281
211
  @amount_constrained ||= {}
282
- @amount_constrained[dependency.name] ||= begin
283
- if (base = @base[dependency.name]) && !base.empty?
284
- dependency.requirement.satisfied_by?(base.first.version) ? 0 : 1
285
- else
286
- 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
287
216
 
288
- if all <= 1
289
- all - 1_000_000
290
- else
291
- search = search_for(dependency)
292
- search = @prerelease_specified[dependency.name] ? search.count : search.count {|s| !s.version.prerelease? }
293
- search - all
294
- 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
295
223
  end
296
224
  end
297
225
  end
298
226
 
299
227
  def verify_gemfile_dependencies_are_found!(requirements)
300
- requirements.each do |requirement|
228
+ requirements.map! do |requirement|
301
229
  name = requirement.name
302
- next if name == "bundler"
303
- next unless search_for(requirement).empty?
304
-
305
- cache_message = begin
306
- " or in gems cached in #{Bundler.settings.app_cache_path}" if Bundler.app_cache.exist?
307
- rescue GemfileNotFound
308
- nil
309
- end
310
-
311
- if (base = @base[name]) && !base.empty?
312
- version = base.first.version
313
- message = "You have requested:\n" \
314
- " #{name} #{requirement.requirement}\n\n" \
315
- "The bundle currently has #{name} locked at #{version}.\n" \
316
- "Try running `bundle update #{name}`\n\n" \
317
- "If you are updating multiple gems in your Gemfile at once,\n" \
318
- "try passing them all to `bundle update`"
319
- elsif source = @source_requirements[name]
320
- specs = source.specs[name]
321
- versions_with_platforms = specs.map {|s| [s.version, s.platform] }
322
- message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n")
323
- message << if versions_with_platforms.any?
324
- "The source contains the following versions of '#{name}': #{formatted_versions_with_platforms(versions_with_platforms)}"
325
- else
326
- "The source does not contain any versions of '#{name}'"
327
- end
328
- else
329
- message = "Could not find gem '#{requirement}' in any of the gem sources " \
330
- "listed in your Gemfile#{cache_message}."
331
- end
332
- raise GemNotFound, message
333
- 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!
334
237
  end
335
238
 
336
- def formatted_versions_with_platforms(versions_with_platforms)
337
- version_platform_strs = versions_with_platforms.map do |vwp|
338
- version = vwp.first
339
- platform = vwp.last
340
- version_platform_str = String.new(version.to_s)
341
- version_platform_str << " #{platform}" unless platform.nil? || platform == Gem::Platform::RUBY
342
- 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")
343
263
  end
344
- version_platform_strs.join(", ")
264
+
265
+ message
345
266
  end
346
267
 
347
268
  def version_conflict_message(e)
@@ -359,29 +280,62 @@ module Bundler
359
280
 
360
281
  e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty?
361
282
 
362
- solver_name = "Bundler"
363
- possibility_type = "gem"
364
283
  e.message_with_trees(
365
- :solver_name => solver_name,
366
- :possibility_type => possibility_type,
367
- :reduce_trees => lambda do |trees|
284
+ :full_message_for_conflict => lambda do |name, conflict|
285
+ trees = conflict.requirement_trees
286
+
368
287
  # called first, because we want to reduce the amount of work required to find maximal empty sets
369
288
  trees = trees.uniq {|t| t.flatten.map {|dep| [dep.name, dep.requirement] } }
370
289
 
371
290
  # bail out if tree size is too big for Array#combination to make any sense
372
- return trees if trees.size > 15
373
- maximal = 1.upto(trees.size).map do |size|
374
- trees.map(&:last).flatten(1).combination(size).to_a
375
- end.flatten(1).select do |deps|
376
- Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
377
- end.min_by(&:size)
378
-
379
- trees.reject! {|t| !maximal.include?(t.last) } if maximal
380
-
381
- trees.sort_by {|t| t.reverse.map(&:name) }
382
- end,
383
- :printable_requirement => lambda {|req| SharedHelpers.pretty_dependency(req) },
384
- :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
+
385
339
  if name == "bundler"
386
340
  o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
387
341
 
@@ -392,7 +346,7 @@ module Bundler
392
346
  if other_bundler_required
393
347
  o << "\n\n"
394
348
 
395
- candidate_specs = @source_requirements[:default_bundler].specs.search(conflict_dependency)
349
+ candidate_specs = source_for(:default_bundler).specs.search(conflict_dependency)
396
350
  if candidate_specs.any?
397
351
  target_version = candidate_specs.last.version
398
352
  new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ")
@@ -402,78 +356,25 @@ module Bundler
402
356
  o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n"
403
357
  end
404
358
  end
405
- elsif conflict.locked_requirement
406
- o << "\n"
407
- o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
408
- 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)
409
361
  elsif !conflict.existing
410
362
  o << "\n"
411
363
 
412
- relevant_sources = if conflict.requirement.source
413
- [conflict.requirement.source]
414
- elsif conflict.requirement.all_sources
415
- conflict.requirement.all_sources
416
- elsif @lockfile_uses_separate_rubygems_sources
417
- # every conflict should have an explicit group of sources when we
418
- # enforce strict pinning
419
- raise "no source set for #{conflict}"
420
- else
421
- []
422
- end.compact.map(&:to_s).uniq.sort
423
-
424
- metadata_requirement = name.end_with?("\0")
425
-
426
- o << "Could not find gem '" unless metadata_requirement
427
- o << SharedHelpers.pretty_dependency(conflict.requirement)
428
- o << "'" unless metadata_requirement
429
- if conflict.requirement_trees.first.size > 1
430
- o << ", which is required by "
431
- o << "gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}',"
432
- end
433
- o << " "
364
+ relevant_source = conflict.requirement.source || source_for(name)
434
365
 
435
- o << if relevant_sources.empty?
436
- "in any of the sources.\n"
437
- elsif metadata_requirement
438
- "is not available in #{relevant_sources.join(" or ")}"
366
+ extra_message = if trees.first.size > 1
367
+ ", which is required by gem '#{SharedHelpers.pretty_dependency(trees.first[-2])}',"
439
368
  else
440
- "in any of the relevant sources:\n #{relevant_sources * "\n "}\n"
369
+ ""
441
370
  end
371
+
372
+ o << gem_not_found_message(name, conflict.requirement, relevant_source, extra_message)
442
373
  end
443
- end,
444
- :version_for_spec => lambda {|spec| spec.version },
445
- :incompatible_version_message_for_conflict => lambda do |name, _conflict|
446
- if name.end_with?("\0")
447
- %(#{solver_name} found conflicting requirements for the #{name} version:)
448
- else
449
- %(#{solver_name} could not find compatible versions for #{possibility_type} "#{name}":)
450
- end
451
- end
452
- )
453
- end
454
374
 
455
- def validate_resolved_specs!(resolved_specs)
456
- resolved_specs.each do |v|
457
- name = v.name
458
- next unless sources = relevant_sources_for_vertex(v)
459
- sources.compact!
460
- if default_index = sources.index(@source_requirements[:default])
461
- sources.delete_at(default_index)
375
+ o
462
376
  end
463
- sources.reject! {|s| s.specs[name].empty? }
464
- sources.uniq!
465
- next if sources.size <= 1
466
-
467
- multisource_disabled = Bundler.feature_flag.disable_multisource?
468
-
469
- msg = ["The gem '#{name}' was found in multiple relevant sources."]
470
- msg.concat sources.map {|s| " * #{s}" }.sort
471
- msg << "You #{multisource_disabled ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
472
- msg = msg.join("\n")
473
-
474
- raise SecurityError, msg if multisource_disabled
475
- Bundler.ui.warn "Warning: #{msg}"
476
- end
377
+ )
477
378
  end
478
379
  end
479
380
  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
 
@@ -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])