forked from sproutit/sproutcore-abbot
-
Notifications
You must be signed in to change notification settings - Fork 1
/
manifest.rake
516 lines (427 loc) · 18.5 KB
/
manifest.rake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
# ===========================================================================
# SC::Manifest Buildtasks
# copyright 2008, Sprout Systems, Inc. and Apple Inc. all rights reserved
# ===========================================================================
# Tasks invoked while building Manifest objects. You can override these
# tasks in your buildfiles.
namespace :manifest do
desc "Invoked just before a manifest object is built to setup standard properties"
task :prepare do
require 'tempfile'
# make sure a language was set
MANIFEST.language ||= :en
# build_root is target.build_root + language + build_number
MANIFEST.build_root = File.join(TARGET.build_root,
MANIFEST.language.to_s, TARGET.build_number.to_s)
# staging_root is target.staging_root + language + build_number
MANIFEST.staging_root = File.join(TARGET.staging_root,
MANIFEST.language.to_s, TARGET.build_number.to_s)
# cache_root is target.cache_root + language + build_number
MANIFEST.cache_root = File.join(TARGET.cache_root,
MANIFEST.language.to_s, TARGET.build_number.to_s)
# url_root
MANIFEST.url_root =
[TARGET.url_root, MANIFEST.language, TARGET.build_number].join('/')
# index_root
MANIFEST.index_root =
[TARGET.index_root, MANIFEST.language, TARGET.build_number].join('/')
# source_root
MANIFEST.source_root = TARGET.source_root
end
desc "Actually builds a manifest. This will catalog all entries and then filter them"
task :build => %w(catalog hide_buildfiles localize prepare_build_tasks:all)
desc "first step in building a manifest, this adds a simple copy file entry for every file in the source"
task :catalog do |t|
source_root = TARGET.source_root
Dir.glob(File.join(source_root, '**', '*')).each do |path|
next if !File.exist?(path) || File.directory?(path)
next if TARGET.target_directory?(path)
# cut source root out to make filename. make sure path separators are /
filename = path.sub /^#{Regexp.escape source_root}\//, ''
filename = filename.split(::File::SEPARATOR).join('/')
MANIFEST.add_entry filename, :original => true # entry:prepare will fill in the rest
end
end
desc "hides structural files that do not belong in build include Buildfiles and debug or fixtures if turned off"
task :hide_buildfiles => :catalog do
# these directories are to be excluded unless CONFIG.load_"dirname" = true
dirnames = %w(debug tests fixtures protocols).reject do |k|
CONFIG["load_#{k}"]
end
# loop through entries and hide those that do not below...
MANIFEST.entries.each do |entry|
# if in /dirname or /foo.lproj/dirname -- hide it!
dirnames.each do |dirname|
if entry.filename =~ /^(([^\/]+)\.lproj\/)?#{dirname}\/.+$/
entry.hide!
next
end
end
# otherwise, allow if inside lproj
next if entry.localized? || entry.filename =~ /^.+\.lproj\/.+$/
# allow if in tests, fixtures or debug as well...
next if entry.filename =~ /^(tests|fixtures|debug|protocols)\/.+$/
# or skip if ext not js
entry.hide! if entry.ext != 'js'
end
end
desc "localizes files. reject any files from other languages"
task :localize => [:catalog, :hide_buildfiles] do
seen = {} # already seen entries...
preferred_language = TARGET.config.preferred_language || :en
MANIFEST.entries.each do |entry|
# Is a localized resource!
if entry.filename =~ /^([^\/]+)\.lproj\/(.+)$/
entry.language = (SC::Target::LONG_LANGUAGE_MAP[$1.to_s.downcase.to_sym]) || $1.to_sym
entry.localized = true
# remove .lproj dir from build paths as well..
lang_dir = "#{$1}.lproj/"
sub_str = (entry.ext == 'js') ? 'lproj/' : ''
entry.filename = entry.filename.sub(lang_dir, sub_str)
entry.build_path = entry.build_path.sub(lang_dir, sub_str)
entry.url = entry.url.sub(lang_dir, sub_str)
# if this is part of the current language, always include...
# hide any preferred_language entry...
if entry.language == MANIFEST.language
seen[entry.filename].hide! if seen[entry.filename]
# if this is a preferred_language, hide unless we've seen one
elsif entry.language == preferred_language
if seen[entry.filename]
entry.hide!
else
seen[entry.filename] = entry
end
# Otherwise, hide it...
else
entry.hide!
end
# Not a localized resource
else
entry.language = MANIFEST.language
entry.localized = false
end
end
end
namespace :prepare_build_tasks do
desc "main entrypoint for preparing all build tasks. This should invoke all needed tasks"
task :all => %w(css javascript sass combine minify html strings tests packed)
desc "executes prerequisites needed before one of the subtasks can be invoked. All subtasks that have this as a prereq"
task :setup => %w(manifest:catalog manifest:hide_buildfiles manifest:localize)
desc "create builder tasks for all unit tests based on file extension."
task :tests => :setup do
# Generate test entries
test_entries = []
entries_by_dirname = {} # for building composites...
MANIFEST.entries.each do |entry|
next unless entry.filename =~ /^tests\//
# if this is a js file, add js transform first to handle sc_static()
# etc.
if entry.ext == 'js'
entry = MANIFEST.add_transform entry,
:build_task => 'build:javascript'
end
# Add transform to build into test.
test_entries << MANIFEST.add_transform(entry,
:build_task => "build:test",
:entry_type => :test,
:ext => :html)
# Strip off dirnames, saving each by dirname...
dirname = entry.filename
while (dirname = dirname.sub(/\/?[^\/]+$/,'')).size > 0
(entries_by_dirname[dirname] ||= []) << entry
end
end
# Generate composite entries for each directory...
entries_by_dirname.each do |dirname, entries|
filename = "#{dirname}.html"
MANIFEST.add_composite filename,
:build_task => "build:test",
:entry_type => :test,
:ext => :html,
:source_entries => entries,
:hide_entries => false
end
# Add summary entry
if CONFIG.load_tests
MANIFEST.add_entry 'tests/-index.json',
:composite => true,
:source_entries => test_entries,
:build_task => 'build:test_index',
:entry_type => :resource
end
end
task :javascript => :tests # IMPORTANT! to avoid JS including unit tests.
task :html => :tests # IMPORTANT! to avoid HTML including tests
desc "scans for javascript files, annotates them and prepares combined entries for each output target"
task :javascript => :setup do
# select all original entries with with ext of css
entries = MANIFEST.entries.select do |e|
e.original? && e.ext == 'js'
end
# add transform & tag with build directives.
entries.each do |entry|
entry = MANIFEST.add_transform entry,
:filename => ['source', entry.filename].join('/'),
:build_path => File.join(MANIFEST.build_root, 'source', entry.filename),
:url => [MANIFEST.url_root, 'source', entry.filename].join("/"),
:build_task => 'build:javascript',
:resource => 'javascript',
:entry_type => :javascript
entry.discover_build_directives!
end
end
desc "scans for css files, creates a transform and annotates them"
task :css => :setup do
# select all original entries with with ext of css
entries = MANIFEST.entries.select do |e|
e.original? && e.ext == 'css'
end
# add transform & tag with build directives.
entries.each do |entry|
entry = MANIFEST.add_transform entry,
:filename => ['source', entry.filename].join('/'),
:build_path => File.join(MANIFEST.build_root, 'source', entry.filename),
:url => [MANIFEST.url_root, 'source', entry.filename].join("/"),
:build_task => 'build:css',
:resource => 'stylesheet',
:entry_type => :css
entry.discover_build_directives!
end
end
desc "generates combined entries for javascript and css"
task :combine => %w(setup css javascript sass) do
# sort entries...
css_entries = {}
javascript_entries = {}
MANIFEST.entries.each do |entry|
# we can only combine entries with a resource property.
next if entry.resource.nil?
# look for CSS or JS type entries
case entry.entry_type
when :css
(css_entries[entry.resource] ||= []) << entry
when :javascript
(javascript_entries[entry.resource] ||= []) << entry
end
end
# build combined CSS entry
css_entries.each do |resource_name, entries|
MANIFEST.add_composite resource_name.ext('css'),
:build_task => 'build:combine',
:source_entries => entries,
:hide_entries => CONFIG.combine_stylesheets,
:ordered_entries => SC::Helpers::EntrySorter.sort(entries),
:entry_type => :css,
:combined => true
end
# build combined JS entry
javascript_entries.each do |resource_name, entries|
resource_name = resource_name.ext('js')
pf = (resource_name == 'javascript.js') ? %w(source/lproj/strings.js source/core.js source/utils.js) : []
MANIFEST.add_composite resource_name,
:build_task => 'build:combine',
:source_entries => entries,
:hide_entries => CONFIG.combine_javascript,
:ordered_entries => SC::Helpers::EntrySorter.sort(entries, pf),
:entry_type => :javascript,
:combined => true
end
end
desc "adds a packed entry including javascript.js from required targets"
task :packed => %w(setup combine) do
# don't add packed entries for apps.
if TARGET.target_type != :app
# Handle JavaScript version. get all required targets and find their
# javascript.js. Build packed js from that.
targets = TARGET.expand_required_targets + [TARGET]
entries = targets.map do |target|
m = target.manifest_for(MANIFEST.variation).build!
# need to find the version that is not minified
entry = m.entry_for('javascript.js')
entry = entry.source_entry while entry && entry.minified?
entry
end
entries.compact!
MANIFEST.add_composite 'javascript-packed.js',
:build_task => 'build:combine',
:source_entries => entries,
:hide_entries => false,
:entry_type => :javascript,
:combined => true,
:ordered_entries => entries, # orderd by load order
:targets => targets,
:packed => true
end
end
task :minify => :packed # IMPORTANT: don't want minified version
desc "adds a packed entry including stylesheet.css from required targets"
task :packed => %w(setup combine) do
# don't add packed entries for apps.
if TARGET.target_type != :app
# Handle CSS version. get all required targets and find their
# stylesheet.css. Build packed css from that.
targets = TARGET.expand_required_targets + [TARGET]
entries = targets.map do |target|
m = target.manifest_for(MANIFEST.variation).build!
# need to find the version that is not minified
entry = m.entry_for('stylesheet.css')
entry = entry.source_entry while entry && entry.minified?
entry
end
entries.compact!
MANIFEST.add_composite 'stylesheet-packed.css',
:build_task => 'build:combine',
:source_entries => entries,
:hide_entries => false,
:entry_type => :css,
:combined => true,
:ordered_entries => entries, # orderd by load order
:targets => targets,
:packed => true
end
end
task :minify => :packed # IMPORTANT: don't want minified version
desc "create a builder task for all sass files to create css files"
task :sass => :setup do
MANIFEST.entries.each do |entry|
next unless entry.ext == "sass"
MANIFEST.add_transform entry,
:filename => ['source', entry.filename].join('/'),
:build_path => File.join(MANIFEST.build_root, 'source', entry.filename),
:url => [MANIFEST.url_root, 'source', entry.filename].join("/"),
:build_task => 'build:sass',
:entry_type => :css,
:ext => 'css',
:resource => 'stylesheet',
:required => []
end
end
desc "find all html-generating files, annotate and combine them"
task :html => :setup do
# select all entries with proper extensions
known_ext = %w(rhtml erb haml)
entries = MANIFEST.entries.select do |e|
(e.entry_type == :html) || (e.entry_type.nil? && known_ext.include?(e.ext))
end
# tag entry with build directives and sort by resource
entries_by_resource = {}
entries.each do |entry|
entry.entry_type = :html
entry.resource = 'index'
entry.render_task = case entry.ext
when 'rhtml':
'render:erubis'
when 'erb':
"render:erubis"
when 'haml':
'render:haml'
end
# items beginning with an underscore are partials. do not build
if entry.filename =~ /^_/
entry.hide!
entry.is_partial = true
# not a partial
else
# use a custom scan method since discover_build_directives! is too
# general...
entry.scan_source(/<%\s*sc_resource\(?\s*['"](.+)['"]\s*\)?/) do |m|
entry.resource = m[0].ext ''
end
(entries_by_resource[entry.resource] ||= []) << entry
end
end
# even if no resource was found for the index.html, add one anyway if
# the target is loadable
if TARGET.loadable? && entries_by_resource['index'].nil?
entries_by_resource['index'] = []
end
# Now, build combined entry for each resource
entries_by_resource.each do |resource_name, entries|
resource_name = resource_name.ext('html')
is_index = resource_name == 'index.html'
# compute the friendly_url assuming normal install process
friendly_url = [TARGET.index_root]
m_language = MANIFEST.language.to_sym
t_preferred = (TARGET.config.preferred_language || :en).to_sym
if is_index
friendly_url << m_language.to_s unless t_preferred == m_language
else
friendly_url << m_language.to_s
friendly_url << resource_name
end
friendly_url = friendly_url.join('/')
is_pref_lang = (MANIFEST.language == CONFIG.preferred_language)
is_hidden = !TARGET.loadable? && is_index
overwrite_current = CONFIG.overwrite_current
# index.html entries get generated three times. Once for inside the
# build dir, once for the language and once for the entire target name
# Note that you must generate an index.html entry for all three even
# if you won't actually use it because other index.html entries may
# reference it
(is_index ? 3 : 1).times do |rep_cnt|
MANIFEST.add_composite resource_name,
:entry_type => :html,
:combined => true,
:build_task => 'build:html',
:source_entries => entries, # make independent
:hidden => is_hidden,
:include_required_targets => TARGET.loadable? && is_index,
:friendly_url => friendly_url,
:is_index => is_index
# if this is the index, setup next rep
if is_index
resource_name = File.join('..', resource_name)
is_hidden = true if !TARGET.loadable? || !overwrite_current
is_hidden = true if (rep_cnt>=2) && !is_pref_lang
end
end
end
end
desc "creates transform entries for all css and Js entries to minify them if needed"
task :minify => %w(setup javascript css combine sass) do
minify_css = CONFIG.minify_css
minify_css = CONFIG.minify if minify_css.nil?
minify_javascript = CONFIG.minify_javascript
minify_javascript = CONFIG.minify if minify_javascript.nil?
MANIFEST.entries.dup.each do |entry|
case entry.entry_type
when :css
if minify_css
MANIFEST.add_transform entry,
:build_task => 'build:minify:css',
:entry_type => :css,
:minified => true,
:packed => entry.packed? # carry forward
end
when :javascript
if minify_javascript
MANIFEST.add_transform entry,
:build_task => 'build:minify:javascript',
:entry_type => :javascript,
:minified => true,
:packed => entry.packed? # carry forward
end
end
end
end
desc "adds a loc strings entry that generates a yaml file server-side functions can use"
task :strings => %w(setup javascript) do
# find the lproj/strings.js file...
if entry = (MANIFEST.entry_for('source/lproj/strings.js') || MANIFEST.entry_for('source/lproj/strings.js', :hidden => true))
MANIFEST.add_transform entry,
:filename => 'strings.yaml',
:build_path => File.join(MANIFEST.build_root, 'strings.yaml'),
:staging_path => File.join(MANIFEST.staging_root, 'strings.yaml'),
:url => [MANIFEST.url_root, 'strings.yaml'].join('/'),
:build_task => 'build:strings',
:ext => 'yaml',
:entry_type => :strings,
:hide_entry => false,
:hidden => true
end
end
desc "..."
task :image => :setup do
end
end
end