7 Example buildout demonstrating some types::
9 >>> write('buildout.cfg',
15 ... recipe = slapos.recipe.template:jinja2
19 ... key bar section:key
20 ... key recipe :recipe
22 ... import json_module json
23 ... section param_dict parameter-collection
25 ... [parameter-collection]
33 And according Jinja2 template (kept simple, control structures are possible)::
37 ... 'Knights who say "{{knight}}"\n'
38 ... '${this:is_literal}\n'
39 ... '${foo:{{bar}}}\n'
40 ... 'swallow: {{ json_module.dumps(("african", "european")) }}\n'
41 ... 'parameters from section: {{ param_dict | dictsort }}\n'
42 ... 'Rendered with {{recipe}}'
47 >>> print system(join('bin', 'buildout')),
50 And the template has been rendered::
54 Knights who say "Ni !"
57 swallow: ["african", "european"]
58 parameters from section: [('bar', 'bar'), ('foo', '1')]
59 Rendered with slapos.recipe.template:jinja2
67 Template url/path, as accepted by zc.buildout.download.Download.__call__ .
68 For very short template, it can make sense to put it directly into
69 buildout.cfg: the value is the template itself, prefixed by the string
70 "inline:" + an optional newline.
73 Where rendered template should be stored.
78 Jinja2 context specification, one variable per line, with 3
79 whitespace-separated parts: type, name and expression. Available types are
80 described below. "name" is the variable name to declare. Expression semantic
81 varies depending on the type.
86 Immediate literal string.
89 Indirect literal string.
92 Import a python module.
95 Make a whole buildout section available to template, as a dictionary.
97 Indirection targets are specified as: [section]:key .
98 It is possible to use buildout's buit-in variable replacement instead instead
99 of ``key`` type, but keep in mind that different lines are different
100 variables for this recipe. It might be what you want (factorising context
101 chunk declarations), otherwise you should use indirect types.
104 Template's MD5, for file integrity checking. By default, no integrity check
108 Mode, in octal representation (no need for 0-prefix) to set output file to.
109 This is applied before storing anything in output file.
112 Jinja2 extensions to enable when rendering the template,
113 whitespace-separated. By default, none is loaded.
116 Delimiter character for in-temlate imports.
118 See also: import-list
121 Declares a list of import paths. Format is similar to ``context``.
122 "name" becomes import's base name.
127 Literal path of a file.
130 Indirect path of a file.
133 Literal path of a folder. Any file in such folder can be imported.
136 Indirect path of a folder. Any file in such folder can be imported.
141 Q: How do I generate ${foo:bar} where foo comes from a variable ?
143 A: ``{{ '${' ~ foo_var ~ ':bar}' }}``
144 This is required as jinja2 fails parsing "${{{ foo_var }}:bar}". Though,
145 jinja2 succeeds at parsing "${foo:{{ bar_var }}}" so this trick isn't
146 needed for that case.
148 Use jinja2 extensions
149 ~~~~~~~~~~~~~~~~~~~~~
152 ... '''{% set foo = ['foo'] -%}
153 ... {% do foo.append(bar) -%}
154 ... {{ foo | join(', ') }}''')
155 >>> write('buildout.cfg',
161 ... recipe = slapos.recipe.template:jinja2
162 ... template = foo.in
164 ... context = key bar buildout:parts
165 ... # We don't actually use all those extensions in this minimal example.
166 ... extensions = jinja2.ext.do jinja2.ext.loopcontrols
169 >>> print system(join('bin', 'buildout')),
170 Uninstalling template.
179 Compute template's MD5 sum::
181 >>> write('foo.in', '{{bar}}')
183 >>> md5sum = md5.new(open('foo.in', 'r').read()).hexdigest()
184 >>> write('buildout.cfg',
190 ... recipe = slapos.recipe.template:jinja2
191 ... template = foo.in
193 ... context = key bar buildout:parts
194 ... md5sum = ''' + md5sum + '''
196 >>> print system(join('bin', 'buildout')),
197 Uninstalling template.
203 If the md5sum doesn't match, the buildout fail::
205 >>> write('buildout.cfg',
211 ... recipe = slapos.recipe.template:jinja2
212 ... template = foo.in
214 ... context = key bar buildout:parts
215 ... md5sum = 0123456789abcdef0123456789abcdef
217 >>> print system(join('bin', 'buildout')),
220 Getting section template.
221 Initializing part template.
222 Error: MD5 checksum mismatch for local resource at 'foo.in'.
225 Specify filesystem permissions
226 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
228 You can specify the mode for rendered file::
230 >>> write('template.in', '{{bar}}')
231 >>> write('buildout.cfg',
237 ... recipe = slapos.recipe.template:jinja2
238 ... template = template.in
240 ... context = key bar buildout:parts
243 >>> print system(join('bin', 'buildout')),
244 Uninstalling template.
247 And the generated file with have the right permissions::
251 >>> print oct(stat.S_IMODE(os.stat('foo').st_mode))
254 Note that Buildout will not allow you to have write permission for others
255 and will silently remove it (i.e a 207 mode will become 205).
260 Here is a simple template importing an equaly-simple library:
262 >>> write('template.in', '''
263 ... {%- import "library" as library -%}
264 ... {{ library.foo() }}
266 >>> write('library.in', '{% macro foo() %}FOO !{% endmacro %}')
268 To import a template from rendered template, you need to specify what can be
271 >>> write('buildout.cfg', '''
276 ... recipe = slapos.recipe.template:jinja2
277 ... template = template.in
279 ... import-list = rawfile library library.in
281 >>> print system(join('bin', 'buildout')),
282 Uninstalling template.
287 Just like context definition, it also works with indirect values::
289 >>> write('buildout.cfg', '''
293 ... [template-library]
294 ... path = library.in
297 ... recipe = slapos.recipe.template:jinja2
298 ... template = template.in
300 ... import-list = file library template-library:path
302 >>> print system(join('bin', 'buildout')),
303 Uninstalling template.
308 This also works to allow importing from identically-named files in different
311 >>> write('template.in', '''
312 ... {%- import "dir_a/1.in" as a1 -%}
313 ... {%- import "dir_a/2.in" as a2 -%}
314 ... {%- import "dir_b/1.in" as b1 -%}
315 ... {%- import "dir_b/c/1.in" as bc1 -%}
323 >>> mkdir(join('b', 'c'))
324 >>> write(join('a', '1.in'), '{% macro foo() %}a1foo{% endmacro %}')
325 >>> write(join('a', '2.in'), '{% macro foo() %}a2foo{% endmacro %}')
326 >>> write(join('b', '1.in'), '{% macro foo() %}b1foo{% endmacro %}')
327 >>> write(join('b', 'c', '1.in'), '{% macro foo() %}bc1foo{% endmacro %}')
329 All templates can be accessed inside both folders::
331 >>> write('buildout.cfg', '''
335 ... [template-library]
336 ... path = library.in
339 ... recipe = slapos.recipe.template:jinja2
340 ... template = template.in
343 ... rawfolder dir_a a
344 ... rawfolder dir_b b
346 >>> print system(join('bin', 'buildout')),
347 Uninstalling template.
355 It is possible to override default path delimiter (without any effect on final
358 >>> write('template.in', r'''
359 ... {%- import "dir_a\\1.in" as a1 -%}
360 ... {%- import "dir_a\\2.in" as a2 -%}
361 ... {%- import "dir_b\\1.in" as b1 -%}
362 ... {%- import "dir_b\\c\\1.in" as bc1 -%}
368 >>> write('buildout.cfg', r'''
372 ... [template-library]
373 ... path = library.in
376 ... recipe = slapos.recipe.template:jinja2
377 ... template = template.in
379 ... import-delimiter = \
381 ... rawfolder dir_a a
382 ... rawfolder dir_b b
384 >>> print system(join('bin', 'buildout')),
385 Uninstalling template.
396 You can use other part of buildout in the template. This way this parts
397 will be installed as dependency::
399 >>> write('buildout.cfg', '''
404 ... recipe = slapos.recipe.template:jinja2
405 ... template = inline:{{bar}}
407 ... context = key bar dependency:foobar
410 ... foobar = dependency content
411 ... recipe = zc.buildout:debug
414 >>> print system(join('bin', 'buildout')),
415 Uninstalling template.
416 Installing dependency.
417 foobar='dependency content'
418 recipe='zc.buildout:debug'
421 This way you can get options which are computed in the ``__init__`` of
422 the dependent recipe.
424 Let's create a sample recipe modifying its option dict::
426 >>> write('setup.py',
428 ... from setuptools import setup
430 ... setup(name='samplerecipe',
433 ... 'default = main:Recipe',
440 ... class Recipe(object):
442 ... def __init__(self, buildout, name, options):
443 ... options['data'] = 'foobar'
445 ... def install(self):
449 Let's just use ``buildout.cfg`` using this egg::
451 >>> write('buildout.cfg',
458 ... recipe = slapos.recipe.template:jinja2
459 ... template = inline:
462 ... context = key bar sample:data
465 ... recipe = samplerecipe
467 >>> print system(join('bin', 'buildout')),
469 Uninstalling template.
470 Uninstalling dependency.