Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
slapos.recipe.template
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Romain Courteaud
slapos.recipe.template
Commits
65cd02ec
Commit
65cd02ec
authored
Mar 28, 2012
by
Vincent Pelletier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add jinja2-based template recipe entry.
parent
c582a98c
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
426 additions
and
1 deletion
+426
-1
.gitignore
.gitignore
+1
-0
CHANGES.txt
CHANGES.txt
+1
-1
MANIFEST.in
MANIFEST.in
+1
-0
README.txt
README.txt
+2
-0
setup.py
setup.py
+2
-0
slapos/recipe/template/README.jinja2.txt
slapos/recipe/template/README.jinja2.txt
+310
-0
slapos/recipe/template/jinja2_template.py
slapos/recipe/template/jinja2_template.py
+108
-0
slapos/recipe/template/tests.py
slapos/recipe/template/tests.py
+1
-0
No files found.
.gitignore
View file @
65cd02ec
...
...
@@ -5,6 +5,7 @@
# "setup.py test"-installed eggs
/zc.buildout-*.egg
/Jinja2-*.egg
# Editor backupfiles
.*.swp
...
...
CHANGES.txt
View file @
65cd02ec
2.3 (unreleased)
================
*
No changes yet.
*
Add jinja2 entry point with jinja2 template support. [Vincent Pelletier]
2.2 (2011-10-12)
================
...
...
MANIFEST.in
View file @
65cd02ec
include CHANGES.txt
include slapos/recipe/template/README.txt
include slapos/recipe/template/README.jinja2.txt
README.txt
View file @
65cd02ec
...
...
@@ -6,3 +6,5 @@ Template recipe which supports remote resource.
Inspired by collective.recipe.template, with minimum set of features, but with
(hopefully) safer buildout-based templating.
"jinja2" entry point allows rendering jinja2 templates.
setup.py
View file @
65cd02ec
...
...
@@ -24,11 +24,13 @@ setup(name=name,
install_requires
=
[
'setuptools'
,
# namespaces
'zc.buildout'
,
# plays with buildout
'jinja2'
,
],
zip_safe
=
True
,
entry_points
=
{
'zc.buildout'
:
[
'default = slapos.recipe.template:Recipe'
,
'jinja2 = slapos.recipe.template.jinja2_template:Recipe'
,
]},
test_suite
=
"slapos.recipe.template.tests.test_suite"
,
)
slapos/recipe/template/README.jinja2.txt
0 → 100644
View file @
65cd02ec
Usage
=====
Getting started
---------------
Example buildout demonstrating some types::
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... context =
... key bar section:key
... key recipe :recipe
... raw knight Ni !
... json words ["Peng", "Neee-wom"]
... jsonkey later section:later-words
... import json_module json
... section param_dict parameter-collection
...
... [parameter-collection]
... foo = 1
... bar = bar
...
... [section]
... key = value
... later-words = "Ekke Ekke Ekke Ekke Ptangya Ziiinnggggggg Ni!"
... ''')
And according Jinja2 template (kept simple, control structures are possible)::
>>> write('foo.in',
... '{{bar}}\n'
... 'Knights who say "{{knight}}" also protect {{ words | join(", ") }}.\n'
... 'They later say {{later}}\n'
... '${this:is_literal}\n'
... 'swallow: {{ json_module.dumps(("african", "european")) }}\n'
... 'parameters from section: {{ param_dict | dictsort }}\n'
... 'Rendered with {{recipe}}'
... )
We run buildout::
>>> print system(join('bin', 'buildout')),
Installing template.
And the template has been rendered::
>>> cat('foo')
value
Knights who say "Ni !" also protect Peng, Neee-wom.
They later say Ekke Ekke Ekke Ekke Ptangya Ziiinnggggggg Ni!
${this:is_literal}
swallow: ["african", "european"]
parameters from section: [('bar', 'bar'), ('foo', '1')]
Rendered with slapos.recipe.template:jinja2
Parameters
----------
Mandatory:
``template``
Template url/path, as accepted by zc.buildout.download.Download.__call__ .
``rendered``
Where rendered template should be stored.
Optional:
``context``
Jinja2 context specification, one variable per line, with 3
whitespace-separated parts: type, name and expression. Available types are
described below. "name" is the variable name to declare. Expression semantic
varies depending on the type.
Available types:
``raw``
Immediate literal string.
``json``
Immediate json-encoded string.
``key``
Indirect literal string.
``jsonkey``
Indirect json-encoded string.
``import``
Import a python module.
``section``
Make a whole buildout section available to template, as a dictionary.
Indirection targets are specified as: [section]:key .
It is possible to use buildout's buit-in variable replacement instead instead
of ``key`` or ``jsonkey`` types, but keep in mind that different lines are
different variables for this recipe. It might be what you want (factorising
context chunk declarations), otherwise you should use indirect types.
``md5sum``
Template's MD5, for file integrity checking. By default, no integrity check
is done.
``umask``
Umask, in octal notation (no need for 0-prefix), to create output file with.
Defaults to system's umask at the time recipe is instanciated.
``extensions``
Jinja2 extensions to enable when rendering the template,
whitespace-separated. By default, none is loaded.
Use jinja2 extensions
~~~~~~~~~~~~~~~~~~~~~
>>> write('foo.in',
... '''{% set foo = ['foo'] -%}
... {% do foo.append(bar) -%}
... {{ foo | join(', ') }}''')
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... context = key bar buildout:parts
... # We don't actually use all those extensions in this minimal example.
... extensions = jinja2.ext.do jinja2.ext.loopcontrols
... jinja2.ext.with_
... ''')
>>> print system(join('bin', 'buildout')),
Uninstalling template.
Installing template.
>>> cat('foo')
foo, template
Check file integrity
~~~~~~~~~~~~~~~~~~~~
Compute template's MD5 sum::
>>> write('foo.in', '{{bar}}')
>>> import md5
>>> md5sum = md5.new(open('foo.in', 'r').read()).hexdigest()
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... context = key bar buildout:parts
... md5sum = ''' + md5sum + '''
... ''')
>>> print system(join('bin', 'buildout')),
Uninstalling template.
Installing template.
>>> cat('foo')
template
If the md5sum doesn't match, the buildout fail::
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... context = key bar buildout:parts
... md5sum = 0123456789abcdef0123456789abcdef
... ''')
>>> print system(join('bin', 'buildout')),
While:
Installing.
Getting section template.
Initializing part template.
Error: MD5 checksum mismatch for local resource at 'foo.in'.
Specify filesystem permissions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can specify the umask for rendered file::
>>> write('template.in', '{{bar}}')
>>> write('buildout.cfg',
... '''
... [buildout]
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... context = key bar buildout:parts
... umask = 570
... ''')
>>> print system(join('bin', 'buildout')),
Uninstalling template.
Installing template.
And the generated file with have the right permissions::
>>> import stat
>>> import os
>>> print oct(stat.S_IMODE(os.stat('foo').st_mode))
0206
Section dependency
------------------
You can use other part of buildout in the template. This way this parts
will be installed as dependency::
>>> write('foo.in', '{{bar}}')
>>> write('buildout.cfg', '''
... [buildout]
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... context = key bar dependency:foobar
...
... [dependency]
... foobar = dependency content
... recipe = zc.buildout:debug
... ''')
>>> print system(join('bin', 'buildout')),
Uninstalling template.
Installing dependency.
foobar='dependency content'
recipe='zc.buildout:debug'
Installing template.
This way you can get options which are computed in the ``__init__`` of
the dependent recipe.
Let's create a sample recipe modifying its option dict::
>>> write('setup.py',
... '''
... from setuptools import setup
...
... setup(name='samplerecipe',
... entry_points = {
... 'zc.buildout': [
... 'default = main:Recipe',
... ],
... }
... )
... ''')
>>> write('main.py',
... '''
... class Recipe(object):
...
... def __init__(self, buildout, name, options):
... options['data'] = 'foobar'
...
... def install(self):
... return []
... ''')
Let's just use ``buildout.cfg`` using this egg::
>>> write('foo.in', '{{bar}}')
>>> write('buildout.cfg',
... '''
... [buildout]
... develop = .
... parts = template
...
... [template]
... recipe = slapos.recipe.template:jinja2
... template = foo.in
... rendered = foo
... context = key bar sample:data
...
... [sample]
... recipe = samplerecipe
... ''')
>>> print system(join('bin', 'buildout')),
Develop: ...
Uninstalling template.
Uninstalling dependency.
Installing sample.
Installing template.
>>> cat('foo')
foobar
slapos/recipe/template/jinja2_template.py
0 → 100644
View file @
65cd02ec
##############################################################################
#
# Copyright (c) 2012 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import
errno
import
os
import
json
import
zc.buildout
from
jinja2
import
Template
,
StrictUndefined
from
contextlib
import
contextmanager
@
contextmanager
def
umask
(
mask
):
original
=
os
.
umask
(
mask
)
try
:
yield
original
finally
:
os
.
umask
(
original
)
def
getKey
(
expression
,
buildout
,
_
,
options
):
section
,
entry
=
expression
.
split
(
':'
)
if
section
:
return
buildout
[
section
][
entry
]
else
:
return
options
[
entry
]
def
getJsonKey
(
expression
,
buildout
,
_
,
__
):
return
json
.
loads
(
getKey
(
expression
,
buildout
,
_
,
__
))
EXPRESSION_HANDLER
=
{
'raw'
:
(
lambda
expression
,
_
,
__
,
___
:
expression
),
'key'
:
getKey
,
'json'
:
(
lambda
expression
,
_
,
__
,
___
:
json
.
loads
(
expression
)),
'jsonkey'
:
getJsonKey
,
'import'
:
(
lambda
expression
,
_
,
__
,
___
:
__import__
(
expression
)),
'section'
:
(
lambda
expression
,
buildout
,
_
,
__
:
dict
(
buildout
[
expression
])),
}
class
Recipe
(
object
):
def
__init__
(
self
,
buildout
,
name
,
options
):
self
.
template
=
zc
.
buildout
.
download
.
Download
(
buildout
[
'buildout'
],
hash_name
=
True
,
)(
options
[
'template'
],
md5sum
=
options
.
get
(
'md5sum'
),
)[
0
]
self
.
rendered
=
options
[
'rendered'
]
self
.
extension_list
=
[
x
for
x
in
(
y
.
strip
()
for
y
in
options
.
get
(
'extensions'
,
''
).
split
())
if
x
]
self
.
context
=
context
=
{}
for
line
in
options
.
get
(
'context'
).
splitlines
(
False
):
if
not
line
:
continue
expression_type
,
variable_name
,
expression
=
line
.
split
(
None
,
2
)
if
variable_name
in
context
:
raise
ValueError
(
'Duplicate context entry %r'
%
(
variable_name
,
))
context
[
variable_name
]
=
EXPRESSION_HANDLER
[
expression_type
](
expression
,
buildout
,
name
,
options
)
if
'umask'
in
options
:
self
.
umask
=
int
(
options
[
'umask'
],
8
)
else
:
self
.
umask
=
os
.
umask
(
0
)
os
.
umask
(
self
.
umask
)
def
install
(
self
):
if
os
.
path
.
lexists
(
self
.
rendered
):
# Unlink any existing file, so umask is always applied.
os
.
unlink
(
self
.
rendered
)
with
umask
(
self
.
umask
):
outdir
=
os
.
path
.
dirname
(
self
.
rendered
)
if
outdir
and
not
os
.
path
.
exists
(
outdir
):
os
.
makedirs
(
outdir
)
with
open
(
self
.
rendered
,
'w'
)
as
out
:
out
.
write
(
Template
(
open
(
self
.
template
).
read
(),
extensions
=
self
.
extension_list
,
undefined
=
StrictUndefined
,
).
render
(
**
self
.
context
)
)
return
self
.
rendered
update
=
install
slapos/recipe/template/tests.py
View file @
65cd02ec
...
...
@@ -41,6 +41,7 @@ def test_suite():
optionflags
=
doctest
.
ELLIPSIS
,
)
for
filename
in
[
'README.txt'
,
'README.jinja2.txt'
,
]
])
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment