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
@@ -6,6 +6,11 @@ module Bundler
6
6
  class Definition
7
7
  include GemHelpers
8
8
 
9
+ class << self
10
+ # Do not create or modify a lockfile (Makes #lock a noop)
11
+ attr_accessor :no_lock
12
+ end
13
+
9
14
  attr_reader(
10
15
  :dependencies,
11
16
  :locked_deps,
@@ -65,6 +70,7 @@ module Bundler
65
70
  @unlock = unlock
66
71
  @optional_groups = optional_groups
67
72
  @remote = false
73
+ @prefer_local = false
68
74
  @specs = nil
69
75
  @ruby_version = ruby_version
70
76
  @gemfiles = gemfiles
@@ -73,7 +79,6 @@ module Bundler
73
79
  @lockfile_contents = String.new
74
80
  @locked_bundler_version = nil
75
81
  @locked_ruby_version = nil
76
- @locked_specs_incomplete_for_platform = false
77
82
  @new_platform = nil
78
83
 
79
84
  if lockfile && File.exist?(lockfile)
@@ -83,10 +88,11 @@ module Bundler
83
88
  @platforms = @locked_platforms.dup
84
89
  @locked_bundler_version = @locked_gems.bundler_version
85
90
  @locked_ruby_version = @locked_gems.ruby_version
91
+ @originally_locked_specs = SpecSet.new(@locked_gems.specs)
86
92
 
87
93
  if unlock != true
88
94
  @locked_deps = @locked_gems.dependencies
89
- @locked_specs = SpecSet.new(@locked_gems.specs)
95
+ @locked_specs = @originally_locked_specs
90
96
  @locked_sources = @locked_gems.sources
91
97
  else
92
98
  @unlock = {}
@@ -100,6 +106,7 @@ module Bundler
100
106
  @locked_gems = nil
101
107
  @locked_deps = {}
102
108
  @locked_specs = SpecSet.new([])
109
+ @originally_locked_specs = @locked_specs
103
110
  @locked_sources = []
104
111
  @locked_platforms = []
105
112
  end
@@ -132,8 +139,8 @@ module Bundler
132
139
  if @unlock[:conservative]
133
140
  @unlock[:gems] ||= @dependencies.map(&:name)
134
141
  else
135
- eager_unlock = expand_dependencies(@unlock[:gems] || [], true)
136
- @unlock[:gems] = @locked_specs.for(eager_unlock, false, false).map(&:name)
142
+ eager_unlock = (@unlock[:gems] || []).map {|name| Dependency.new(name, ">= 0") }
143
+ @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name).uniq
137
144
  end
138
145
 
139
146
  @dependency_changes = converge_dependencies
@@ -143,22 +150,20 @@ module Bundler
143
150
  end
144
151
 
145
152
  def gem_version_promoter
146
- @gem_version_promoter ||= begin
147
- locked_specs =
148
- if unlocking? && @locked_specs.empty? && !@lockfile_contents.empty?
149
- # Definition uses an empty set of locked_specs to indicate all gems
150
- # are unlocked, but GemVersionPromoter needs the locked_specs
151
- # for conservative comparison.
152
- Bundler::SpecSet.new(@locked_gems.specs)
153
- else
154
- @locked_specs
155
- end
156
- GemVersionPromoter.new(locked_specs, @unlock[:gems])
157
- end
153
+ @gem_version_promoter ||= GemVersionPromoter.new(@originally_locked_specs, @unlock[:gems])
154
+ end
155
+
156
+ def resolve_only_locally!
157
+ @remote = false
158
+ sources.local_only!
159
+ resolve
158
160
  end
159
161
 
160
- def multisource_allowed?
161
- @multisource_allowed
162
+ def resolve_prefering_local!
163
+ @prefer_local = true
164
+ @remote = true
165
+ sources.remote!
166
+ resolve
162
167
  end
163
168
 
164
169
  def resolve_with_cache!
@@ -201,6 +206,7 @@ module Bundler
201
206
  true
202
207
  rescue BundlerError => e
203
208
  @resolve = nil
209
+ @resolver = nil
204
210
  @specs = nil
205
211
  @gem_version_promoter = nil
206
212
 
@@ -218,14 +224,26 @@ module Bundler
218
224
 
219
225
  def current_dependencies
220
226
  dependencies.select do |d|
221
- d.should_include? && !d.gem_platforms(@platforms).empty?
227
+ d.should_include? && !d.gem_platforms([generic_local_platform]).empty?
222
228
  end
223
229
  end
224
230
 
231
+ def locked_dependencies
232
+ @locked_deps.values
233
+ end
234
+
235
+ def new_deps
236
+ @new_deps ||= @dependencies - locked_dependencies
237
+ end
238
+
239
+ def deleted_deps
240
+ @deleted_deps ||= locked_dependencies - @dependencies
241
+ end
242
+
225
243
  def specs_for(groups)
226
- groups = requested_groups if groups.empty?
244
+ return specs if groups.empty?
227
245
  deps = dependencies_for(groups)
228
- materialize(expand_dependencies(deps))
246
+ materialize(deps)
229
247
  end
230
248
 
231
249
  def dependencies_for(groups)
@@ -241,20 +259,24 @@ module Bundler
241
259
  #
242
260
  # @return [SpecSet] resolved dependencies
243
261
  def resolve
244
- @resolve ||= begin
245
- last_resolve = converge_locked_specs
246
- if Bundler.frozen_bundle?
247
- Bundler.ui.debug "Frozen, using resolution from the lockfile"
248
- last_resolve
249
- elsif !unlocking? && nothing_changed?
250
- Bundler.ui.debug("Found no changes, using resolution from the lockfile")
251
- last_resolve
262
+ @resolve ||= if Bundler.frozen_bundle?
263
+ Bundler.ui.debug "Frozen, using resolution from the lockfile"
264
+ @locked_specs
265
+ elsif !unlocking? && nothing_changed?
266
+ if deleted_deps.any?
267
+ Bundler.ui.debug("Some dependencies were deleted, using a subset of the resolution from the lockfile")
268
+ SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps))
252
269
  else
253
- # Run a resolve against the locally available gems
254
- Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
255
- expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote)
256
- Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
270
+ Bundler.ui.debug("Found no changes, using resolution from the lockfile")
271
+ if @locked_gems.may_include_redundant_platform_specific_gems?
272
+ SpecSet.new(filter_specs(@locked_specs, @dependencies))
273
+ else
274
+ @locked_specs
275
+ end
257
276
  end
277
+ else
278
+ Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
279
+ resolver.start(expanded_dependencies)
258
280
  end
259
281
  end
260
282
 
@@ -267,6 +289,8 @@ module Bundler
267
289
  end
268
290
 
269
291
  def lock(file, preserve_unknown_sections = false)
292
+ return if Definition.no_lock
293
+
270
294
  contents = to_lock
271
295
 
272
296
  # Convert to \r\n if the existing lock has them
@@ -277,10 +301,7 @@ module Bundler
277
301
  locked_major = @locked_bundler_version.segments.first
278
302
  current_major = Gem::Version.create(Bundler::VERSION).segments.first
279
303
 
280
- if updating_major = locked_major < current_major
281
- Bundler.ui.warn "Warning: the lockfile is being updated to Bundler #{current_major}, " \
282
- "after which you will be unable to return to Bundler #{@locked_bundler_version.segments.first}."
283
- end
304
+ updating_major = locked_major < current_major
284
305
  end
285
306
 
286
307
  preserve_unknown_sections ||= !updating_major && (Bundler.frozen_bundle? || !(unlocking? || @unlocking_bundler))
@@ -297,14 +318,6 @@ module Bundler
297
318
  end
298
319
  end
299
320
 
300
- def locked_bundler_version
301
- if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION)
302
- new_version = Bundler::VERSION
303
- end
304
-
305
- new_version || @locked_bundler_version || Bundler::VERSION
306
- end
307
-
308
321
  def locked_ruby_version
309
322
  return unless ruby_version
310
323
  if @unlock[:ruby] || !@locked_ruby_version
@@ -344,7 +357,7 @@ module Bundler
344
357
  "bundle config unset deployment"
345
358
  end
346
359
  msg << "\n\nIf this is a development machine, remove the #{Bundler.default_gemfile} " \
347
- "freeze \nby running `#{suggested_command}`."
360
+ "freeze \nby running `#{suggested_command}`." if suggested_command
348
361
  end
349
362
 
350
363
  added = []
@@ -356,44 +369,28 @@ module Bundler
356
369
  added.concat new_platforms.map {|p| "* platform: #{p}" }
357
370
  deleted.concat deleted_platforms.map {|p| "* platform: #{p}" }
358
371
 
359
- gemfile_sources = sources.lock_sources
360
-
361
- new_sources = gemfile_sources - @locked_sources
362
- deleted_sources = @locked_sources - gemfile_sources
363
-
364
- new_deps = @dependencies - @locked_deps.values
365
- deleted_deps = @locked_deps.values - @dependencies
372
+ added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
373
+ deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" } if deleted_deps.any?
366
374
 
367
- # Check if it is possible that the source is only changed thing
368
- if (new_deps.empty? && deleted_deps.empty?) && (!new_sources.empty? && !deleted_sources.empty?)
369
- new_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
370
- deleted_sources.reject! {|source| (source.path? && source.path.exist?) || equivalent_rubygems_remotes?(source) }
371
- end
375
+ both_sources = Hash.new {|h, k| h[k] = [] }
376
+ @dependencies.each {|d| both_sources[d.name][0] = d }
372
377
 
373
- if @locked_sources != gemfile_sources
374
- if new_sources.any?
375
- added.concat new_sources.map {|source| "* source: #{source}" }
376
- end
378
+ locked_dependencies.each do |d|
379
+ next if !Bundler.feature_flag.bundler_3_mode? && @locked_specs[d.name].empty?
377
380
 
378
- if deleted_sources.any?
379
- deleted.concat deleted_sources.map {|source| "* source: #{source}" }
380
- end
381
+ both_sources[d.name][1] = d
381
382
  end
382
383
 
383
- added.concat new_deps.map {|d| "* #{pretty_dep(d)}" } if new_deps.any?
384
- if deleted_deps.any?
385
- deleted.concat deleted_deps.map {|d| "* #{pretty_dep(d)}" }
386
- end
384
+ both_sources.each do |name, (dep, lock_dep)|
385
+ next if dep.nil? || lock_dep.nil?
387
386
 
388
- both_sources = Hash.new {|h, k| h[k] = [] }
389
- @dependencies.each {|d| both_sources[d.name][0] = d }
390
- @locked_deps.each {|name, d| both_sources[name][1] = d.source }
387
+ gemfile_source = dep.source || sources.default_source
388
+ lock_source = lock_dep.source || sources.default_source
389
+ next if lock_source.include?(gemfile_source)
391
390
 
392
- both_sources.each do |name, (dep, lock_source)|
393
- next if lock_source.nil? || (dep && lock_source.can_lock?(dep))
394
- gemfile_source_name = (dep && dep.source) || "no specified source"
395
- lockfile_source_name = lock_source
396
- changed << "* #{name} from `#{gemfile_source_name}` to `#{lockfile_source_name}`"
391
+ gemfile_source_name = dep.source ? gemfile_source.identifier : "no specified source"
392
+ lockfile_source_name = lock_dep.source ? lock_source.identifier : "no specified source"
393
+ changed << "* #{name} from `#{lockfile_source_name}` to `#{gemfile_source_name}`"
397
394
  end
398
395
 
399
396
  reason = change_reason
@@ -441,7 +438,7 @@ module Bundler
441
438
 
442
439
  raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
443
440
  "but your local platform is #{Bundler.local_platform}. " \
444
- "Add the current platform to the lockfile with `bundle lock --add-platform #{Bundler.local_platform}` and try again."
441
+ "Add the current platform to the lockfile with\n`bundle lock --add-platform #{Bundler.local_platform}` and try again."
445
442
  end
446
443
 
447
444
  def add_platform(platform)
@@ -464,7 +461,7 @@ module Bundler
464
461
  private :sources
465
462
 
466
463
  def nothing_changed?
467
- !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform
464
+ !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes
468
465
  end
469
466
 
470
467
  def unlocking?
@@ -473,6 +470,22 @@ module Bundler
473
470
 
474
471
  private
475
472
 
473
+ def resolver
474
+ @resolver ||= begin
475
+ last_resolve = converge_locked_specs
476
+ remove_ruby_from_platforms_if_necessary!(current_dependencies)
477
+ Resolver.new(source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve(last_resolve), platforms)
478
+ end
479
+ end
480
+
481
+ def expanded_dependencies
482
+ @expanded_dependencies ||= dependencies + metadata_dependencies
483
+ end
484
+
485
+ def filter_specs(specs, deps)
486
+ SpecSet.new(specs).for(deps, false, platforms)
487
+ end
488
+
476
489
  def materialize(dependencies)
477
490
  specs = resolve.materialize(dependencies)
478
491
  missing_specs = specs.missing_specs
@@ -487,14 +500,25 @@ module Bundler
487
500
  "removed in order to install."
488
501
  end
489
502
 
490
- raise GemNotFound, "Could not find #{missing_specs.map(&:full_name).join(", ")} in any of the sources"
503
+ missing_specs_list = missing_specs.group_by(&:source).map do |source, missing_specs_for_source|
504
+ "#{missing_specs_for_source.map(&:full_name).join(", ")} in #{source}"
505
+ end
506
+
507
+ raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}"
491
508
  end
492
509
 
493
- unless specs["bundler"].any?
494
- bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
495
- specs["bundler"] = bundler
510
+ loop do
511
+ incomplete_specs = specs.incomplete_specs
512
+ break if incomplete_specs.empty?
513
+
514
+ Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies")
515
+ @resolve = resolver.start(expanded_dependencies, :exclude_specs => incomplete_specs)
516
+ specs = resolve.materialize(dependencies)
496
517
  end
497
518
 
519
+ bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last
520
+ specs["bundler"] = bundler
521
+
498
522
  specs
499
523
  end
500
524
 
@@ -502,8 +526,22 @@ module Bundler
502
526
  @remote && sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
503
527
  end
504
528
 
529
+ def pin_locally_available_names(source_requirements)
530
+ source_requirements.each_with_object({}) do |(name, original_source), new_source_requirements|
531
+ local_source = original_source.dup
532
+ local_source.local_only!
533
+
534
+ new_source_requirements[name] = if local_source.specs.search(name).any?
535
+ local_source
536
+ else
537
+ original_source
538
+ end
539
+ end
540
+ end
541
+
505
542
  def current_ruby_platform_locked?
506
543
  return false unless generic_local_platform == Gem::Platform::RUBY
544
+ return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY)
507
545
 
508
546
  current_platform_locked?
509
547
  end
@@ -536,12 +574,11 @@ module Bundler
536
574
  [@new_platform, "you added a new platform to your gemfile"],
537
575
  [@path_changes, "the gemspecs for path gems changed"],
538
576
  [@local_changes, "the gemspecs for git local gems changed"],
539
- [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"],
540
577
  ].select(&:first).map(&:last).join(", ")
541
578
  end
542
579
 
543
- def pretty_dep(dep, source = false)
544
- SharedHelpers.pretty_dependency(dep, source)
580
+ def pretty_dep(dep)
581
+ SharedHelpers.pretty_dependency(dep)
545
582
  end
546
583
 
547
584
  # Check if the specs of the given source changed
@@ -554,7 +591,7 @@ module Bundler
554
591
 
555
592
  def dependencies_for_source_changed?(source, locked_source = source)
556
593
  deps_for_source = @dependencies.select {|s| s.source == source }
557
- locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }
594
+ locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source }
558
595
 
559
596
  deps_for_source.uniq.sort != locked_deps_for_source.sort
560
597
  end
@@ -637,25 +674,14 @@ module Bundler
637
674
  end
638
675
 
639
676
  def converge_dependencies
640
- frozen = Bundler.frozen_bundle?
641
- (@dependencies + @locked_deps.values).each do |dep|
642
- locked_source = @locked_deps[dep.name]
643
- # This is to make sure that if bundler is installing in deployment mode and
644
- # after locked_source and sources don't match, we still use locked_source.
645
- if frozen && !locked_source.nil? &&
646
- locked_source.respond_to?(:source) && locked_source.source.instance_of?(Source::Path) && locked_source.source.path.exist?
647
- dep.source = locked_source.source
648
- elsif dep.source
677
+ changes = false
678
+
679
+ @dependencies.each do |dep|
680
+ if dep.source
649
681
  dep.source = sources.get(dep.source)
650
682
  end
651
- end
652
683
 
653
- changes = false
654
- # We want to know if all match, but don't want to check all entries
655
- # This means we need to return false if any dependency doesn't match
656
- # the lock or doesn't exist in the lock.
657
- @dependencies.each do |dependency|
658
- unless locked_dep = @locked_deps[dependency.name]
684
+ unless locked_dep = @locked_deps[dep.name]
659
685
  changes = true
660
686
  next
661
687
  end
@@ -666,11 +692,11 @@ module Bundler
666
692
  # directive, the lockfile dependencies and resolved dependencies end up
667
693
  # with a mismatch on #type. Work around that by setting the type on the
668
694
  # dep from the lockfile.
669
- locked_dep.instance_variable_set(:@type, dependency.type)
695
+ locked_dep.instance_variable_set(:@type, dep.type)
670
696
 
671
697
  # We already know the name matches from the hash lookup
672
698
  # so we only need to check the requirement now
673
- changes ||= dependency.requirement != locked_dep.requirement
699
+ changes ||= dep.requirement != locked_dep.requirement
674
700
  end
675
701
 
676
702
  changes
@@ -680,43 +706,50 @@ module Bundler
680
706
  # commonly happen if the Gemfile has changed since the lockfile was last
681
707
  # generated
682
708
  def converge_locked_specs
683
- deps = []
709
+ converged = converge_specs(@locked_specs)
684
710
 
685
- # Build a list of dependencies that are the same in the Gemfile
686
- # and Gemfile.lock. If the Gemfile modified a dependency, but
687
- # the gem in the Gemfile.lock still satisfies it, this is fine
688
- # too.
689
- @dependencies.each do |dep|
690
- locked_dep = @locked_deps[dep.name]
711
+ resolve = SpecSet.new(converged.reject {|s| @unlock[:gems].include?(s.name) })
691
712
 
692
- # If the locked_dep doesn't match the dependency we're looking for then we ignore the locked_dep
693
- locked_dep = nil unless locked_dep == dep
713
+ diff = nil
694
714
 
695
- if in_locked_deps?(dep, locked_dep) || satisfies_locked_spec?(dep)
696
- deps << dep
697
- elsif dep.source.is_a?(Source::Path) && dep.current_platform? && (!locked_dep || dep.source != locked_dep.source)
698
- @locked_specs.each do |s|
699
- @unlock[:gems] << s.name if s.source == dep.source
700
- end
715
+ # Now, we unlock any sources that do not have anymore gems pinned to it
716
+ sources.all_sources.each do |source|
717
+ next unless source.respond_to?(:unlock!)
701
718
 
702
- dep.source.unlock! if dep.source.respond_to?(:unlock!)
703
- dep.source.specs.each {|s| @unlock[:gems] << s.name }
719
+ unless resolve.any? {|s| s.source == source }
720
+ diff ||= @locked_specs.to_a - resolve.to_a
721
+ source.unlock! if diff.any? {|s| s.source == source }
704
722
  end
705
723
  end
706
724
 
725
+ resolve
726
+ end
727
+
728
+ def converge_specs(specs)
707
729
  converged = []
708
- @locked_specs.each do |s|
709
- # Replace the locked dependency's source with the equivalent source from the Gemfile
730
+
731
+ deps = @dependencies.select do |dep|
732
+ specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
733
+ end
734
+
735
+ @specs_that_changed_sources = []
736
+
737
+ specs.each do |s|
710
738
  dep = @dependencies.find {|d| s.satisfies?(d) }
711
- s.source = (dep && dep.source) || sources.get(s.source) unless multisource_allowed?
712
739
 
713
- # Don't add a spec to the list if its source is expired. For example,
714
- # if you change a Git gem to RubyGems.
715
- next if s.source.nil?
716
- next if @unlock[:sources].include?(s.source.name)
740
+ # Replace the locked dependency's source with the equivalent source from the Gemfile
741
+ s.source = if dep && dep.source
742
+ gemfile_source = dep.source
743
+ lockfile_source = s.source
717
744
 
718
- # If the spec is from a path source and it doesn't exist anymore
719
- # then we unlock it.
745
+ @specs_that_changed_sources << s if gemfile_source != lockfile_source
746
+
747
+ gemfile_source
748
+ else
749
+ sources.get_with_fallback(s.source)
750
+ end
751
+
752
+ next if @unlock[:sources].include?(s.source.name)
720
753
 
721
754
  # Path sources have special logic
722
755
  if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
@@ -725,8 +758,8 @@ module Bundler
725
758
  rescue PathError, GitError
726
759
  # if we won't need the source (according to the lockfile),
727
760
  # don't error if the path/git source isn't available
728
- next if @locked_specs.
729
- for(requested_dependencies, false, true).
761
+ next if specs.
762
+ for(requested_dependencies, false).
730
763
  none? {|locked_spec| locked_spec.source == s.source }
731
764
 
732
765
  raise
@@ -741,79 +774,21 @@ module Bundler
741
774
  s.dependencies.replace(new_spec.dependencies)
742
775
  end
743
776
 
744
- converged << s
745
- end
746
-
747
- resolve = SpecSet.new(converged)
748
- @locked_specs_incomplete_for_platform = !resolve.for(expand_dependencies(requested_dependencies & deps), true, true)
749
- resolve = SpecSet.new(resolve.for(expand_dependencies(deps, true), false, false).reject{|s| @unlock[:gems].include?(s.name) })
750
- diff = nil
751
-
752
- # Now, we unlock any sources that do not have anymore gems pinned to it
753
- sources.all_sources.each do |source|
754
- next unless source.respond_to?(:unlock!)
755
-
756
- unless resolve.any? {|s| s.source == source }
757
- diff ||= @locked_specs.to_a - resolve.to_a
758
- source.unlock! if diff.any? {|s| s.source == source }
777
+ if dep.nil? && requested_dependencies.find {|d| s.name == d.name }
778
+ @unlock[:gems] << s.name
779
+ else
780
+ converged << s
759
781
  end
760
782
  end
761
783
 
762
- resolve
763
- end
764
-
765
- def in_locked_deps?(dep, locked_dep)
766
- # Because the lockfile can't link a dep to a specific remote, we need to
767
- # treat sources as equivalent anytime the locked dep has all the remotes
768
- # that the Gemfile dep does.
769
- locked_dep && locked_dep.source && dep.source && locked_dep.source.include?(dep.source)
770
- end
771
-
772
- def satisfies_locked_spec?(dep)
773
- @locked_specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
784
+ filter_specs(converged, deps)
774
785
  end
775
786
 
776
787
  def metadata_dependencies
777
- @metadata_dependencies ||= begin
778
- ruby_versions = ruby_version_requirements(@ruby_version)
779
- [
780
- Dependency.new("Ruby\0", ruby_versions),
781
- Dependency.new("RubyGems\0", Gem::VERSION),
782
- ]
783
- end
784
- end
785
-
786
- def ruby_version_requirements(ruby_version)
787
- return [] unless ruby_version
788
- if ruby_version.patchlevel
789
- [ruby_version.to_gem_version_with_patchlevel]
790
- else
791
- ruby_version.versions.map do |version|
792
- requirement = Gem::Requirement.new(version)
793
- if requirement.exact?
794
- "~> #{version}.0"
795
- else
796
- requirement
797
- end
798
- end
799
- end
800
- end
801
-
802
- def expand_dependencies(dependencies, remote = false)
803
- deps = []
804
- dependencies.each do |dep|
805
- dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
806
- next unless remote || dep.current_platform?
807
- target_platforms = dep.gem_platforms(remote ? @platforms : [generic_local_platform])
808
- deps += expand_dependency_with_platforms(dep, target_platforms)
809
- end
810
- deps
811
- end
812
-
813
- def expand_dependency_with_platforms(dep, platforms)
814
- platforms.map do |p|
815
- DepProxy.get_proxy(dep, p)
816
- end
788
+ @metadata_dependencies ||= [
789
+ Dependency.new("Ruby\0", Gem.ruby_version),
790
+ Dependency.new("RubyGems\0", Gem::VERSION),
791
+ ]
817
792
  end
818
793
 
819
794
  def source_requirements
@@ -821,20 +796,34 @@ module Bundler
821
796
  # specs will be available later when the resolver knows where to
822
797
  # look for that gemspec (or its dependencies)
823
798
  source_requirements = if precompute_source_requirements_for_indirect_dependencies?
824
- { :default => sources.default_source }.merge(source_map.all_requirements)
799
+ all_requirements = source_map.all_requirements
800
+ all_requirements = pin_locally_available_names(all_requirements) if @prefer_local
801
+ { :default => sources.default_source }.merge(all_requirements)
825
802
  else
826
803
  { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
827
804
  end
805
+ source_requirements.merge!(source_map.locked_requirements) unless @remote
828
806
  metadata_dependencies.each do |dep|
829
807
  source_requirements[dep.name] = sources.metadata_source
830
808
  end
831
809
  source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source
832
810
  source_requirements["bundler"] = sources.metadata_source # needs to come last to override
811
+ verify_changed_sources!
833
812
  source_requirements
834
813
  end
835
814
 
815
+ def verify_changed_sources!
816
+ @specs_that_changed_sources.each do |s|
817
+ if s.source.specs.search(s.name).empty?
818
+ raise GemNotFound, "Could not find gem '#{s.name}' in #{s.source}"
819
+ end
820
+ end
821
+ end
822
+
836
823
  def requested_groups
837
- groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
824
+ values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with]
825
+ values &= Bundler.settings[:only] unless Bundler.settings[:only].empty?
826
+ values
838
827
  end
839
828
 
840
829
  def lockfiles_equal?(current, proposed, preserve_unknown_sections)
@@ -861,28 +850,26 @@ module Bundler
861
850
  end
862
851
  end
863
852
 
864
- def additional_base_requirements_for_resolve
853
+ def additional_base_requirements_for_resolve(last_resolve)
865
854
  return [] unless @locked_gems && unlocking? && !sources.expired_sources?(@locked_gems.sources)
866
- dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) }
867
- @locked_gems.specs.reduce({}) do |requirements, locked_spec|
868
- name = locked_spec.name
869
- dependency = dependencies_by_name[name]
870
- next requirements if @locked_gems.dependencies[name] != dependency
871
- next requirements if dependency && dependency.source.is_a?(Source::Path)
872
- dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
873
- requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform)
874
- requirements
875
- end.values
855
+ converge_specs(@originally_locked_specs - last_resolve).map do |locked_spec|
856
+ Dependency.new(locked_spec.name, ">= #{locked_spec.version}")
857
+ end.uniq
876
858
  end
877
859
 
878
- def equivalent_rubygems_remotes?(source)
879
- return false unless source.is_a?(Source::Rubygems)
860
+ def remove_ruby_from_platforms_if_necessary!(dependencies)
861
+ return if Bundler.frozen_bundle? ||
862
+ Bundler.local_platform == Gem::Platform::RUBY ||
863
+ !platforms.include?(Gem::Platform::RUBY) ||
864
+ (@new_platform && platforms.last == Gem::Platform::RUBY) ||
865
+ !@originally_locked_specs.incomplete_ruby_specs?(dependencies)
880
866
 
881
- Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
867
+ remove_platform(Gem::Platform::RUBY)
868
+ add_current_platform
882
869
  end
883
870
 
884
871
  def source_map
885
- @source_map ||= SourceMap.new(sources, dependencies)
872
+ @source_map ||= SourceMap.new(sources, dependencies, @locked_specs)
886
873
  end
887
874
  end
888
875
  end