...
 
Commits (2)
......@@ -25,7 +25,7 @@ setup(name=name,
include_package_data=True,
install_requires=[
'setuptools', # namespaces
'zc.buildout', # plays with buildout
'zc.buildout==1.7.1', # plays with buildout
'jinja2 >= 2.7',
],
zip_safe=True,
......
......@@ -58,6 +58,66 @@ And the template has been rendered::
parameters from section: [('bar', 'bar'), ('foo', '1')]
Rendered with slapos.recipe.template:jinja2
Custom environment
------------------
We might want to embed jinja inline templates inside jinja template files.
To this purpose, we can use two sets of delimiters, by defining our owns
instead of the default ones - {% %} {{ }} {# and #}.
Other options for controlling whitespace handling are supported as well, see
http://jinja.pocoo.org/docs/dev/api/
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... block-start-string = [%
... block-end-string = %]
... variable-start-string = [[
... variable-end-string = ]]
... comment-start-string = /*
... comment-end-string = */
... line-statement-prefix = @@
... line-comment-prefix = //
... lstrip-blocks = True
... trim-blocks = True
... context =
... raw knight Ni!
... ''')
The template can now use [ instead of {
>>> write('foo.in',
... 'Knights who say "[[knight]]"\n'
... 'Say it again: /* embedded comment */\n'
... ' [% for i in range(5) -%][[knight]] [% endfor -%]\n'
... '// full line comment\n'
... '@@ for i in range(3)\n'
... '[[knight]]\n'
... '@@ endfor\n'
... )
We run buildout::
>>> print system(join('bin', 'buildout')),
Uninstalling template.
Installing template.
And the template has been rendered::
>>> cat('foo')
Knights who say "Ni!"
Say it again: Ni! Ni! Ni! Ni! Ni!
Ni!
Ni!
Ni!
Parameters
----------
......@@ -225,8 +285,10 @@ If the md5sum doesn't match, the buildout fail::
Specify filesystem permissions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can specify the mode for rendered file::
You can specify the mode for rendered file (according to umask settings)::
>>> import os
>>> old_umask = os.umask(0)
>>> write('template.in', '{{bar}}')
>>> write('buildout.cfg',
... '''
......@@ -243,6 +305,8 @@ You can specify the mode for rendered file::
>>> print system(join('bin', 'buildout')),
Uninstalling template.
Installing template.
>>> os.umask(old_umask)
0
And the generated file with have the right permissions::
......
......@@ -186,6 +186,37 @@ class Recipe(object):
if umask_value:
self.umask = int(umask_value, 8)
self.extra_environment = dict((key, value)
for key, value in self.iter_extra_environment(options))
def iter_extra_environment(self, options):
for is_boolean, okey in [
(0, 'block-start-string'),
(0, 'block-end-string'),
(0, 'variable-start-string'),
(0, 'variable-end-string'),
(0, 'comment-start-string'),
(0, 'comment-end-string'),
(0, 'line-statement-prefix'),
(0, 'line-comment-prefix'),
(1, 'trim-blocks'),
(1, 'lstrip-blocks')]:
jkey = okey.replace('-', '_')
if jkey in options:
raise ValueError('Invalid Jinja2 environment key %s: use %s' % (jkey, okey))
if okey in options:
if is_boolean:
if options[okey].strip().lower() == 'true':
yield jkey, True
elif options[okey].strip().lower() == 'false':
yield jkey, False
else:
raise ValueError('Invalid value for boolean key %s, should be True or False' % okey)
else:
yield jkey, options[okey]
def install(self):
# Unlink any existing file, so umask is always applied.
try:
......@@ -197,6 +228,7 @@ class Recipe(object):
outdir = os.path.dirname(self.rendered)
if outdir and not os.path.exists(outdir):
os.makedirs(outdir)
# XXX: open doesn't allow providing a filesystem mode, so use
# os.open and os.fdopen instead.
with os.fdopen(os.open(self.rendered,
......@@ -207,6 +239,7 @@ class Recipe(object):
extensions=self.extension_list,
undefined=StrictUndefined,
loader=self.loader,
**self.extra_environment
).from_string(
self.get_template(),
).render(
......