forked from FOSDEM/website
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Rules
544 lines (470 loc) · 18 KB
/
Rules
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
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
#!/usr/bin/env ruby
# vim: set ts=2 sw=2 et ai ft=ruby:
# encoding: UTF-8
#
# fosdem.org nanoc configuration
#
# Original version: 2012-06-05 by Pascal Bleser <[email protected]>
# Questions -> [email protected]
# Documentation -> http://nanoc.stoneship.org/docs/
#
# Copyright (c) 2012 FOSDEM VZW
# See the LICENSE file this this repository for licensing terms.
#
##### PREPROCESSING
preprocess do
# Check for presence of export file first:
begin
f = config.fetch(:pentabarf).fetch(:meta_export_file)
unless File.exists? f
# ... and fail if it doesn't exist
fail "Failed to find schedule metadata export file #{f}#{$/}Did you run \"nanoc update -y\" ?"
end
end
# Determine the prefix for output paths and absolute links by using either
# the "config" setting in config.yaml, if present, or, better, determine it
# automatically from the schedule information that is exported from Pentabarf,
# by looking up the first conference day and using the year as the prefix.
# Note that this must be done as the *FIRST* thing in the preprocessing, as
# we reference that $prefix global variable in a lot of places (for performance
# reasons, rather than looking it up each time):
$prefix ||= begin
if config[:prefix]
config[:prefix]
else
# search the first day item
first_day = begin
d = @items.select { |i| i.identifier =~ %r{^/schedule/day/[^/]+/$} }.sort_by { |d| d[:conference_day] }.first
raise "failed to find item with identifier /schedule/day/..." unless d
d[:conference_day]
end
# the prefix of the site is the year
"/" + first_day.year.to_s
end
end
### CREATE ITEMS
# Create some items programmatically
# clone items that have "aliases: foo, bar, spam" in their metadata
make_aliases
# create /headline/... items from content/news/*
make_headlines
make_newspages
# auto-set the title of content/interviews/*
#decorate_interviews
# duplicate favicon.ico to also deploy it under output/ and not just
# under e.g. output/2013/
begin
favicon = @items.select { |i| i.identifier == '/favicon/' }.first
if favicon
@items << dup_item(favicon, '/root_favicon/')
else
raise "no favicon!"
end
end
### DO NOT CREATE ANY ITEMS BELOW THIS LINE #######################################################
# As we are collecting, caching, optimizing...
# build a global hash of items by their identifier, much faster for lookups
# than having to run over all of them; needs to be a global variable
$item_by_id = {}
@items.each do |item|
raise "duplicate identifier #{item.identifier}" if $item_by_id.has_key? item.identifier
$item_by_id[item.identifier] = item
end
# performance hack:
# All the schedule/ pages have the same navigation and, hence, we're going
# to create a single item where it is rendered once
# (see content/schedule_navigation.erb)
# and cache the reference to that item using a global variable
# $schedule_navigation_item to also avoid having to run through
# all items to find it.
# That $schedule_navigation_item is referenced and used in
# layouts/default.html
#$schedule_navigation_item = $item_by_id.fetch('/schedule_navigation/')
# and the same for the sponsors block
# (this optimization actually reduces rendering time from 4min to 30sec)
#$sponsors_navigation_item = $item_by_id.fetch('/sponsors_navigation/')
# compute the timetables once and cache them, they're used in a few places
# (put this rule *after* computing $item_by_id as we are using $item_by_id
# in that helper function)
$timetable = timetable_from_items(@items)
$track_flatlist = timetable_to_track_cells($timetable, true)
$event_flatlist = timetable_to_event_cells($timetable, true)
# compute room to building associations programmatically and using
# the metadata in content/buildings.yaml
# (note that the ranking/order of buildings also stems from the order
# of buildings as defined in content/buildings.yaml
# (defined in lib/helpers/schedule_helpers.rb)
$buildings, $room_to_building = build_room_buildings()
$colors, $colormap = begin
c = config.fetch(:colors)
list = case c
when String
c.split /\s+/
when Array
c
else
raise "invalid type for config.colors: #{c.class}"
end
result = []
map = {}
list.each_with_index do |color, index|
css = "c#{index + 1}"
result << css
map[css] = '#' + color
end
[result, map]
end
end
##### COMPILING
### CSS STYLESHEETS
# skip those, as they are combined into content/assets/style/fosdem.css
compile '/assets/style/parts/*' do
filter :erb
end
# route them into oblivion, as we will only deploy the aggregated
# CSS file:
route '/assets/style/parts/*' do; end
compile '/assets/style/sprite/' do
filter :erb
end
compile '/assets/style/*' do
# merge all content/assets/style/parts/*.css files into one
# in content/assets/style/*.css (see the ERB/ruby code there)
# in order to optimize web browser performance (less HTTP
# round-trips), see
# http://userprimary.net/posts/2011/01/10/optimizing-nanoc-based-websites/
# for inspiration
unless item.binary?
case item[:extension]
when 'css'
# process those using ERB:
filter :erb
# fix url() links in CSS:
filter :csslinks
# then relativize any resource paths (to images and such):
filter :relativize_paths, :type => :css
# minimize CSS files:
filter :rainpress if @site.config.fetch(:minify_css, true)
end
end
end
### NAVIGATION
# We only use the /navigation/ item (content/navigation.yaml)
# internally and don't render it to the website as a file, hence
# short-circuit any compilation and routing right here:
compile '/navigation/' do; end
route '/navigation/' do; end
# Same applies to /buildings/:
compile '/buildings/' do; end
route '/buildings/' do; end
### NEWS AND HEADLINES
# don't apply any filters on the headlines/* items as they are already
# rendered by the "make_headlines" helper at preprocessing stage
# (they do not exist in the filesystem under content/ -- instead, they
# are items that are created on-the-fly as headlines from content/news/*)
#compile '/headlines/*' do
# filter :erb
#end
# don't modify anything on attachments
compile '/schedule/event/*/attachments/*' do; end
compile '/schedule/event/*/logo/' do; end
compile '/schedule/speaker/*/photo/' do; end
compile '/schedule/speaker/*/thumbnail/' do; end
### Schedule PDF grids
# handling is a bit special here, as they go through a specific
# layout
compile '/schedule/pdf/*' do
if @site.config.fetch(:pdf_grid)
filter :erb
layout "/schedule/pdf_grid/"
end
end
route '/schedule/pdf/*' do
suffix = if @site.config[:digest_pdfs] then
"-#{digest item}"
else
""
end
"#{$prefix}/schedule/pdf/#{item[:page_size].to_s.downcase}#{suffix}.pdf"
end
### Searcher layout
# don't run any filters on this one
compile '/searcherview/' do
layout 'main'
end
### EVERYTHING ELSE (real content)
compile '*' do
if item.binary?
# don’t filter binary items
else
case item.identifier
when %r{^/news/(\d+/)?$}
layout "/news/"
when %r{^/schedule/devrooms/.+}
when %r{^/schedule/([^/]+)/.+}
# process schedule items with their respective template from layouts/schedule/
# (e.g. /schedule/event/foo is processed with layouts/schedule/event.*)
layout "/schedule/#{$1}/"
end
# process <% ERB %> templating
# http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html
filter :erb
# only run the chain of filters when it's not an .xml or .erb or .ics file
unless ['xml', 'erb', 'ics'].include? item[:extension] then
# don't process content that is generated from Pentabarf, or content
# pages that have "kind: internal" in their metadata
unless item.identifier =~ %r{^/schedule/.+} or item[:kind] == 'internal'
# run the custom news filter (lib/filters/news_filter.rb) on
# content/news/* -- it removes "---MORE---" lines and removes
# from the beginning of the content until "---FULL---" lines
# (analog to the make_headlines function from lib/helpers/news.rb
# which does the "opposite" (kindof) to generate headline items)
filter :news if news?(item)
# convert .md and .markdown files to HTML using the
# kramdown processor
filter :kramdown if ['markdown', 'md'].include? item[:extension]
# run the custom interview filter (lib/filters/interview_filter.rb)
# on content/interviews/* -- it adds a CC license footer and
# converts "Q: ..." lines to styled HTML markup
filter :interview if interview?(item)
# do the same as above for items that have "qa: true" in their
# metadata, but without adding the license footer
filter :interview, { :nolicense => true } if item[:filter] == 'qa'
filter :toc if item[:toc] == true
filter :semantic if item[:semantic] == true
# run the custom pagelinks filter (lib/filters/pagelinks.rb) on
# all items to replace page:... URLs with their actual URLs as
# they will be rendered
filter :pagelinks
# retrieve the image width and height from the image files that
# are referenced in <img/> tags to speed up browser rendering
# performance, see
# http://userprimary.net/posts/2011/01/10/optimizing-nanoc-based-websites/
# for inspiration, as well as
# https://developers.google.com/speed/docs/best-practices/rendering#SpecifyImageDimensions
filter :imagesize
end
if item[:forcepagelinks]
filter :pagelinks
filter :imagesize
end
# transform absolute paths in URLs with relative paths using the
# relativize_paths filter (that is shipped with nanoc)
# ***
# OPTIMIZATION: don't apply it to schedule pages, as they already
# render absolute paths that are correct, wins a few seconds
# ***
#filter :relativize_paths, :type => :xhtml unless item[:relativize] == false or item.identifier =~ %r{^/schedule/.+}
# use layout/default.html for all items, except
# sponsor pages and pages that have "layout: false"
# in their metadata
if item[:layout] == false or sponsor?(item) or item.identifier =~ %r{/[ix]cal/} or item[:kind] == 'internal' or item.identifier =~ %r{^/schedule/devrooms/}
# do nothing
elsif item[:layout]
# or those that explicitly specify the layout in their metadata
layout item[:layout]
elsif item.identifier =~ %r{^/schedule/day/.+}
# and for these, we go full page
layout 'fullpage'
else
layout 'main'
end
end
end
end
##### ROUTING
route '/searcherview/' do
"/searcher/layout.rhtml"
end
route '/404/' do
"/404.html"
end
# send this one into oblivion, its compiled content is included in
# layouts/default.html, but is not to be rendered as a file of its
# own into output
route '/schedule_navigation/' do; end
# same here:
route '/sponsors_navigation/' do; end
# attachments and such
route '/schedule/event/*/attachments/*' do
"#{$prefix}/schedule/event/#{item[:event_slug]}/attachments/#{item[:type]}/#{item[:id]}/#{item[:filename]}"
end
route '/schedule/event/*/logo/*' do
suffix = if @site.config[:digest_assets] then
"-#{digest item}"
else
""
end
"#{$prefix}/schedule/event/#{item[:event_slug]}/#{item[:event_slug]}#{suffix}.#{item[:extension]}"
end
route '/schedule/speaker/*/photo/' do
if @site.config[:digest_assets] then
"#{$prefix}/schedule/speaker/#{item[:speaker_slug]}/#{digest item}.#{item[:extension]}"
else
"#{$prefix}/schedule/speaker/#{item[:speaker_slug]}/#{item[:speaker]}.#{item[:extension]}"
end
end
route '/schedule/speaker/*/thumbnail/' do
if @site.config[:digest_assets] then
"#{$prefix}/schedule/speaker/#{item[:speaker_slug]}/#{digest item}.#{item[:extension]}"
else
"#{$prefix}/schedule/speaker/#{item[:speaker_slug]}/#{item[:speaker]}-thumbnail.#{item[:extension]}"
end
end
# iCal, xCal, XML stuff from Pentabarf:
route '/schedule/xcal/track/*' do
"#{$prefix}/schedule/track/#{item.identifier.split('/')[-1]}.xcs"
end
route '/schedule/ical/track/*' do
"#{$prefix}/schedule/track/#{item.identifier.split('/')[-1]}.ics"
end
route '/schedule/pentabarf/' do
"#{$prefix}/schedule/xml"
end
route '/schedule/pentabarf-tz/' do
"#{$prefix}/schedule/xml-tz"
end
route '/schedule/xcal/' do
"#{$prefix}/schedule/xcal"
end
route '/schedule/ical/' do
"#{$prefix}/schedule/ical"
end
# route /headlines/* into oblivion as they don't really exist on
# the site (and are not supposed to): they are created dynamically
# during preprocessing stage (by the "make_headlines" function that's
# defined in lib/helpers/news.rb) and only intended to be gathered
# in content/index.html
# route '/headlines/*/' do;end
# partials, are included somewhere else, don't create files in
# output for these:
route '/schedule/devrooms/*/' do; end
route '/assets/style/sprite/' do
suffix = if @site.config[:digest_assets]
"-#{digest item[:sprites].values.map(&$to_item)}"
else
""
end
"#{$prefix}#{item.identifier.chop}#{suffix}.#{item[:extension]}"
end
# deploy content/assets/style/foo.css as output/assets/style/foo.css
# (without this, nanoc would deploy it as output/assets/style/foo/index.html)
route '/assets/style/fosdem/' do
fail "#{item.identifier} is not the css file!" unless item[:extension] == 'css'
suffix = if @site.config[:digest_css]
parts = @items.select { |i| i.identifier =~ %r{^/assets/style/parts/.+} }.sort_by(&:identifier)
"-" + digest(parts)
else
""
end
"#{$prefix}#{item.identifier.chop}#{suffix}.#{item[:extension]}"
end
route '/assets/style/fosdem-static/' do
fail "#{item.identifier} is not the css file!" unless item[:extension] == 'css'
"#{$prefix}#{item.identifier.chop}.#{item[:extension]}"
end
route '/assets/style/*/' do
unless $item_by_id.fetch('/assets/style/sprite/')[:sprites].values.include? item.identifier
suffix = if @site.config[:digest_assets]
"-#{digest item}"
else
""
end
"#{$prefix}#{item.identifier.chop}#{suffix}.#{item[:extension]}"
end
end
# don't add a digest to the banner and flyer filenames: as they are linked
# to on external sites, we need meaningful and stable names here, even
# if the content is changing
route '/assets/promote/*/' do
"#{$prefix}/support/promote/#{item.identifier.chop.split('/').last}.#{item[:extension]}"
end
# everything else in assets/* gets a digest suffix
route '/assets/*/' do
suffix = if @site.config[:digest_assets]
"-" + digest(item)
else
""
end
"#{$prefix}#{item.identifier.chop}#{suffix}.#{item[:extension]}"
end
# don't deploy these anywhere, they are only used internally
route %r{^/schedule/(thumbnail|photo)/speaker/} do; end
# this is where they are processed to, and these ones get to be deployed:
route '/schedule/speaker_thumbnails/*/' do
suffix = if @site.config[:digest_assets]
"-#{digest item}"
else
""
end
"#{$prefix}/schedule/speaker/#{item[:slug]}-small#{suffix}.#{item[:extension]}"
end
# do _not_ deploy the files under content/sponsors/ as they are only used
# programmatically in content/about/sponsors.html, but we _do_ want to
# deploy binary files (typically the sponsor logos) that are under
# content/sponsors/, hence the "if item.binary?"
route '/sponsors/*/' do
if item.binary?
if item.identifier =~ %r{^(.+)/(.+?)-(big|small)/$} then
name = $2
size = $3
suffix = if @site.config[:digest_sponsor_logos] then
"-#{digest item}"
else
""
end
case size
when 'big'
# big logos: /sponsored-by/google.png
"#{$prefix}/sponsored-by/#{name}#{suffix}.#{item[:extension]}"
when 'small'
# small logos: /sponsored-by/thumb/oreilly.png
"#{$prefix}/sponsored-by/thumb/#{name}#{suffix}.#{item[:extension]}"
else
raise "wtf? ran into a sponsor logo that is neither :big nor :small"
end
else
"#{$prefix}/sponsored-by/#{item.id}.#{item[:extension]}"
end
else
# do nothing with the non-binary files
end
end
# we duplicated the favicon.ico to also route one into the content
# root (output/), rather than in e.g. output/2013/
route '/root_favicon/' do
"/favicon.#{item[:extension]}"
end
route '/icon/' do
suffix = if @site.config[:digest_assets] then
"-#{digest item}"
else
""
end
"#{$prefix}/icon#{suffix}.#{item[:extension]}"
end
route %r{^/news/\d+/$} do
if item.identifier =~ %r{^/news/(\d+)/$}
if $1.to_i == 1
"#{$prefix}/news/index.html"
else
"#{$prefix}/news/#{$1}/index.html"
end
else
fail "newspage item has invalid identifier \"#{item.identifier}\""
end
end
# and this is for everything else:
route '*' do
unless item[:kind] == 'internal' or item[:hidden] == true
if item.binary? or ['xml'].include? item[:extension]
# Write binary item and XML files with identifier /foo/ to /foo.ext
"#{$prefix}#{item.identifier.chop}.#{item[:extension]}"
else
# Write text item with identifier /foo/ to /foo/index.html
"#{$prefix}#{item.identifier}index.html"
end
end
end
##### LAYOUT PROCESSING
layout '*', :erb