bundler 1.5.3 → 1.6.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +14 -11
  3. data/CHANGELOG.md +10 -3
  4. data/CONTRIBUTING.md +21 -12
  5. data/DEVELOPMENT.md +2 -2
  6. data/README.md +3 -2
  7. data/Rakefile +19 -9
  8. data/bundler.gemspec +1 -1
  9. data/lib/bundler.rb +9 -5
  10. data/lib/bundler/cli.rb +51 -10
  11. data/lib/bundler/dsl.rb +10 -6
  12. data/lib/bundler/friendly_errors.rb +1 -1
  13. data/lib/bundler/installer.rb +28 -17
  14. data/lib/bundler/parallel_workers/worker.rb +1 -1
  15. data/lib/bundler/resolver.rb +191 -207
  16. data/lib/bundler/rubygems_ext.rb +2 -4
  17. data/lib/bundler/rubygems_integration.rb +5 -0
  18. data/lib/bundler/runtime.rb +15 -12
  19. data/lib/bundler/settings.rb +4 -2
  20. data/lib/bundler/source.rb +11 -1
  21. data/lib/bundler/source/git.rb +11 -7
  22. data/lib/bundler/source/git/git_proxy.rb +4 -7
  23. data/lib/bundler/source/path.rb +21 -12
  24. data/lib/bundler/source/path/installer.rb +1 -1
  25. data/lib/bundler/source/rubygems.rb +18 -8
  26. data/lib/bundler/ssl_certs/certificate_manager.rb +41 -0
  27. data/lib/bundler/templates/newgem/README.md.tt +1 -1
  28. data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +2 -2
  29. data/lib/bundler/ui.rb +4 -141
  30. data/lib/bundler/ui/rg_proxy.rb +21 -0
  31. data/lib/bundler/ui/shell.rb +98 -0
  32. data/lib/bundler/ui/silent.rb +44 -0
  33. data/lib/bundler/vendor/net/http/faster.rb +0 -1
  34. data/lib/bundler/vendor/net/http/persistent.rb +0 -1
  35. data/lib/bundler/vendor/net/http/persistent/ssl_reuse.rb +0 -1
  36. data/lib/bundler/version.rb +1 -1
  37. data/spec/bundler/definition_spec.rb +2 -2
  38. data/spec/bundler/dsl_spec.rb +3 -3
  39. data/spec/bundler/gem_helper_spec.rb +5 -7
  40. data/spec/bundler/settings_spec.rb +15 -0
  41. data/spec/bundler/source_spec.rb +1 -1
  42. data/spec/commands/config_spec.rb +18 -0
  43. data/spec/commands/console_spec.rb +22 -0
  44. data/spec/commands/exec_spec.rb +1 -0
  45. data/spec/commands/newgem_spec.rb +2 -2
  46. data/spec/commands/open_spec.rb +13 -0
  47. data/spec/{install/gems/packed_spec.rb → commands/package_spec.rb} +30 -0
  48. data/spec/commands/show_spec.rb +87 -71
  49. data/spec/install/binstubs_spec.rb +1 -1
  50. data/spec/install/bundler_spec.rb +1 -1
  51. data/spec/install/gemfile/git_spec.rb +1 -1
  52. data/spec/install/gemfile/path_spec.rb +12 -0
  53. data/spec/install/gemfile_spec.rb +1 -1
  54. data/spec/install/gems/groups_spec.rb +1 -1
  55. data/spec/install/gems/platform_spec.rb +0 -1
  56. data/spec/install/gems/post_install_spec.rb +74 -0
  57. data/spec/install/gems/resolving_spec.rb +22 -26
  58. data/spec/install/gems/simple_case_spec.rb +17 -1
  59. data/spec/install/gemspecs_spec.rb +1 -1
  60. data/spec/install/path_spec.rb +1 -1
  61. data/spec/install/prereleases_spec.rb +1 -1
  62. data/spec/other/ext_spec.rb +1 -1
  63. data/spec/other/ssl_cert_spec.rb +10 -0
  64. data/spec/realworld/edgecases_spec.rb +1 -1
  65. data/spec/resolver/basic_spec.rb +29 -0
  66. data/spec/support/builders.rb +42 -43
  67. data/spec/support/indexes.rb +129 -1
  68. data/spec/support/permissions.rb +1 -0
  69. data/spec/update/gems_spec.rb +37 -0
  70. data/spec/update/git_spec.rb +24 -1
  71. data/spec/update/source_spec.rb +14 -1
  72. metadata +14 -9
  73. data/lib/bundler/safe_catch.rb +0 -101
  74. data/spec/bundler/safe_catch_spec.rb +0 -37
@@ -22,7 +22,7 @@ module Bundler
22
22
  Bundler.ui.warn <<-WARN, :wrap => true
23
23
  You must recompile Ruby with OpenSSL support or change the sources in your \
24
24
  Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL \
25
- using RVM are available at rvm.io/packages/openssl.
25
+ using RVM are available at http://rvm.io/packages/openssl.
26
26
  WARN
27
27
  Bundler.ui.trace e
28
28
  exit 1
@@ -90,7 +90,7 @@ module Bundler
90
90
  # dependencies might actually affect the installation of a gem.
91
91
  # that said, it's a rare situation (other than rake), and parallel
92
92
  # installation is just SO MUCH FASTER. so we let people opt in.
93
- jobs = [Bundler.settings[:jobs].to_i-1, 1].max
93
+ jobs = [Bundler.settings[:jobs].to_i, 1].max
94
94
  if jobs > 1 && can_install_parallely?
95
95
  install_in_parallel jobs, options[:standalone]
96
96
  else
@@ -109,10 +109,13 @@ module Bundler
109
109
  debug_message = nil
110
110
  Bundler.rubygems.with_build_args [settings] do
111
111
  install_message, post_install_message, debug_message = spec.source.install(spec)
112
- Bundler.ui.info install_message
112
+ if install_message.include? 'Installing'
113
+ Bundler.ui.confirm install_message
114
+ else
115
+ Bundler.ui.info install_message
116
+ end
113
117
  Bundler.ui.debug debug_message if debug_message
114
- spec_info = "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
115
- Bundler.ui.debug spec_info
118
+ Bundler.ui.debug "#{worker}: #{spec.name} (#{spec.version}) from #{spec.loaded_from}"
116
119
  end
117
120
 
118
121
  if Bundler.settings[:bin] && standalone
@@ -283,19 +286,13 @@ module Bundler
283
286
  message = install_gem_from_spec spec, standalone, worker
284
287
  { :name => spec.name, :post_install => message }
285
288
  }
286
- specs.each do |spec|
287
- if ready_to_install?(spec, remains)
288
- worker_pool.enq spec.name
289
- enqueued[spec.name] = true
290
- end
291
- end
292
289
 
293
- until remains.empty?
294
- message = worker_pool.deq
295
- remains.delete message[:name]
296
- if message[:post_install]
297
- Installer.post_install_messages[message[:name]] = message[:post_install]
298
- end
290
+ # Keys in the remains hash represent uninstalled gems specs.
291
+ # We enqueue all gem specs that do not have any dependencies.
292
+ # Later we call this lambda again to install specs that depended on
293
+ # previously installed specifications. We continue until all specs
294
+ # are installed.
295
+ enqueue_remaining_specs = lambda do
299
296
  remains.keys.each do |name|
300
297
  next if enqueued[name]
301
298
  spec = name2spec[name]
@@ -305,14 +302,28 @@ module Bundler
305
302
  end
306
303
  end
307
304
  end
305
+ enqueue_remaining_specs.call
306
+
307
+ until remains.empty?
308
+ message = worker_pool.deq
309
+ remains.delete message[:name]
310
+ if message[:post_install]
311
+ Installer.post_install_messages[message[:name]] = message[:post_install]
312
+ end
313
+ enqueue_remaining_specs.call
314
+ end
308
315
  message
309
316
  ensure
310
317
  worker_pool && worker_pool.stop
311
318
  end
312
319
 
320
+ # We only want to install a gem spec if all its dependencies are met.
321
+ # If the dependency is no longer in the `remains` hash then it has been met.
322
+ # If a dependency is only development or is self referential it can be ignored.
313
323
  def ready_to_install?(spec, remains)
314
324
  spec.dependencies.none? do |dep|
315
- remains[dep.name] && dep.type != :development && dep.name != spec.name
325
+ next if dep.type == :development || dep.name == spec.name
326
+ remains[dep.name]
316
327
  end
317
328
  end
318
329
  end
@@ -45,7 +45,7 @@ module Bundler
45
45
  end
46
46
 
47
47
  private
48
- # Stop the worker threads by sending a poison object down the request queue
48
+ # Stop the worker threads by sending a poison object down the request queue
49
49
  # so as worker threads after retrieving it, shut themselves down
50
50
  def stop_threads
51
51
  @threads.each do
@@ -1,5 +1,4 @@
1
1
  require 'set'
2
- require 'bundler/safe_catch'
3
2
  # This is the latest iteration of the gem dependency resolving algorithm. As of now,
4
3
  # it can resolve (as a success or failure) any set of gem dependencies we throw at it
5
4
  # in a reasonable amount of time. The most iterations I've seen it take is about 150.
@@ -22,8 +21,6 @@ end
22
21
 
23
22
  module Bundler
24
23
  class Resolver
25
- include SafeCatch
26
- extend SafeCatch
27
24
 
28
25
  ALL = Bundler::Dependency::PLATFORM_MAP.values.uniq.freeze
29
26
 
@@ -129,11 +126,7 @@ module Bundler
129
126
  Bundler.ui.info "Resolving dependencies...", false
130
127
  base = SpecSet.new(base) unless base.is_a?(SpecSet)
131
128
  resolver = new(index, source_requirements, base)
132
- result = safe_catch(:success) do
133
- resolver.start(requirements)
134
- raise resolver.version_conflict
135
- nil
136
- end
129
+ result = resolver.start(requirements)
137
130
  Bundler.ui.info "" # new line now that dots are done
138
131
  SpecSet.new(result)
139
132
  rescue => e
@@ -172,220 +165,198 @@ module Bundler
172
165
  resolve(reqs, activated)
173
166
  end
174
167
 
175
- def resolve(reqs, activated, depth = 0)
176
- # If the requirements are empty, then we are in a success state. Aka, all
177
- # gem dependencies have been resolved.
178
- safe_throw :success, successify(activated) if reqs.empty?
179
-
180
- indicate_progress
181
-
182
- debug { print "\e[2J\e[f" ; "==== Iterating ====\n\n" }
183
-
184
- # Sort dependencies so that the ones that are easiest to resolve are first.
185
- # Easiest to resolve is defined by:
186
- # 1) Is this gem already activated?
187
- # 2) Do the version requirements include prereleased gems?
188
- # 3) Sort by number of gems available in the source.
189
- reqs = reqs.sort_by do |a|
190
- [ activated[a.name] ? 0 : 1,
191
- a.requirement.prerelease? ? 0 : 1,
192
- @errors[a.name] ? 0 : 1,
193
- activated[a.name] ? 0 : @gems_size[a] ]
168
+ class State < Struct.new(:reqs, :activated, :requirement, :possibles, :depth)
169
+ def name
170
+ requirement.name
194
171
  end
172
+ end
195
173
 
196
- debug { "Activated:\n" + activated.values.map {|a| " #{a}" }.join("\n") }
197
- debug { "Requirements:\n" + reqs.map {|r| " #{r}"}.join("\n") }
174
+ def handle_conflict(current, states)
175
+ return unless current
176
+ parent = current
177
+ state = states.detect { |i| i.name == parent.name }
178
+ until (state && state.possibles.any?) || parent.required_by.empty?
179
+ parent = parent.required_by.last
180
+ state = states.detect { |i| i.name == parent.name }
181
+ end
182
+ return parent, state
183
+ end
198
184
 
199
- activated = activated.dup
185
+ def other_possible?(conflict, states)
186
+ return unless conflict
187
+ state = states.detect { |i| i.name == conflict.name }
188
+ state && state.possibles.any?
189
+ end
200
190
 
201
- # Pull off the first requirement so that we can resolve it
202
- current = reqs.shift
191
+ def find_conflict_state(conflict, states)
192
+ until states.empty? do
193
+ state = states.pop
194
+ return state if conflict.name == state.name
195
+ end
196
+ end
203
197
 
204
- $stderr.puts "#{' ' * depth}#{current}" if ENV['DEBUG_RESOLVER_TREE']
198
+ def activate_gem(reqs, activated, requirement, current)
199
+ requirement.required_by.replace current.required_by
200
+ requirement.required_by << current
201
+ activated[requirement.name] = requirement
205
202
 
206
- debug { "Attempting:\n #{current}"}
203
+ debug { " Activating: #{requirement.name} (#{requirement.version})" }
204
+ debug { requirement.required_by.map { |d| " * #{d.name} (#{d.requirement})" }.join("\n") }
207
205
 
208
- # Check if the gem has already been activated, if it has, we will make sure
209
- # that the currently activated gem satisfies the requirement.
210
- existing = activated[current.name]
211
- if existing || current.name == 'bundler'
212
- # Force the current
213
- if current.name == 'bundler' && !existing
214
- existing = search(DepProxy.new(Gem::Dependency.new('bundler', VERSION), Gem::Platform::RUBY)).first
215
- raise GemNotFound, %Q{Bundler could not find gem "bundler" (#{VERSION})} unless existing
216
- existing.required_by << existing
217
- activated['bundler'] = existing
218
- end
206
+ dependencies = requirement.activate_platform(current.__platform)
219
207
 
220
- if current.requirement.satisfied_by?(existing.version)
221
- debug { " * [SUCCESS] Already activated" }
222
- @errors.delete(existing.name)
223
- # Since the current requirement is satisfied, we can continue resolving
224
- # the remaining requirements.
225
-
226
- # I have no idea if this is the right way to do it, but let's see if it works
227
- # The current requirement might activate some other platforms, so let's try
228
- # adding those requirements here.
229
- dependencies = existing.activate_platform(current.__platform)
230
- reqs.concat dependencies
231
-
232
- dependencies.each do |dep|
233
- next if dep.type == :development
234
- @gems_size[dep] ||= gems_size(dep)
235
- end
208
+ debug { " Dependencies"}
209
+ dependencies.each do |dep|
210
+ next if dep.type == :development
211
+ dep.required_by.replace(current.required_by)
212
+ dep.required_by << current
213
+ @gems_size[dep] ||= gems_size(dep)
214
+ reqs << dep
215
+ end
216
+ end
236
217
 
237
- resolve(reqs, activated, depth + 1)
238
- else
239
- debug { " * [FAIL] Already activated" }
240
- @errors[existing.name] = [existing, current]
241
- debug { current.required_by.map {|d| " * #{d.name} (#{d.requirement})" }.join("\n") }
242
- # debug { " * All current conflicts:\n" + @errors.keys.map { |c| " - #{c}" }.join("\n") }
243
- # Since the current requirement conflicts with an activated gem, we need
244
- # to backtrack to the current requirement's parent and try another version
245
- # of it (maybe the current requirement won't be present anymore). If the
246
- # current requirement is a root level requirement, we need to jump back to
247
- # where the conflicting gem was activated.
248
- parent = current.required_by.last
249
- # `existing` could not respond to required_by if it is part of the base set
250
- # of specs that was passed to the resolver (aka, instance of LazySpecification)
251
- parent ||= existing.required_by.last if existing.respond_to?(:required_by)
252
- # We track the spot where the current gem was activated because we need
253
- # to keep a list of every spot a failure happened.
254
- if parent && parent.name != 'bundler'
255
- debug { " -> Jumping to: #{parent.name}" }
256
- required_by = existing.respond_to?(:required_by) && existing.required_by.last
257
- safe_throw parent.name, required_by && required_by.name
258
- else
259
- # The original set of dependencies conflict with the base set of specs
260
- # passed to the resolver. This is by definition an impossible resolve.
261
- raise version_conflict
262
- end
263
- end
264
- else
265
- # There are no activated gems for the current requirement, so we are going
266
- # to find all gems that match the current requirement and try them in decending
267
- # order. We also need to keep a set of all conflicts that happen while trying
268
- # this gem. This is so that if no versions work, we can figure out the best
269
- # place to backtrack to.
270
- conflicts = Set.new
271
-
272
- # Fetch all gem versions matching the requirement
273
- matching_versions = search(current)
274
-
275
- # If we found no versions that match the current requirement
276
- if matching_versions.empty?
277
- # If this is a top-level Gemfile requirement
278
- if current.required_by.empty?
279
- if base = @base[current.name] and !base.empty?
280
- version = base.first.version
281
- message = "You have requested:\n" \
282
- " #{current.name} #{current.requirement}\n\n" \
283
- "The bundle currently has #{current.name} locked at #{version}.\n" \
284
- "Try running `bundle update #{current.name}`"
285
- elsif current.source
286
- name = current.name
287
- versions = @source_requirements[name][name].map { |s| s.version }
288
- message = "Could not find gem '#{current}' in #{current.source}.\n"
289
- if versions.any?
290
- message << "Source contains '#{name}' at: #{versions.join(', ')}"
291
- else
292
- message << "Source does not contain any versions of '#{current}'"
293
- end
294
- else
295
- message = "Could not find gem '#{current}' "
296
- if @index.source_types.include?(Bundler::Source::Rubygems)
297
- message << "in any of the gem sources listed in your Gemfile."
298
- else
299
- message << "in the gems available on this machine."
300
- end
301
- end
302
- raise GemNotFound, message
303
- # This is not a top-level Gemfile requirement
304
- else
305
- @errors[current.name] = [nil, current]
306
- end
307
- end
218
+ def resolve_for_conflict(state)
219
+ raise version_conflict if state.nil? || state.possibles.empty?
220
+ reqs, activated, depth = state.reqs.dup, state.activated.dup, state.depth
221
+ requirement = state.requirement
222
+ possible = state.possibles.pop
308
223
 
309
- matching_versions.reverse_each do |spec_group|
310
- conflict = resolve_requirement(spec_group, current, reqs.dup, activated.dup, depth)
311
- conflicts << conflict if conflict
312
- end
224
+ activate_gem(reqs, activated, possible, requirement)
313
225
 
314
- # We throw the conflict up the dependency chain if it has not been
315
- # resolved (in @errors), thus avoiding branches of the tree that have no effect
316
- # on this conflict. Note that if the tree has multiple conflicts, we don't
317
- # care which one we throw, as long as we get out safe
318
- if !current.required_by.empty? && !conflicts.empty?
319
- @errors.reverse_each do |req_name, pair|
320
- if conflicts.include?(req_name)
321
- # Choose the closest pivot in the stack that will affect the conflict
322
- errorpivot = (@stack & [req_name, current.required_by.last.name]).last
323
- debug { " -> Jumping to: #{errorpivot}" }
324
- safe_throw errorpivot, req_name
325
- end
326
- end
226
+ return reqs, activated, depth
227
+ end
228
+
229
+ def resolve_conflict(current, states)
230
+ # Return a requirment/gem which has other possibles states
231
+ # Given the set of constraints placed by requrired_by
232
+ parent, _ = handle_conflict(current, states)
233
+
234
+ debug { " -> Going to: #{parent.name} state" }
235
+
236
+ # Find the state where the conlict has occured
237
+ state = find_conflict_state(parent, states)
238
+
239
+ # Resolve the conflicts by rewinding the state
240
+ # when the conflicted gem was activated
241
+ reqs, activated, depth = resolve_for_conflict(state)
242
+
243
+ # Keep the state around if it still has other possiblities
244
+ states << state unless state.possibles.empty?
245
+ clear_search_cache
246
+
247
+ return reqs, activated, depth
248
+ end
249
+
250
+ def resolve(reqs, activated)
251
+ states = []
252
+ depth = 0
253
+
254
+ until reqs.empty?
255
+
256
+ indicate_progress
257
+
258
+ debug { print "\e[2J\e[f" ; "==== Iterating ====\n\n" }
259
+
260
+ reqs = reqs.sort_by do |a|
261
+ [ activated[a.name] ? 0 : 1,
262
+ a.requirement.prerelease? ? 0 : 1,
263
+ @errors[a.name] ? 0 : 1,
264
+ activated[a.name] ? 0 : @gems_size[a] ]
327
265
  end
328
266
 
329
- # If the current requirement is a root level gem and we have conflicts, we
330
- # can figure out the best spot to backtrack to.
331
- if current.required_by.empty? && !conflicts.empty?
332
- # Check the current "catch" stack for the first one that is included in the
333
- # conflicts set. That is where the parent of the conflicting gem was required.
334
- # By jumping back to this spot, we can try other version of the parent of
335
- # the conflicting gem, hopefully finding a combination that activates correctly.
336
- @stack.reverse_each do |savepoint|
337
- if conflicts.include?(savepoint)
338
- debug { " -> Jumping to: #{savepoint}" }
339
- safe_throw savepoint
340
- end
267
+ debug { "Activated:\n" + activated.values.map {|a| " #{a}" }.join("\n") }
268
+ debug { "Requirements:\n" + reqs.map {|r| " #{r}"}.join("\n") }
269
+
270
+ current = reqs.shift
271
+
272
+ $stderr.puts "#{' ' * depth}#{current}" if ENV['DEBUG_RESOLVER_TREE']
273
+
274
+ debug { "Attempting:\n #{current}"}
275
+
276
+ existing = activated[current.name]
277
+
278
+
279
+ if existing || current.name == 'bundler'
280
+ # Force the current
281
+ if current.name == 'bundler' && !existing
282
+ existing = search(DepProxy.new(Gem::Dependency.new('bundler', VERSION), Gem::Platform::RUBY)).first
283
+ raise GemNotFound, %Q{Bundler could not find gem "bundler" (#{VERSION})} unless existing
284
+ existing.required_by << existing
285
+ activated['bundler'] = existing
341
286
  end
342
- end
343
- end
344
- end
345
287
 
346
- def resolve_requirement(spec_group, requirement, reqs, activated, depth)
347
- # We are going to try activating the spec. We need to keep track of stack of
348
- # requirements that got us to the point of activating this gem.
349
- spec_group.required_by.replace requirement.required_by
350
- spec_group.required_by << requirement
288
+ if current.requirement.satisfied_by?(existing.version)
289
+ debug { " * [SUCCESS] Already activated" }
290
+ @errors.delete(existing.name)
291
+ dependencies = existing.activate_platform(current.__platform)
292
+ reqs.concat dependencies
351
293
 
352
- activated[spec_group.name] = spec_group
353
- debug { " Activating: #{spec_group.name} (#{spec_group.version})" }
354
- debug { spec_group.required_by.map { |d| " * #{d.name} (#{d.requirement})" }.join("\n") }
294
+ dependencies.each do |dep|
295
+ next if dep.type == :development
296
+ @gems_size[dep] ||= gems_size(dep)
297
+ end
355
298
 
356
- dependencies = spec_group.activate_platform(requirement.__platform)
299
+ depth += 1
300
+ next
301
+ else
302
+ debug { " * [FAIL] Already activated" }
303
+ @errors[existing.name] = [existing, current]
357
304
 
358
- # Now, we have to loop through all child dependencies and add them to our
359
- # array of requirements.
360
- debug { " Dependencies"}
361
- dependencies.each do |dep|
362
- next if dep.type == :development
363
- debug { " * #{dep.name} (#{dep.requirement})" }
364
- dep.required_by.replace(requirement.required_by)
365
- dep.required_by << requirement
366
- @gems_size[dep] ||= gems_size(dep)
367
- reqs << dep
368
- end
305
+ parent = current.required_by.last
306
+ parent, state = handle_conflict(existing.required_by[-2], states) if !other_possible?(parent, states) && existing.respond_to?(:required_by)
307
+ parent = current unless state && state.possibles.any?
369
308
 
370
- # We create a savepoint and mark it by the name of the requirement that caused
371
- # the gem to be activated. If the activated gem ever conflicts, we are able to
372
- # jump back to this point and try another version of the gem.
373
- length = @stack.length
374
- @stack << requirement.name
375
- retval = safe_catch(requirement.name) do
376
- # try to resolve the next option
377
- resolve(reqs, activated, depth)
378
- end
309
+ raise version_conflict if parent.nil? || parent.name == 'bundler'
379
310
 
380
- # clear the search cache since the catch means we couldn't meet the
381
- # requirement we need with the current constraints on search
382
- clear_search_cache
383
311
 
384
- # Since we're doing a lot of throw / catches. A push does not necessarily match
385
- # up to a pop. So, we simply slice the stack back to what it was before the catch
386
- # block.
387
- @stack.slice!(length..-1)
388
- retval
312
+ reqs, activated, depth = resolve_conflict(parent, states)
313
+ end
314
+ else
315
+ matching_versions = search(current)
316
+
317
+ # If we found no versions that match the current requirement
318
+ if matching_versions.empty?
319
+ # If this is a top-level Gemfile requirement
320
+ if current.required_by.empty?
321
+ if base = @base[current.name] and !base.empty?
322
+ version = base.first.version
323
+ message = "You have requested:\n" \
324
+ " #{current.name} #{current.requirement}\n\n" \
325
+ "The bundle currently has #{current.name} locked at #{version}.\n" \
326
+ "Try running `bundle update #{current.name}`"
327
+ elsif current.source
328
+ name = current.name
329
+ versions = @source_requirements[name][name].map { |s| s.version }
330
+ message = "Could not find gem '#{current}' in #{current.source}.\n"
331
+ if versions.any?
332
+ message << "Source contains '#{name}' at: #{versions.join(', ')}"
333
+ else
334
+ message << "Source does not contain any versions of '#{current}'"
335
+ end
336
+ else
337
+ message = "Could not find gem '#{current}' "
338
+ if @index.source_types.include?(Bundler::Source::Rubygems)
339
+ message << "in any of the gem sources listed in your Gemfile."
340
+ else
341
+ message << "in the gems available on this machine."
342
+ end
343
+ end
344
+ raise GemNotFound, message
345
+ # This is not a top-level Gemfile requirement
346
+ else
347
+ @errors[current.name] = [nil, current]
348
+ reqs, activated, depth = resolve_conflict(current, states)
349
+ next
350
+ end
351
+ end
352
+
353
+ state = State.new(reqs.dup, activated.dup, current, matching_versions, depth)
354
+ states << state
355
+ requirement = state.possibles.pop
356
+ activate_gem(reqs, activated, requirement, current)
357
+ end
358
+ end
359
+ successify(activated)
389
360
  end
390
361
 
391
362
  def gems_size(dep)
@@ -438,20 +409,29 @@ module Bundler
438
409
  end
439
410
 
440
411
  # For a given conflicted requirement, print out what exactly went wrong
441
- def gem_message(requirement)
412
+ def gem_message(requirement, required_by=[])
442
413
  m = ""
443
414
 
444
415
  # A requirement that is required by itself is actually in the Gemfile, and does
445
416
  # not "depend on" itself
446
417
  if requirement.required_by.first && requirement.required_by.first.name != requirement.name
447
- m << " #{clean_req(requirement.required_by.first)} depends on\n"
448
- m << " #{clean_req(requirement)}\n"
418
+ dependency_tree(m, required_by)
419
+ m << "#{clean_req(requirement)}\n"
449
420
  else
450
421
  m << " #{clean_req(requirement)}\n"
451
422
  end
452
423
  m << "\n"
453
424
  end
454
425
 
426
+ def dependency_tree(m, requirements)
427
+ requirements.each_with_index do |i, j|
428
+ m << " " << (" " * j)
429
+ m << "#{clean_req(i)}"
430
+ m << " depends on\n"
431
+ end
432
+ m << " " << (" " * requirements.size)
433
+ end
434
+
455
435
  def error_message
456
436
  errors.inject("") do |o, (conflict, (origin, requirement))|
457
437
 
@@ -461,7 +441,8 @@ module Bundler
461
441
  o << %{Bundler could not find compatible versions for gem "#{origin.name}":\n}
462
442
  o << " In Gemfile:\n"
463
443
 
464
- o << gem_message(requirement)
444
+ required_by = requirement.required_by
445
+ o << gem_message(requirement, required_by)
465
446
 
466
447
  # If the origin is "bundler", the conflict is us
467
448
  if origin.name == "bundler"
@@ -472,7 +453,8 @@ module Bundler
472
453
  o << " In snapshot (Gemfile.lock):\n"
473
454
  end
474
455
 
475
- o << gem_message(origin)
456
+ required_by = origin.required_by[0..-2]
457
+ o << gem_message(origin, required_by)
476
458
 
477
459
  # If the bundle wants a newer bundler than the running bundler, explain
478
460
  if origin.name == "bundler" && other_bundler_required
@@ -495,7 +477,9 @@ module Bundler
495
477
  o << " #{clean_req(locked)}\n\n"
496
478
 
497
479
  o << " In Gemfile:\n"
498
- o << gem_message(requirement)
480
+
481
+ required_by = requirement.required_by
482
+ o << gem_message(requirement, required_by)
499
483
  o << "Running `bundle update` will rebuild your snapshot from scratch, using only\n"
500
484
  o << "the gems in your Gemfile, which may resolve the conflict.\n"
501
485