bundler 1.5.3 → 1.6.0.pre.1
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.
Potentially problematic release.
This version of bundler might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +14 -11
- data/CHANGELOG.md +10 -3
- data/CONTRIBUTING.md +21 -12
- data/DEVELOPMENT.md +2 -2
- data/README.md +3 -2
- data/Rakefile +19 -9
- data/bundler.gemspec +1 -1
- data/lib/bundler.rb +9 -5
- data/lib/bundler/cli.rb +51 -10
- data/lib/bundler/dsl.rb +10 -6
- data/lib/bundler/friendly_errors.rb +1 -1
- data/lib/bundler/installer.rb +28 -17
- data/lib/bundler/parallel_workers/worker.rb +1 -1
- data/lib/bundler/resolver.rb +191 -207
- data/lib/bundler/rubygems_ext.rb +2 -4
- data/lib/bundler/rubygems_integration.rb +5 -0
- data/lib/bundler/runtime.rb +15 -12
- data/lib/bundler/settings.rb +4 -2
- data/lib/bundler/source.rb +11 -1
- data/lib/bundler/source/git.rb +11 -7
- data/lib/bundler/source/git/git_proxy.rb +4 -7
- data/lib/bundler/source/path.rb +21 -12
- data/lib/bundler/source/path/installer.rb +1 -1
- data/lib/bundler/source/rubygems.rb +18 -8
- data/lib/bundler/ssl_certs/certificate_manager.rb +41 -0
- data/lib/bundler/templates/newgem/README.md.tt +1 -1
- data/lib/bundler/templates/newgem/spec/newgem_spec.rb.tt +2 -2
- data/lib/bundler/ui.rb +4 -141
- data/lib/bundler/ui/rg_proxy.rb +21 -0
- data/lib/bundler/ui/shell.rb +98 -0
- data/lib/bundler/ui/silent.rb +44 -0
- data/lib/bundler/vendor/net/http/faster.rb +0 -1
- data/lib/bundler/vendor/net/http/persistent.rb +0 -1
- data/lib/bundler/vendor/net/http/persistent/ssl_reuse.rb +0 -1
- data/lib/bundler/version.rb +1 -1
- data/spec/bundler/definition_spec.rb +2 -2
- data/spec/bundler/dsl_spec.rb +3 -3
- data/spec/bundler/gem_helper_spec.rb +5 -7
- data/spec/bundler/settings_spec.rb +15 -0
- data/spec/bundler/source_spec.rb +1 -1
- data/spec/commands/config_spec.rb +18 -0
- data/spec/commands/console_spec.rb +22 -0
- data/spec/commands/exec_spec.rb +1 -0
- data/spec/commands/newgem_spec.rb +2 -2
- data/spec/commands/open_spec.rb +13 -0
- data/spec/{install/gems/packed_spec.rb → commands/package_spec.rb} +30 -0
- data/spec/commands/show_spec.rb +87 -71
- data/spec/install/binstubs_spec.rb +1 -1
- data/spec/install/bundler_spec.rb +1 -1
- data/spec/install/gemfile/git_spec.rb +1 -1
- data/spec/install/gemfile/path_spec.rb +12 -0
- data/spec/install/gemfile_spec.rb +1 -1
- data/spec/install/gems/groups_spec.rb +1 -1
- data/spec/install/gems/platform_spec.rb +0 -1
- data/spec/install/gems/post_install_spec.rb +74 -0
- data/spec/install/gems/resolving_spec.rb +22 -26
- data/spec/install/gems/simple_case_spec.rb +17 -1
- data/spec/install/gemspecs_spec.rb +1 -1
- data/spec/install/path_spec.rb +1 -1
- data/spec/install/prereleases_spec.rb +1 -1
- data/spec/other/ext_spec.rb +1 -1
- data/spec/other/ssl_cert_spec.rb +10 -0
- data/spec/realworld/edgecases_spec.rb +1 -1
- data/spec/resolver/basic_spec.rb +29 -0
- data/spec/support/builders.rb +42 -43
- data/spec/support/indexes.rb +129 -1
- data/spec/support/permissions.rb +1 -0
- data/spec/update/gems_spec.rb +37 -0
- data/spec/update/git_spec.rb +24 -1
- data/spec/update/source_spec.rb +14 -1
- metadata +14 -9
- data/lib/bundler/safe_catch.rb +0 -101
- 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
|
data/lib/bundler/installer.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
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
|
-
|
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
|
data/lib/bundler/resolver.rb
CHANGED
@@ -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 =
|
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
|
-
|
176
|
-
|
177
|
-
|
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
|
-
|
197
|
-
|
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
|
-
|
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
|
-
|
202
|
-
|
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
|
-
|
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 { "
|
203
|
+
debug { " Activating: #{requirement.name} (#{requirement.version})" }
|
204
|
+
debug { requirement.required_by.map { |d| " * #{d.name} (#{d.requirement})" }.join("\n") }
|
207
205
|
|
208
|
-
|
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
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
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
|
-
|
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
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
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
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
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
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
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
|
-
|
353
|
-
|
354
|
-
|
294
|
+
dependencies.each do |dep|
|
295
|
+
next if dep.type == :development
|
296
|
+
@gems_size[dep] ||= gems_size(dep)
|
297
|
+
end
|
355
298
|
|
356
|
-
|
299
|
+
depth += 1
|
300
|
+
next
|
301
|
+
else
|
302
|
+
debug { " * [FAIL] Already activated" }
|
303
|
+
@errors[existing.name] = [existing, current]
|
357
304
|
|
358
|
-
|
359
|
-
|
360
|
-
|
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
|
-
|
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
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
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
|
448
|
-
m << "
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
|