bundler 2.2.26 → 2.3.26

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