honkster-bundler 1.1.pre

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 (137) hide show
  1. data/.gitignore +14 -0
  2. data/CHANGELOG.md +547 -0
  3. data/ISSUES.md +32 -0
  4. data/LICENSE +20 -0
  5. data/README.md +29 -0
  6. data/Rakefile +150 -0
  7. data/UPGRADING.md +103 -0
  8. data/bin/bundle +21 -0
  9. data/bundler.gemspec +30 -0
  10. data/lib/bundler.rb +268 -0
  11. data/lib/bundler/capistrano.rb +11 -0
  12. data/lib/bundler/cli.rb +515 -0
  13. data/lib/bundler/definition.rb +427 -0
  14. data/lib/bundler/dependency.rb +114 -0
  15. data/lib/bundler/deployment.rb +37 -0
  16. data/lib/bundler/dsl.rb +245 -0
  17. data/lib/bundler/environment.rb +47 -0
  18. data/lib/bundler/gem_helper.rb +145 -0
  19. data/lib/bundler/graph.rb +130 -0
  20. data/lib/bundler/index.rb +114 -0
  21. data/lib/bundler/installer.rb +84 -0
  22. data/lib/bundler/lazy_specification.rb +71 -0
  23. data/lib/bundler/lockfile_parser.rb +108 -0
  24. data/lib/bundler/remote_specification.rb +59 -0
  25. data/lib/bundler/resolver.rb +454 -0
  26. data/lib/bundler/rubygems_ext.rb +203 -0
  27. data/lib/bundler/runtime.rb +148 -0
  28. data/lib/bundler/settings.rb +117 -0
  29. data/lib/bundler/setup.rb +15 -0
  30. data/lib/bundler/shared_helpers.rb +151 -0
  31. data/lib/bundler/source.rb +662 -0
  32. data/lib/bundler/spec_set.rb +134 -0
  33. data/lib/bundler/templates/Executable +16 -0
  34. data/lib/bundler/templates/Gemfile +4 -0
  35. data/lib/bundler/templates/newgem/Gemfile.tt +4 -0
  36. data/lib/bundler/templates/newgem/Rakefile.tt +2 -0
  37. data/lib/bundler/templates/newgem/bin/newgem.tt +3 -0
  38. data/lib/bundler/templates/newgem/gitignore.tt +3 -0
  39. data/lib/bundler/templates/newgem/lib/newgem.rb.tt +7 -0
  40. data/lib/bundler/templates/newgem/lib/newgem/version.rb.tt +7 -0
  41. data/lib/bundler/templates/newgem/newgem.gemspec.tt +21 -0
  42. data/lib/bundler/ui.rb +60 -0
  43. data/lib/bundler/vendor/thor.rb +319 -0
  44. data/lib/bundler/vendor/thor/actions.rb +297 -0
  45. data/lib/bundler/vendor/thor/actions/create_file.rb +105 -0
  46. data/lib/bundler/vendor/thor/actions/directory.rb +93 -0
  47. data/lib/bundler/vendor/thor/actions/empty_directory.rb +134 -0
  48. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +229 -0
  49. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +104 -0
  50. data/lib/bundler/vendor/thor/base.rb +556 -0
  51. data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +9 -0
  52. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  53. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +100 -0
  54. data/lib/bundler/vendor/thor/error.rb +30 -0
  55. data/lib/bundler/vendor/thor/invocation.rb +168 -0
  56. data/lib/bundler/vendor/thor/parser.rb +4 -0
  57. data/lib/bundler/vendor/thor/parser/argument.rb +67 -0
  58. data/lib/bundler/vendor/thor/parser/arguments.rb +161 -0
  59. data/lib/bundler/vendor/thor/parser/option.rb +120 -0
  60. data/lib/bundler/vendor/thor/parser/options.rb +174 -0
  61. data/lib/bundler/vendor/thor/shell.rb +88 -0
  62. data/lib/bundler/vendor/thor/shell/basic.rb +275 -0
  63. data/lib/bundler/vendor/thor/shell/color.rb +108 -0
  64. data/lib/bundler/vendor/thor/shell/html.rb +121 -0
  65. data/lib/bundler/vendor/thor/task.rb +114 -0
  66. data/lib/bundler/vendor/thor/util.rb +229 -0
  67. data/lib/bundler/vendor/thor/version.rb +3 -0
  68. data/lib/bundler/version.rb +6 -0
  69. data/lib/bundler/vlad.rb +9 -0
  70. data/man/bundle-config.ronn +90 -0
  71. data/man/bundle-exec.ronn +98 -0
  72. data/man/bundle-install.ronn +310 -0
  73. data/man/bundle-package.ronn +59 -0
  74. data/man/bundle-update.ronn +176 -0
  75. data/man/bundle.ronn +77 -0
  76. data/man/gemfile.5.ronn +273 -0
  77. data/man/index.txt +6 -0
  78. data/spec/cache/gems_spec.rb +205 -0
  79. data/spec/cache/git_spec.rb +9 -0
  80. data/spec/cache/path_spec.rb +27 -0
  81. data/spec/cache/platform_spec.rb +57 -0
  82. data/spec/install/deploy_spec.rb +197 -0
  83. data/spec/install/deprecated_spec.rb +43 -0
  84. data/spec/install/gems/c_ext_spec.rb +48 -0
  85. data/spec/install/gems/env_spec.rb +107 -0
  86. data/spec/install/gems/flex_spec.rb +272 -0
  87. data/spec/install/gems/groups_spec.rb +228 -0
  88. data/spec/install/gems/packed_spec.rb +72 -0
  89. data/spec/install/gems/platform_spec.rb +195 -0
  90. data/spec/install/gems/resolving_spec.rb +72 -0
  91. data/spec/install/gems/simple_case_spec.rb +749 -0
  92. data/spec/install/gems/sudo_spec.rb +77 -0
  93. data/spec/install/gems/win32_spec.rb +26 -0
  94. data/spec/install/gemspec_spec.rb +96 -0
  95. data/spec/install/git_spec.rb +553 -0
  96. data/spec/install/invalid_spec.rb +17 -0
  97. data/spec/install/path_spec.rb +329 -0
  98. data/spec/install/upgrade_spec.rb +26 -0
  99. data/spec/lock/flex_spec.rb +650 -0
  100. data/spec/lock/git_spec.rb +35 -0
  101. data/spec/other/check_spec.rb +221 -0
  102. data/spec/other/config_spec.rb +40 -0
  103. data/spec/other/console_spec.rb +54 -0
  104. data/spec/other/exec_spec.rb +241 -0
  105. data/spec/other/ext_spec.rb +16 -0
  106. data/spec/other/gem_helper_spec.rb +126 -0
  107. data/spec/other/help_spec.rb +36 -0
  108. data/spec/other/init_spec.rb +40 -0
  109. data/spec/other/newgem_spec.rb +24 -0
  110. data/spec/other/open_spec.rb +35 -0
  111. data/spec/other/show_spec.rb +82 -0
  112. data/spec/pack/gems_spec.rb +22 -0
  113. data/spec/quality_spec.rb +55 -0
  114. data/spec/resolver/basic_spec.rb +20 -0
  115. data/spec/resolver/platform_spec.rb +57 -0
  116. data/spec/runtime/environment_rb_spec.rb +162 -0
  117. data/spec/runtime/executable_spec.rb +110 -0
  118. data/spec/runtime/load_spec.rb +102 -0
  119. data/spec/runtime/platform_spec.rb +90 -0
  120. data/spec/runtime/require_spec.rb +231 -0
  121. data/spec/runtime/setup_spec.rb +412 -0
  122. data/spec/runtime/with_clean_env_spec.rb +15 -0
  123. data/spec/spec_helper.rb +82 -0
  124. data/spec/support/builders.rb +566 -0
  125. data/spec/support/helpers.rb +243 -0
  126. data/spec/support/indexes.rb +113 -0
  127. data/spec/support/matchers.rb +89 -0
  128. data/spec/support/path.rb +71 -0
  129. data/spec/support/platforms.rb +49 -0
  130. data/spec/support/ruby_ext.rb +19 -0
  131. data/spec/support/rubygems_ext.rb +30 -0
  132. data/spec/support/rubygems_hax/rubygems_plugin.rb +9 -0
  133. data/spec/support/sudo.rb +21 -0
  134. data/spec/update/gems_spec.rb +112 -0
  135. data/spec/update/git_spec.rb +159 -0
  136. data/spec/update/source_spec.rb +50 -0
  137. metadata +251 -0
@@ -0,0 +1,59 @@
1
+ require "uri"
2
+ require "rubygems/spec_fetcher"
3
+
4
+ module Bundler
5
+ # Represents a lazily loaded gem specification, where the full specification
6
+ # is on the source server in rubygems' "quick" index. The proxy object is to
7
+ # be seeded with what we're given from the source's abbreviated index - the
8
+ # full specification will only be fetched when necesary.
9
+ class RemoteSpecification
10
+ include MatchPlatform
11
+
12
+ attr_reader :name, :version, :platform
13
+ attr_accessor :source
14
+
15
+ def initialize(name, version, platform, source_uri)
16
+ @name = name
17
+ @version = version
18
+ @platform = platform
19
+ @source_uri = source_uri
20
+ end
21
+
22
+ # Needed before installs, since the arch matters then and quick
23
+ # specs don't bother to include the arch in the platform string
24
+ def fetch_platform
25
+ @platform = _remote_specification.platform
26
+ end
27
+
28
+ def full_name
29
+ if platform == Gem::Platform::RUBY or platform.nil? then
30
+ "#{@name}-#{@version}"
31
+ else
32
+ "#{@name}-#{@version}-#{platform}"
33
+ end
34
+ end
35
+
36
+ # Because Rubyforge cannot be trusted to provide valid specifications
37
+ # once the remote gem is downloaded, the backend specification will
38
+ # be swapped out.
39
+ def __swap__(spec)
40
+ @specification = spec
41
+ end
42
+
43
+ private
44
+
45
+ def _remote_specification
46
+ @specification ||= begin
47
+ Gem::SpecFetcher.new.fetch_spec([@name, @version, @platform], URI(@source_uri.to_s))
48
+ end
49
+ end
50
+
51
+ def method_missing(method, *args, &blk)
52
+ if Gem::Specification.new.respond_to?(method)
53
+ _remote_specification.send(method, *args, &blk)
54
+ else
55
+ super
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,454 @@
1
+ require 'set'
2
+ # This is the latest iteration of the gem dependency resolving algorithm. As of now,
3
+ # it can resolve (as a success or failure) any set of gem dependencies we throw at it
4
+ # in a reasonable amount of time. The most iterations I've seen it take is about 150.
5
+ # The actual implementation of the algorithm is not as good as it could be yet, but that
6
+ # can come later.
7
+
8
+ # Extending Gem classes to add necessary tracking information
9
+ module Gem
10
+ class Specification
11
+ def required_by
12
+ @required_by ||= []
13
+ end
14
+ end
15
+ class Dependency
16
+ def required_by
17
+ @required_by ||= []
18
+ end
19
+ end
20
+ end
21
+
22
+ module Bundler
23
+ class Resolver
24
+ ALL = [ Gem::Platform::RUBY,
25
+ Gem::Platform::JAVA,
26
+ Gem::Platform::MSWIN,
27
+ Gem::Platform::MING]
28
+
29
+ class SpecGroup < Array
30
+ include GemHelpers
31
+
32
+ attr_reader :activated, :required_by
33
+
34
+ def initialize(a)
35
+ super
36
+ @required_by = []
37
+ @activated = []
38
+ @dependencies = nil
39
+ @specs = {}
40
+
41
+ ALL.each do |p|
42
+ @specs[p] = reverse.find { |s| s.match_platform(p) }
43
+ end
44
+ end
45
+
46
+ def initialize_copy(o)
47
+ super
48
+ @required_by = o.required_by.dup
49
+ @activated = o.activated.dup
50
+ end
51
+
52
+ def to_specs
53
+ specs = {}
54
+
55
+ @activated.each do |p|
56
+ if s = @specs[p]
57
+ platform = generic(Gem::Platform.new(s.platform))
58
+ next if specs[platform]
59
+
60
+ lazy_spec = LazySpecification.new(name, version, platform, source)
61
+ lazy_spec.dependencies.replace s.dependencies
62
+ specs[platform] = lazy_spec
63
+ end
64
+ end
65
+ specs.values
66
+ end
67
+
68
+ def activate_platform(platform)
69
+ unless @activated.include?(platform)
70
+ @activated << platform
71
+ return __dependencies[platform] || []
72
+ end
73
+ []
74
+ end
75
+
76
+ def name
77
+ @name ||= first.name
78
+ end
79
+
80
+ def version
81
+ @version ||= first.version
82
+ end
83
+
84
+ def source
85
+ @source ||= first.source
86
+ end
87
+
88
+ def for?(platform)
89
+ @specs[platform]
90
+ end
91
+
92
+ def to_s
93
+ "#{name} (#{version})"
94
+ end
95
+
96
+ private
97
+
98
+ def __dependencies
99
+ @dependencies ||= begin
100
+ dependencies = {}
101
+ ALL.each do |p|
102
+ if spec = @specs[p]
103
+ dependencies[p] = []
104
+ spec.dependencies.each do |dep|
105
+ next if dep.type == :development
106
+ dependencies[p] << DepProxy.new(dep, p)
107
+ end
108
+ end
109
+ end
110
+ dependencies
111
+ end
112
+ end
113
+ end
114
+
115
+ attr_reader :errors
116
+
117
+ # Figures out the best possible configuration of gems that satisfies
118
+ # the list of passed dependencies and any child dependencies without
119
+ # causing any gem activation errors.
120
+ #
121
+ # ==== Parameters
122
+ # *dependencies<Gem::Dependency>:: The list of dependencies to resolve
123
+ #
124
+ # ==== Returns
125
+ # <GemBundle>,nil:: If the list of dependencies can be resolved, a
126
+ # collection of gemspecs is returned. Otherwise, nil is returned.
127
+ def self.resolve(requirements, index, source_requirements = {}, base = [])
128
+ base = SpecSet.new(base) unless base.is_a?(SpecSet)
129
+ resolver = new(index, source_requirements, base)
130
+ result = catch(:success) do
131
+ resolver.start(requirements)
132
+ raise resolver.version_conflict
133
+ nil
134
+ end
135
+ SpecSet.new(result)
136
+ end
137
+
138
+ def initialize(index, source_requirements, base)
139
+ @errors = {}
140
+ @stack = []
141
+ @base = base
142
+ @index = index
143
+ @missing_gems = Hash.new(0)
144
+ @source_requirements = source_requirements
145
+ end
146
+
147
+ def debug
148
+ if ENV['DEBUG_RESOLVER']
149
+ debug_info = yield
150
+ debug_info = debug_info.inpsect unless debug_info.is_a?(String)
151
+ $stderr.puts debug_info
152
+ end
153
+ end
154
+
155
+ def successify(activated)
156
+ activated.values.map { |s| s.to_specs }.flatten.compact
157
+ end
158
+
159
+ def start(reqs)
160
+ activated = {}
161
+
162
+ resolve(reqs, activated)
163
+ end
164
+
165
+ def resolve(reqs, activated)
166
+ # If the requirements are empty, then we are in a success state. Aka, all
167
+ # gem dependencies have been resolved.
168
+ throw :success, successify(activated) if reqs.empty?
169
+
170
+ debug { print "\e[2J\e[f" ; "==== Iterating ====\n\n" }
171
+ debug { "Activated:\n" + activated.values.map { |a| " #{a.name} (#{a.version})" }.join("\n") }
172
+ debug { "Requirements:\n" + reqs.map { |r| " #{r.name} (#{r.requirement})"}.join("\n") }
173
+
174
+ activated = activated.dup
175
+
176
+ # Pull off the first requirement so that we can resolve it
177
+ current = reqs.shift
178
+
179
+ debug { "Attempting:\n #{current.name} (#{current.requirement})"}
180
+
181
+ # Check if the gem has already been activated, if it has, we will make sure
182
+ # that the currently activated gem satisfies the requirement.
183
+ existing = activated[current.name]
184
+ if existing || current.name == 'bundler'
185
+ # Force the current
186
+ if current.name == 'bundler' && !existing
187
+ existing = search(DepProxy.new(Gem::Dependency.new('bundler', VERSION), Gem::Platform::RUBY)).first
188
+ raise GemNotFound, %Q{Bundler could not find gem "bundler" (#{VERSION})} unless existing
189
+ existing.required_by << existing
190
+ activated['bundler'] = existing
191
+ end
192
+
193
+ if current.requirement.satisfied_by?(existing.version)
194
+ debug { " * [SUCCESS] Already activated" }
195
+ @errors.delete(existing.name)
196
+ # Since the current requirement is satisfied, we can continue resolving
197
+ # the remaining requirements.
198
+
199
+ # I have no idea if this is the right way to do it, but let's see if it works
200
+ # The current requirement might activate some other platforms, so let's try
201
+ # adding those requirements here.
202
+ reqs.concat existing.activate_platform(current.__platform)
203
+
204
+ resolve(reqs, activated)
205
+ else
206
+ debug { " * [FAIL] Already activated" }
207
+ @errors[existing.name] = [existing, current]
208
+ debug { current.required_by.map {|d| " * #{d.name} (#{d.requirement})" }.join("\n") }
209
+ # debug { " * All current conflicts:\n" + @errors.keys.map { |c| " - #{c}" }.join("\n") }
210
+ # Since the current requirement conflicts with an activated gem, we need
211
+ # to backtrack to the current requirement's parent and try another version
212
+ # of it (maybe the current requirement won't be present anymore). If the
213
+ # current requirement is a root level requirement, we need to jump back to
214
+ # where the conflicting gem was activated.
215
+ parent = current.required_by.last
216
+ # `existing` could not respond to required_by if it is part of the base set
217
+ # of specs that was passed to the resolver (aka, instance of LazySpecification)
218
+ parent ||= existing.required_by.last if existing.respond_to?(:required_by)
219
+ # We track the spot where the current gem was activated because we need
220
+ # to keep a list of every spot a failure happened.
221
+ if parent && parent.name != 'bundler'
222
+ debug { " -> Jumping to: #{parent.name}" }
223
+ throw parent.name, existing.respond_to?(:required_by) && existing.required_by.last && existing.required_by.last.name
224
+ else
225
+ # The original set of dependencies conflict with the base set of specs
226
+ # passed to the resolver. This is by definition an impossible resolve.
227
+ raise version_conflict
228
+ end
229
+ end
230
+ else
231
+ # There are no activated gems for the current requirement, so we are going
232
+ # to find all gems that match the current requirement and try them in decending
233
+ # order. We also need to keep a set of all conflicts that happen while trying
234
+ # this gem. This is so that if no versions work, we can figure out the best
235
+ # place to backtrack to.
236
+ conflicts = Set.new
237
+
238
+ # Fetch all gem versions matching the requirement
239
+ #
240
+ # TODO: Warn / error when no matching versions are found.
241
+ matching_versions = search(current)
242
+
243
+ if matching_versions.empty?
244
+ if current.required_by.empty?
245
+ if base = @base[current.name] and !base.empty?
246
+ version = base.first.version
247
+ message = "You have requested:\n" \
248
+ " #{current.name} #{current.requirement}\n\n" \
249
+ "The bundle currently has #{current.name} locked at #{version}.\n" \
250
+ "Try running `bundle update #{current.name}`"
251
+ elsif current.source
252
+ name = current.name
253
+ versions = @source_requirements[name][name].map { |s| s.version }
254
+ message = "Could not find gem '#{current}' in #{current.source}.\n"
255
+ if versions.any?
256
+ message << "Source contains '#{name}' at: #{versions.join(', ')}"
257
+ else
258
+ message << "Source does not contain any versions of '#{current}'"
259
+ end
260
+ else
261
+ message = "Could not find gem '#{current}' "
262
+ if @index.sources.include?(Bundler::Source::Rubygems)
263
+ message << "in any of the gem sources."
264
+ else
265
+ message << "in the gems available on this machine."
266
+ end
267
+ end
268
+ raise GemNotFound, message
269
+ else
270
+ if @missing_gems[current] >= 5
271
+ message = "Bundler could not find find gem #{current.required_by.last},"
272
+ message << "which is required by gem #{current}."
273
+ raise GemNotFound, message
274
+ end
275
+ @missing_gems[current] += 1
276
+
277
+ debug { " Could not find #{current} by #{current.required_by.last}" }
278
+ @errors[current.name] = [nil, current]
279
+ end
280
+ end
281
+
282
+ matching_versions.reverse_each do |spec_group|
283
+ conflict = resolve_requirement(spec_group, current, reqs.dup, activated.dup)
284
+ conflicts << conflict if conflict
285
+ end
286
+ # If the current requirement is a root level gem and we have conflicts, we
287
+ # can figure out the best spot to backtrack to.
288
+ if current.required_by.empty? && !conflicts.empty?
289
+ # Check the current "catch" stack for the first one that is included in the
290
+ # conflicts set. That is where the parent of the conflicting gem was required.
291
+ # By jumping back to this spot, we can try other version of the parent of
292
+ # the conflicting gem, hopefully finding a combination that activates correctly.
293
+ @stack.reverse_each do |savepoint|
294
+ if conflicts.include?(savepoint)
295
+ debug { " -> Jumping to: #{savepoint}" }
296
+ throw savepoint
297
+ end
298
+ end
299
+ end
300
+ end
301
+ end
302
+
303
+ def resolve_requirement(spec_group, requirement, reqs, activated)
304
+ # We are going to try activating the spec. We need to keep track of stack of
305
+ # requirements that got us to the point of activating this gem.
306
+ spec_group.required_by.replace requirement.required_by
307
+ spec_group.required_by << requirement
308
+
309
+ activated[spec_group.name] = spec_group
310
+ debug { " Activating: #{spec_group.name} (#{spec_group.version})" }
311
+ debug { spec_group.required_by.map { |d| " * #{d.name} (#{d.requirement})" }.join("\n") }
312
+
313
+ dependencies = spec_group.activate_platform(requirement.__platform)
314
+
315
+ # Now, we have to loop through all child dependencies and add them to our
316
+ # array of requirements.
317
+ debug { " Dependencies"}
318
+ dependencies.each do |dep|
319
+ next if dep.type == :development
320
+ debug { " * #{dep.name} (#{dep.requirement})" }
321
+ dep.required_by.replace(requirement.required_by)
322
+ dep.required_by << requirement
323
+ reqs << dep
324
+ end
325
+
326
+ # We create a savepoint and mark it by the name of the requirement that caused
327
+ # the gem to be activated. If the activated gem ever conflicts, we are able to
328
+ # jump back to this point and try another version of the gem.
329
+ length = @stack.length
330
+ @stack << requirement.name
331
+ retval = catch(requirement.name) do
332
+ resolve(reqs, activated)
333
+ end
334
+ # Since we're doing a lot of throw / catches. A push does not necessarily match
335
+ # up to a pop. So, we simply slice the stack back to what it was before the catch
336
+ # block.
337
+ @stack.slice!(length..-1)
338
+ retval
339
+ end
340
+
341
+ def search(dep)
342
+ if base = @base[dep.name] and base.any?
343
+ d = Gem::Dependency.new(base.first.name, *[dep.requirement.as_list, base.first.version].flatten)
344
+ else
345
+ d = dep.dep
346
+ end
347
+ index = @source_requirements[d.name] || @index
348
+ results = index.search_for_all_platforms(d, @base[d.name])
349
+
350
+ if results.any?
351
+ version = results.first.version
352
+ nested = [[]]
353
+ results.each do |spec|
354
+ if spec.version != version
355
+ nested << []
356
+ version = spec.version
357
+ end
358
+ nested.last << spec
359
+ end
360
+ nested.map { |a| SpecGroup.new(a) }.select { |sg| sg.for?(dep.__platform) }
361
+ else
362
+ []
363
+ end
364
+ end
365
+
366
+ def clean_req(req)
367
+ if req.to_s.include?(">= 0")
368
+ req.to_s.gsub(/ \(.*?\)$/, '')
369
+ else
370
+ req.to_s.gsub(/\, (runtime|development)\)$/, ')')
371
+ end
372
+ end
373
+
374
+ def version_conflict
375
+ VersionConflict.new(errors.keys, error_message)
376
+ end
377
+
378
+ # For a given conflicted requirement, print out what exactly went wrong
379
+ def gem_message(requirement)
380
+ m = ""
381
+
382
+ # A requirement that is required by itself is actually in the Gemfile, and does
383
+ # not "depend on" itself
384
+ if requirement.required_by.first && requirement.required_by.first.name != requirement.name
385
+ m << " #{clean_req(requirement.required_by.first)} depends on\n"
386
+ m << " #{clean_req(requirement)}\n"
387
+ else
388
+ m << " #{clean_req(requirement)}\n"
389
+ end
390
+ m << "\n"
391
+ end
392
+
393
+ def error_message
394
+ output = errors.inject("") do |o, (conflict, (origin, requirement))|
395
+
396
+ # origin is the SpecSet of specs from the Gemfile that is conflicted with
397
+ if origin
398
+
399
+ o << %{Bundler could not find compatible versions for gem "#{origin.name}":\n}
400
+ o << " In Gemfile:\n"
401
+
402
+ o << gem_message(requirement)
403
+
404
+ # If the origin is "bundler", the conflict is us
405
+ if origin.name == "bundler"
406
+ o << " Current Bundler version:\n"
407
+ newer_bundler_required = requirement.requirement > Gem::Requirement.new(origin.version)
408
+ # If the origin is a LockfileParser, it does not respond_to :required_by
409
+ elsif !origin.respond_to?(:required_by) || !(required_by = origin.required_by.first)
410
+ o << " In snapshot (Gemfile.lock):\n"
411
+ end
412
+
413
+ o << gem_message(origin)
414
+
415
+ # If the bundle wants a newer bundler than the running bundler, explain
416
+ if origin.name == "bundler" && newer_bundler_required
417
+ o << "Your version of Bundler is older than the one requested by the Gemfile.\n"
418
+ o << "Perhaps you need to update Bundler by running `gem install bundler`."
419
+ end
420
+
421
+ # origin is nil if the required gem and version cannot be found in any of
422
+ # the specified sources
423
+ else
424
+
425
+ # if the gem cannot be found because of a version conflict between lockfile and gemfile,
426
+ # print a useful error that suggests running `bundle update`, which may fix things
427
+ #
428
+ # @base is a SpecSet of the gems in the lockfile
429
+ # conflict is the name of the gem that could not be found
430
+ if locked = @base[conflict].first
431
+ o << "Bundler could not find compatible versions for gem #{conflict.inspect}:\n"
432
+ o << " In snapshot (Gemfile.lock):\n"
433
+ o << " #{clean_req(locked)}\n\n"
434
+
435
+ o << " In Gemfile:\n"
436
+ o << gem_message(requirement)
437
+ o << "Running `bundle update` will rebuild your snapshot from scratch, using only\n"
438
+ o << "the gems in your Gemfile, which may resolve the conflict.\n"
439
+
440
+ # the rest of the time, the gem cannot be found because it does not exist in the known sources
441
+ else
442
+ if requirement.required_by.first
443
+ o << "Could not find gem '#{clean_req(requirement)}', required by '#{clean_req(requirement.required_by.first)}', in any of the sources\n"
444
+ else
445
+ o << "Could not find gem '#{clean_req(requirement)} in any of the sources\n"
446
+ end
447
+ end
448
+
449
+ end
450
+ o
451
+ end
452
+ end
453
+ end
454
+ end