sprout 0.7.236-x86-darwin-10 → 0.7.237-x86-darwin-10

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sprout.rb CHANGED
@@ -29,6 +29,7 @@ require 'sprout/archive_unpacker'
29
29
  require 'sprout/remote_file_target'
30
30
  require 'sprout/simple_resolver'
31
31
  # require 'sprout/template_resolver'
32
+ require 'sprout/bundle_resolver'
32
33
 
33
34
  require 'rubygems/installer'
34
35
  require 'rubygems/source_info_cache'
@@ -0,0 +1,349 @@
1
+ # Taken from http://github.com/carlhuda/bundler
2
+ module Gem
3
+ class Dependency
4
+ def required_by
5
+ @required_by ||= []
6
+ end
7
+ end
8
+ class Specification
9
+ def required_by
10
+ @required_by ||= []
11
+ end
12
+ end
13
+ end
14
+
15
+ module Sprout
16
+
17
+ class Index
18
+ def self.from_installed_gems
19
+ #Source::SystemGems.new.specs
20
+ index = Index.new
21
+ Gem::cache.each do |name, spec|
22
+ index << spec
23
+ end
24
+ index
25
+ end
26
+
27
+ def self.from_cached_specs(path)
28
+ # index = Index.new
29
+ # Sprout::cache
30
+ # Dir["#{path}/*.gem"].each do |gemfile|
31
+ # spec = Gem::Format.from_file_by_path(gemfile).spec
32
+ # index << spec
33
+ # end
34
+
35
+ # index
36
+ end
37
+
38
+ def initialize
39
+ @cache = {}
40
+ @specs = Hash.new { |h,k| h[k] = [] }
41
+ end
42
+
43
+ def initialize_copy(o)
44
+ super
45
+ @cache = {}
46
+ @specs = Hash.new { |h,k| h[k] = [] }
47
+ merge!(o)
48
+ end
49
+
50
+ def empty?
51
+ each { return false }
52
+ true
53
+ end
54
+
55
+ def search(query)
56
+ case query
57
+ when Gem::Specification then search_by_spec(query)
58
+ when String then @specs[query]
59
+ else search_by_dependency(query)
60
+ end
61
+ end
62
+
63
+ alias [] search
64
+
65
+ def <<(spec)
66
+ arr = @specs[spec.name]
67
+
68
+ arr.delete_if do |s|
69
+ s.version == spec.version && s.platform == spec.platform
70
+ end
71
+
72
+ arr << spec
73
+ spec
74
+ end
75
+
76
+ def each(&blk)
77
+ @specs.values.each do |specs|
78
+ specs.each(&blk)
79
+ end
80
+ end
81
+
82
+ def merge!(other)
83
+ other.each do |spec|
84
+ self << spec
85
+ end
86
+ self
87
+ end
88
+
89
+ def merge(other)
90
+ dup.merge!(other)
91
+ end
92
+
93
+ def freeze
94
+ @specs.each do |k,v|
95
+ v.freeze
96
+ end
97
+ super
98
+ end
99
+
100
+ private
101
+
102
+ def search_by_spec(spec)
103
+ @specs[spec.name].select { |s| s.version == spec.version }
104
+ end
105
+
106
+ def search_by_dependency(dependency)
107
+ @cache[dependency.hash] ||= begin
108
+ specs = @specs[dependency.name]
109
+
110
+ #wants_prerelease = dependency.requirement.prerelease?
111
+ #only_prerelease = specs.all? {|spec| spec.version.prerelease? }
112
+ found = specs.select { |spec| dependency =~ spec }
113
+
114
+ #unless wants_prerelease || only_prerelease
115
+ # found.reject! { |spec| spec.version.prerelease? }
116
+ #end
117
+
118
+ found.sort_by {|s| [s.version, s.platform.to_s == 'ruby' ? "\\0" : s.platform.to_s] }
119
+ end
120
+
121
+ end
122
+
123
+ end
124
+
125
+ class Resolver
126
+ attr_reader :errors
127
+
128
+ # Figures out the best possible configuration of gems that satisfies
129
+ # the list of passed dependencies and any child dependencies without
130
+ # causing any gem activation errors.
131
+ #
132
+ # ==== Parameters
133
+ # *dependencies<Gem::Dependency>:: The list of dependencies to resolve
134
+ #
135
+ # ==== Returns
136
+ # <GemBundle>,nil:: If the list of dependencies can be resolved, a
137
+ # collection of gemspecs is returned. Otherwise, nil is returned.
138
+ def self.resolve(requirements, index, source_requirements = {})
139
+ resolver = new(index, source_requirements)
140
+ result = catch(:success) do
141
+ resolver.resolve(requirements, {})
142
+ output = resolver.errors.inject("") do |o, (conflict, (origin, requirement))|
143
+ if origin
144
+ o << " Conflict on: #{conflict.inspect}:\\n"
145
+ o << " * #{conflict} (#{origin.version}) activated by #{origin.required_by.first}\\n"
146
+ o << " * #{requirement} required by #{requirement.required_by.first}\\n"
147
+ else
148
+ o << " #{requirement} not found in any of the sources\\n"
149
+ o << " required by #{requirement.required_by.first}\\n"
150
+ end
151
+ o << " All possible versions of origin requirements conflict."
152
+ end
153
+ raise VersionConflict, "No compatible versions could be found for required dependencies:\\n #{output}"
154
+ nil
155
+ end
156
+ if result
157
+ # Order gems in order of dependencies. Every gem's dependency is at
158
+ # a smaller index in the array.
159
+ ordered = []
160
+ result.values.each do |spec1|
161
+ index = nil
162
+ place = ordered.detect do |spec2|
163
+ spec1.dependencies.any? { |d| d.name == spec2.name }
164
+ end
165
+ place ?
166
+ ordered.insert(ordered.index(place), spec1) :
167
+ ordered << spec1
168
+ end
169
+ ordered.reverse
170
+ end
171
+ end
172
+
173
+ def self.resolve_libraries(library_names)
174
+ index = Index.from_installed_gems
175
+ lib_specs = library_names.map {|lib| Sprout.find_gem_spec "sprout-#{lib}-library" }
176
+ resolved_specs = resolve lib_specs, index
177
+ library_names_with_dependencies = []
178
+ resolved_specs.each do |l|
179
+ if l.name =~ /\Asprout-(.*)-library\Z/
180
+ library_names_with_dependencies << $1
181
+ end
182
+ end
183
+ library_names_with_dependencies
184
+ end
185
+
186
+ def initialize(index, source_requirements)
187
+ @errors = {}
188
+ @stack = []
189
+ @index = index
190
+ @source_requirements = source_requirements
191
+ end
192
+
193
+ def debug
194
+ puts yield if defined?($debug) && $debug
195
+ end
196
+
197
+ def resolve(reqs, activated)
198
+ # If the requirements are empty, then we are in a success state. Aka, all
199
+ # gem dependencies have been resolved.
200
+ throw :success, activated if reqs.empty?
201
+
202
+ debug { STDIN.gets ; print "\\e[2J\\e[f" ; "==== Iterating ====\\n\\n" }
203
+
204
+ # Sort dependencies so that the ones that are easiest to resolve are first.
205
+ # Easiest to resolve is defined by:
206
+ # 1) Is this gem already activated?
207
+ # 2) Do the version requirements include prereleased gems?
208
+ # 3) Sort by number of gems available in the source.
209
+ reqs = reqs.sort_by do |a|
210
+ [ activated[a.name] ? 0 : 1,
211
+ #a.requirement.prerelease? ? 0 : 1,
212
+ @errors[a.name] ? 0 : 1,
213
+ activated[a.name] ? 0 : search(a).size ]
214
+ end
215
+
216
+ debug { "Activated:\\n" + activated.values.map { |a| " #{a.name} (#{a.version})" }.join("\\n") }
217
+ debug { "Requirements:\\n" + reqs.map { |r| " #{r.name} (#{r.requirement})"}.join("\\n") }
218
+
219
+ activated = activated.dup
220
+ # Pull off the first requirement so that we can resolve it
221
+ current = reqs.shift
222
+
223
+ debug { "Attempting:\\n #{current.name} (#{current.requirement})"}
224
+
225
+ # Check if the gem has already been activated, if it has, we will make sure
226
+ # that the currently activated gem satisfies the requirement.
227
+ if existing = activated[current.name]
228
+ if current.requirement.satisfied_by?(existing.version)
229
+ debug { " * [SUCCESS] Already activated" }
230
+ @errors.delete(existing.name)
231
+ # Since the current requirement is satisfied, we can continue resolving
232
+ # the remaining requirements.
233
+ resolve(reqs, activated)
234
+ else
235
+ debug { " * [FAIL] Already activated" }
236
+ @errors[existing.name] = [existing, current]
237
+ debug { current.required_by.map {|d| " * #{d.name} (#{d.requirement})" }.join("\\n") }
238
+ # debug { " * All current conflicts:\\n" + @errors.keys.map { |c| " - #{c}" }.join("\\n") }
239
+ # Since the current requirement conflicts with an activated gem, we need
240
+ # to backtrack to the current requirement's parent and try another version
241
+ # of it (maybe the current requirement won't be present anymore). If the
242
+ # current requirement is a root level requirement, we need to jump back to
243
+ # where the conflicting gem was activated.
244
+ parent = current.required_by.last || existing.required_by.last
245
+ # We track the spot where the current gem was activated because we need
246
+ # to keep a list of every spot a failure happened.
247
+ debug { " -> Jumping to: #{parent.name}" }
248
+ throw parent.name, existing.required_by.last.name
249
+ end
250
+ else
251
+ # There are no activated gems for the current requirement, so we are going
252
+ # to find all gems that match the current requirement and try them in decending
253
+ # order. We also need to keep a set of all conflicts that happen while trying
254
+ # this gem. This is so that if no versions work, we can figure out the best
255
+ # place to backtrack to.
256
+ conflicts = Set.new
257
+
258
+ # Fetch all gem versions matching the requirement
259
+ #
260
+ # TODO: Warn / error when no matching versions are found.
261
+ matching_versions = search(current)
262
+
263
+ if matching_versions.empty?
264
+ if current.required_by.empty?
265
+ if current.source
266
+ name = current.name
267
+ versions = @source_requirements[name][name].map { |s| s.version }
268
+ message = "Could not find gem '#{current}' in #{current.source}.\\n"
269
+ if versions.any?
270
+ message << "Source contains '#{current.name}' at: #{versions.join(', ')}"
271
+ else
272
+ message << "Source does not contain any versions of '#{current}'"
273
+ end
274
+
275
+ raise GemNotFound, message
276
+ else
277
+ raise GemNotFound, "Could not find gem '#{current}' in any of the sources."
278
+ end
279
+ location = current.source ? current.source.to_s : "any of the sources"
280
+ raise GemNotFound, "Could not find gem '#{current}' in #{location}.\\n"
281
+ else
282
+ @errors[current.name] = [nil, current]
283
+ end
284
+ end
285
+
286
+ matching_versions.reverse_each do |spec|
287
+ conflict = resolve_requirement(spec, current, reqs.dup, activated.dup)
288
+ conflicts << conflict if conflict
289
+ end
290
+ # If the current requirement is a root level gem and we have conflicts, we
291
+ # can figure out the best spot to backtrack to.
292
+ if current.required_by.empty? && !conflicts.empty?
293
+ # Check the current "catch" stack for the first one that is included in the
294
+ # conflicts set. That is where the parent of the conflicting gem was required.
295
+ # By jumping back to this spot, we can try other version of the parent of
296
+ # the conflicting gem, hopefully finding a combination that activates correctly.
297
+ @stack.reverse_each do |savepoint|
298
+ if conflicts.include?(savepoint)
299
+ debug { " -> Jumping to: #{savepoint}" }
300
+ throw savepoint
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+ def resolve_requirement(spec, requirement, reqs, activated)
308
+ # We are going to try activating the spec. We need to keep track of stack of
309
+ # requirements that got us to the point of activating this gem.
310
+ spec.required_by.replace requirement.required_by
311
+ spec.required_by << requirement
312
+
313
+ activated[spec.name] = spec
314
+ debug { " Activating: #{spec.name} (#{spec.version})" }
315
+ debug { spec.required_by.map { |d| " * #{d.name} (#{d.requirement})" }.join("\\n") }
316
+
317
+ # Now, we have to loop through all child dependencies and add them to our
318
+ # array of requirements.
319
+ debug { " Dependencies"}
320
+ spec.dependencies.each do |dep|
321
+ next if dep.type == :development
322
+ debug { " * #{dep.name} (#{dep.requirement})" }
323
+ dep.required_by.replace(requirement.required_by)
324
+ dep.required_by << requirement
325
+ reqs << dep
326
+ end
327
+
328
+ # We create a savepoint and mark it by the name of the requirement that caused
329
+ # the gem to be activated. If the activated gem ever conflicts, we are able to
330
+ # jump back to this point and try another version of the gem.
331
+ length = @stack.length
332
+ @stack << requirement.name
333
+ retval = catch(requirement.name) do
334
+ resolve(reqs, activated)
335
+ end
336
+ # Since we're doing a lot of throw / catches. A push does not necessarily match
337
+ # up to a pop. So, we simply slice the stack back to what it was before the catch
338
+ # block.
339
+ @stack.slice!(length..-1)
340
+ retval
341
+ end
342
+
343
+ def search(dep)
344
+ index = @source_requirements[dep.name] || @index
345
+ index.search(dep)
346
+ end
347
+
348
+ end
349
+ end
@@ -63,6 +63,10 @@ module Sprout
63
63
  # archive_path: flickr-.87/src
64
64
  # EOF
65
65
  attr_writer :sprout_spec
66
+ # An array of library names this sprout depends on.
67
+ # Each will be expanded to sprout-[library-name]-library
68
+ # and resolved at compile stage
69
+ attr_writer :libraries
66
70
 
67
71
  def self.define_task(args, &block)
68
72
  t = super
@@ -110,6 +114,10 @@ module Sprout
110
114
  gem_dependencies.each do |dep|
111
115
  s.requirements << dep
112
116
  end
117
+ libraries.each do |l|
118
+ puts "Adding #{l} to gem dependencies"
119
+ s.add_dependency("sprout-#{l}-library", ">= 0.0.0")
120
+ end
113
121
 
114
122
  sprout_requirement = s.requirements.collect do |req|
115
123
  (req[0] == 'sprout')
@@ -157,6 +165,10 @@ module Sprout
157
165
  return @extensions ||= []
158
166
  end
159
167
 
168
+ def libraries
169
+ @libraries ||= []
170
+ end
171
+
160
172
  private
161
173
 
162
174
  def gem_package
@@ -3,7 +3,7 @@ module Sprout
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 0
5
5
  MINOR = 7
6
- TINY = 236
6
+ TINY = 237
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
9
9
  MAJOR_MINOR = [MAJOR, MINOR].join('.')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.236
4
+ version: 0.7.237
5
5
  platform: x86-darwin-10
6
6
  authors:
7
7
  - Luke Bayes
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-03-03 00:00:00 -08:00
12
+ date: 2010-03-10 00:00:00 -08:00
13
13
  default_executable: sprout
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -101,6 +101,7 @@ files:
101
101
  - lib/progress_bar.rb
102
102
  - lib/sprout/archive_unpacker.rb
103
103
  - lib/sprout/builder.rb
104
+ - lib/sprout/bundle_resolver.rb
104
105
  - lib/sprout/commands/generate.rb
105
106
  - lib/sprout/dynamic_accessors.rb
106
107
  - lib/sprout/general_tasks.rb