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
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
slapos.recipe.template
Commits
65cd02ec
Commit
65cd02ec
authored
Mar 28, 2012
by
Vincent Pelletier
1
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'
,
]
])
...
...
Kirill Smelkov
@kirr
mentioned in merge request
!9 (merged)
·
Oct 30, 2023
mentioned in merge request
!9 (merged)
mentioned in merge request !9
Toggle commit list
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