Metadata-Version: 1.0
Name: slapos.recipe.template
Version: 2.4.3
Summary: Templating recipe with remote resource support.
Home-page: UNKNOWN
Author: UNKNOWN
Author-email: UNKNOWN
License: GPLv3
Description: ======================
        slapos.recipe.template
        ======================
        
        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.
        
        Usage
        =====
        
        Getting started
        ---------------
        
        You can start by a simple buildout::
        
            >>> write('buildout.cfg',
            ... '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template
            ... url = template.in
            ... output = template.out
            ...
            ... [section]
            ... option = value
            ... ''')
        
        And a simple template::
        
            >>> write('template.in', '${section:option}')
        
        We run buildout::
        
            >>> print system(join('bin', 'buildout')),
            Installing template.
        
        And the output file has been parsed by buildout itself::
        
            >>> cat('template.out')
            value
        
        Full options
        ------------
        
        There is two non required options:
        
        ``md5sum``
          Check the integrity of the input file.
        
        ``mode``
          Specify the filesystem permissions in octal notation.
        
        Check file integrity
        ~~~~~~~~~~~~~~~~~~~~
        
        Let's write a file template::
        
            >>> write('template.in', '${buildout:parts}')
        
        Compute its MD5 sum::
        
            >>> import md5
            >>> md5sum = md5.new(open('template.in', 'r').read()).hexdigest()
        
        Write the ``buildout.cfg`` using slapos.recipe.template::
        
            >>> write('buildout.cfg',
            ... '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template
            ... url = template.in
            ... output = template.out
            ... md5sum = ''' + md5sum + '''
            ... ''')
        
        And run buildout, and see the result::
        
            >>> print system(join('bin', 'buildout')),
            Uninstalling template.
            Installing template.
        
            >>> cat('template.out')
            template
        
        If the md5sum doesn't match, the buildout fail::
        
            >>> write('buildout.cfg',
            ... '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template
            ... url = template.in
            ... output = template.out
            ... md5sum = 0123456789abcdef0123456789abcdef
            ... ''')
            >>> print system(join('bin', 'buildout')),
            While:
              Installing.
              Getting section template.
              Initializing part template.
            Error: MD5 checksum mismatch for local resource at 'template.in'.
        
        
        Specify filesystem permissions
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        
        You can specify the mode of the written file::
        
            >>> write('template.in', '${buildout:installed}')
        
            >>> write('buildout.cfg',
            ... '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template
            ... url = template.in
            ... output = template.out
            ... mode = 0627
            ... ''')
        
            >>> 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('template.out').st_mode))
            0627
        
        Section dependency
        ------------------
        
        You can use other part of buildout in the template. This way this parts
        will be installed as dependency::
        
            >>> write('template.in', '${dependency:foobar}')
            >>> write('buildout.cfg', '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template
            ... url = template.in
            ... output = template.out
            ...
            ... [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('template.in', '${sample:data}')
            >>> write('buildout.cfg',
            ... '''
            ... [buildout]
            ... develop = .
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template
            ... url = template.in
            ... output = template.out
            ...
            ... [sample]
            ... recipe = samplerecipe
            ... ''')
            >>> print system(join('bin', 'buildout')),
            Develop: ...
            Uninstalling template.
            Uninstalling dependency.
            Installing sample.
            Installing template.
            >>> cat('template.out')
            foobar
        
        Jinja2 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 !
            ...     import  json_module  json
            ...     section param_dict   parameter-collection
            ...
            ... [parameter-collection]
            ... foo = 1
            ... bar = bar
            ...
            ... [section]
            ... key = value
            ... ''')
        
        And according Jinja2 template (kept simple, control structures are possible)::
        
            >>> write('foo.in',
            ...     '{{bar}}\n'
            ...     'Knights who say "{{knight}}"\n'
            ...     '${this:is_literal}\n'
            ...     '${foo:{{bar}}}\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 !"
            ${this:is_literal}
            ${foo:value}
            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__ .
          For very short template, it can make sense to put it directly into
          buildout.cfg: the value is the template itself, prefixed by the string
          "inline:" + an optional newline.
        
        ``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.
        
          ``key``
            Indirect literal 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`` type, 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.
        
        ``mode``
          Mode, in octal representation (no need for 0-prefix) to set output file to.
          This is applied before storing anything in output file.
        
        ``extensions``
          Jinja2 extensions to enable when rendering the template,
          whitespace-separated. By default, none is loaded.
        
        ``import-delimiter``
          Delimiter character for in-temlate imports.
          Defaults to ``/``.
          See also: import-list
        
        ``import-list``
          Declares a list of import paths. Format is similar to ``context``.
          "name" becomes import's base name.
        
          Available types:
        
          ``rawfile``
            Literal path of a file.
        
          ``file``
            Indirect path of a file.
        
          ``rawfolder``
            Literal path of a folder. Any file in such folder can be imported.
        
          ``folder``
            Indirect path of a folder. Any file in such folder can be imported.
        
        FAQ
        ---
        
        Q: How do I generate ${foo:bar} where foo comes from a variable ?
        
        A: ``{{ '${' ~ foo_var ~ ':bar}' }}``
           This is required as jinja2 fails parsing "${{{ foo_var }}:bar}". Though,
           jinja2 succeeds at parsing "${foo:{{ bar_var }}}" so this trick isn't
           needed for that case.
        
        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 mode for rendered file::
        
            >>> write('template.in', '{{bar}}')
            >>> write('buildout.cfg',
            ... '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template:jinja2
            ... template = template.in
            ... rendered = foo
            ... context = key bar buildout:parts
            ... mode = 206
            ... ''')
            >>> 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
        
        Template imports
        ~~~~~~~~~~~~~~~~
        
        Here is a simple template importing an equaly-simple library:
        
            >>> write('template.in', '''
            ... {%- import "library" as library -%}
            ... {{ library.foo() }}
            ... ''')
            >>> write('library.in', '{% macro foo() %}FOO !{% endmacro %}')
        
        To import a template from rendered template, you need to specify what can be
        imported::
        
            >>> write('buildout.cfg', '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template:jinja2
            ... template = template.in
            ... rendered = bar
            ... import-list = rawfile library library.in
            ... ''')
            >>> print system(join('bin', 'buildout')),
            Uninstalling template.
            Installing template.
            >>> cat('bar')
            FOO !
        
        Just like context definition, it also works with indirect values::
        
            >>> write('buildout.cfg', '''
            ... [buildout]
            ... parts = template
            ...
            ... [template-library]
            ... path = library.in
            ...
            ... [template]
            ... recipe = slapos.recipe.template:jinja2
            ... template = template.in
            ... rendered = bar
            ... import-list = file library template-library:path
            ... ''')
            >>> print system(join('bin', 'buildout')),
            Uninstalling template.
            Installing template.
            >>> cat('bar')
            FOO !
        
        This also works to allow importing from identically-named files in different
        directories::
        
            >>> write('template.in', '''
            ... {%- import "dir_a/1.in" as a1 -%}
            ... {%- import "dir_a/2.in" as a2 -%}
            ... {%- import "dir_b/1.in" as b1 -%}
            ... {%- import "dir_b/c/1.in" as bc1 -%}
            ... {{ a1.foo() }}
            ... {{ a2.foo() }}
            ... {{ b1.foo() }}
            ... {{ bc1.foo() }}
            ... ''')
            >>> mkdir('a')
            >>> mkdir('b')
            >>> mkdir(join('b', 'c'))
            >>> write(join('a', '1.in'), '{% macro foo() %}a1foo{% endmacro %}')
            >>> write(join('a', '2.in'), '{% macro foo() %}a2foo{% endmacro %}')
            >>> write(join('b', '1.in'), '{% macro foo() %}b1foo{% endmacro %}')
            >>> write(join('b', 'c', '1.in'), '{% macro foo() %}bc1foo{% endmacro %}')
        
        All templates can be accessed inside both folders::
        
            >>> write('buildout.cfg', '''
            ... [buildout]
            ... parts = template
            ...
            ... [template-library]
            ... path = library.in
            ...
            ... [template]
            ... recipe = slapos.recipe.template:jinja2
            ... template = template.in
            ... rendered = bar
            ... import-list =
            ...     rawfolder dir_a a
            ...     rawfolder dir_b b
            ... ''')
            >>> print system(join('bin', 'buildout')),
            Uninstalling template.
            Installing template.
            >>> cat('bar')
            a1foo
            a2foo
            b1foo
            bc1foo
        
        It is possible to override default path delimiter (without any effect on final
        path)::
        
            >>> write('template.in', r'''
            ... {%- import "dir_a\\1.in" as a1 -%}
            ... {%- import "dir_a\\2.in" as a2 -%}
            ... {%- import "dir_b\\1.in" as b1 -%}
            ... {%- import "dir_b\\c\\1.in" as bc1 -%}
            ... {{ a1.foo() }}
            ... {{ a2.foo() }}
            ... {{ b1.foo() }}
            ... {{ bc1.foo() }}
            ... ''')
            >>> write('buildout.cfg', r'''
            ... [buildout]
            ... parts = template
            ...
            ... [template-library]
            ... path = library.in
            ...
            ... [template]
            ... recipe = slapos.recipe.template:jinja2
            ... template = template.in
            ... rendered = bar
            ... import-delimiter = \
            ... import-list =
            ...     rawfolder dir_a a
            ...     rawfolder dir_b b
            ... ''')
            >>> print system(join('bin', 'buildout')),
            Uninstalling template.
            Installing template.
            >>> cat('bar')
            a1foo
            a2foo
            b1foo
            bc1foo
        
        Section dependency
        ------------------
        
        You can use other part of buildout in the template. This way this parts
        will be installed as dependency::
        
            >>> write('buildout.cfg', '''
            ... [buildout]
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template:jinja2
            ... template = inline:{{bar}}
            ... 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('buildout.cfg',
            ... '''
            ... [buildout]
            ... develop = .
            ... parts = template
            ...
            ... [template]
            ... recipe = slapos.recipe.template:jinja2
            ... template = inline:
            ...   {{bar}}
            ... 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
        
        
        2.4.3 (2013-08-02)
        ======================
        
         * jinja2: add support for inline templates.
        
        2.4.2 (2012-08-21)
        ==================
        
         * jinja2: Mode shall be used instead of umask. [Vincent Pelletier]
         * jinja2: Add jinja2 "import" directive support. [Vincent Pelletier,
           Timothee Lacroix]
         * Added rawfile and rawfolder types. [Vincent Pelletier, Timothee Lacroix]
         * Reworked loader classes [Vincent Pelletier]
        
        2.4.1 (2012-08-01)
        ==================
        
         * jinja2: Make "context" parameter really optional. [Vincent Pelletier]
        
        2.4 (2012-06-01)
        ================
        
         * Provide access to zc.buildout.buildout.dumps when it exists. [Vincent
           Pelletier]
        
         * Fix missing jinja2 entry point documentation in pacakge description [Vincent
           Pelletier]
        
        2.3 (2012-03-29)
        ================
        
         * Add jinja2 entry point with jinja2 template support. [Vincent Pelletier]
        
        2.2 (2011-10-12)
        ================
        
         * Include missing files in package. [Łukasz Nowak]
        
        2.1 (2011-10-12)
        ================
        
         * Description update. [Łukasz Nowak]
        
        2.0 (2011-10-12)
        ================
        
         * Dropping collective.recipe.template dependency. [Romain Courteaud, Antoine
           Catton]
        
        1.1 (2011-05-30)
        ================
        
         * Moved out from slapos.cookbook in order to minimise depenencies [Łukasz
           Nowak]
        
        
Keywords: slapos recipe
Platform: UNKNOWN
Classifier: Framework :: Buildout :: Recipe
Classifier: Programming Language :: Python
