PK4@xHԬ((c2c.template-1.2.0-nspkg.pthimport sys, types, os;p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('c2c',));ie = os.path.exists(os.path.join(p,'__init__.py'));m = not ie and sys.modules.setdefault('c2c', types.ModuleType('c2c'));mp = (m or []) and m.__dict__.setdefault('__path__',[]);(p not in mp) and mp.append(p) PK{^Gߏ8R=R=c2c/template.py# -*- coding: utf-8 -*- # Copyright (c) 2011-2014, Camptocamp SA # All rights reserved. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # The views and conclusions contained in the software and documentation are those # of the authors and should not be interpreted as representing official policies, # either expressed or implied, of the FreeBSD Project. import os import sys import traceback import json import yaml from yaml.parser import ParserError from argparse import ArgumentParser from string import Formatter from subprocess import CalledProcessError try: from subprocess import check_output except ImportError: # pragma: nocover from subprocess import Popen, PIPE def check_output(cmd, cwd=None, stdin=None, stderr=None, shell=False): # noqa """Backwards compatible check_output""" p = Popen(cmd, cwd=cwd, stdin=stdin, stderr=stderr, shell=shell, stdout=PIPE) out, err = p.communicate() return out def main(): parser = ArgumentParser( description='Used to run a template' ) parser.add_argument( '--engine', '-e', choices=['jinja', 'mako', 'template'], default='jinja', help='the used template engine' ) parser.add_argument( '--vars', '-c', default='vars.yaml', help="the YAML file defining the variables" ) parser.add_argument( '--section', action='store_true', help="use the section (template specific)" ) parser.add_argument( '--files', nargs='*', help="the files to interpret" ) parser.add_argument( '--get-vars', nargs='*', default=[], help="the vars to get, can be MY_VAR=my_var" ) parser.add_argument( '--get-config', nargs='*', help="generate a configuration file" ) files_builder_help = \ "generate some files from a source file (first ARG), " \ "to files (second ARG, with format we can access to the value attribute), " \ "and get the value on iter on the variable referenced by the third argument" parser.add_argument( '--files-builder', nargs=3, metavar='ARG', help=files_builder_help ) options = parser.parse_args() used_vars = read_vars(options.vars) formatter = Formatter() formatted = [] def format_walker(current_vars, path=None): if isinstance(current_vars, basestring): if path not in formatted: attrs = formatter.parse(current_vars) for _, attr, _, _ in attrs: if attr is not None and attr not in formatted: return current_vars, 1 formatted.append(path) return current_vars.format(**used_vars), 0 return current_vars, 0 elif isinstance(current_vars, list): formatteds = [ format_walker(var, "%s[%i]" % (path, index)) for index, var in enumerate(current_vars) ] return [v for v, s in formatteds], sum([s for v, s in formatteds]) elif isinstance(current_vars, dict): skip = 0 for key in current_vars.keys(): if path is None: current_path = key else: current_path = "%s[%s]" % (path, key) current_formatted = format_walker(current_vars[key], current_path) current_vars[key] = current_formatted[0] skip += current_formatted[1] return current_vars, skip else: formatted.append(path) return current_vars, 0 old_skip = 0 skip = -1 while old_skip != skip and skip != 0: old_skip = skip used_vars, skip = format_walker(used_vars) for get_var in options.get_vars: corresp = get_var.split('=') if len(corresp) == 1: corresp = (get_var.upper(), get_var) if len(corresp) != 2: # pragma: nocover print("ERROR the get variable '%s' has more than one '='." % ( get_var )) exit(1) print("%s=%r" % (corresp[0], used_vars[corresp[1]])) if options.get_config is not None: new_vars = {} for v in options.get_config[1:]: var_path = v.split('.') value = used_vars for key in var_path: if key in value: value = value[key] else: print("ERROR the variable '%s' don't exists." % v) exit(1) new_vars[v] = value with open(options.get_config[0], 'wb') as file_open: file_open.write(yaml.dump(new_vars)) if options.files_builder is not None: var_path = options.files_builder[2].split('.') values = used_vars for key in var_path: values = values[key] if not isinstance(values, list): # pragma: nocover print("ERROR the variable '%s': '%r' should be an array." % ( options.files_builder[2], values )) for value in values: file_vars = {} file_vars.update(used_vars) file_vars.update(value) template = options.files_builder[0] destination = options.files_builder[1].format(**value) _proceed([[template, destination]], file_vars, options) if options.files is not None: files = [(f, '.'.join(f.split('.')[:-1])) for f in options.files] _proceed(files, used_vars, options) def get_path(value, path): split_path = path.split(".") parent = None for element in split_path: parent = value value = parent[element] return (parent, split_path[-1]), value def set_path(item, value): parent, element = item parent[element] = value def _proceed(files, used_vars, options): if options.engine == 'jinja': from bottle import jinja2_template as engine bottle_template(files, used_vars, engine) elif options.engine == 'mako': from bottle import mako_template as engine bottle_template(files, used_vars, engine) elif options.engine == 'template': for template, destination in files: c2c_template = C2cTemplate( template, template, used_vars ) c2c_template.section = options.section processed = unicode(c2c_template.substitute(), "utf8") save(template, destination, processed) try: from z3c.recipe.filetemplate import Template class C2cTemplate(Template): # pragma: nocover def _get(self, section, option, start): if self.section and section is not None: return self.recipe[section][option] else: return self.recipe[option] except ImportError: class C2cTemplate: def __init__(self, *args): raise Exception("The egg 'z3c.recipe.filetemplate' is missing.") def bottle_template(files, used_vars, engine): for template, destination in files: processed = engine( template, **used_vars ) save(template, destination, processed) def save(template, destination, processed): with open(destination, 'wb') as file_open: file_open.write(processed.encode("utf-8")) os.chmod(destination, os.stat(template).st_mode) def read_vars(vars_file): with open(vars_file, 'r') as file_open: used = yaml.load(file_open.read()) current_vars = {} if 'extends' in used: current_vars = read_vars(used['extends']) new_vars = used['vars'] if 'interpreted' in used: interpreters = [] globs = {'__builtins__': __builtins__, 'os': os, 'sys': sys} for key, interpreter in used['interpreted'].items(): if isinstance(interpreter, dict): interpreter["name"] = key if 'priority' not in interpreter: interpreter["priority"] = 0 if key in ['json', 'yaml'] else 100 else: interpreter = { "name": key, "vars": interpreter, "priority": 0 if key in ['json', 'yaml'] else 100 } interpreters.append(interpreter) interpreters.sort(key=lambda v: -v["priority"]) for interpreter in interpreters: for var_name in interpreter["vars"]: try: item, expression = get_path(new_vars, var_name) except KeyError: # pragma: nocover print("ERROR: Expression for key not found: %s" % var_name) exit(1) if "cmd" in interpreter: cmd = interpreter["cmd"][:] # [:] to clone cmd.append(expression) try: evaluated = check_output(cmd) except OSError as e: # pragma: nocover print("ERROR when running the expression '%r': %s" % ( expression, e )) exit(1) except CalledProcessError as e: # pragma: nocover error = "ERROR when running the expression '%r': %s" % ( expression, e ) print(error) if interpreter.get("ignore_error", False): evaluated = error else: exit(1) elif interpreter["name"] == "python": try: evaluated = eval(expression, globs) except: # pragma: nocover error = "ERROR when evaluating %r expression %r as Python:\n%s" % ( var_name, expression, traceback.format_exc() ) print(error) if interpreter.get("ignore_error", False): evaluated = error else: exit(1) elif interpreter["name"] == 'bash': try: evaluated = check_output(expression, shell=True) except OSError as e: # pragma: nocover print("ERROR when running the expression '%r': %s" % ( expression, e )) exit(1) except CalledProcessError as e: # pragma: nocover error = "ERROR when running the expression '%r': %s" % ( expression, e ) print(error) if interpreter.get("ignore_error", False): evaluated = error else: exit(1) elif interpreter["name"] == 'environment': # pragma: nocover if expression is None: evaluated = os.environ else: try: evaluated = os.environ[expression] except KeyError: error = \ "ERROR when getting %r in environment variables, " \ "possible values are: %r" % ( expression, os.environ.keys() ) print(error) if interpreter.get("ignore_error", False): evaluated = error else: exit(1) elif interpreter["name"] == 'json': try: evaluated = json.loads(expression) except ValueError as e: # pragma: nocover error = "ERROR when evaluating %r expression %r as JSON: %s" % ( key, expression, e ) print(error) if interpreter.get("ignore_error", False): evaluated = error else: exit(1) elif interpreter["name"] == 'yaml': try: evaluated = yaml.load(expression) except ParserError as e: # pragma: nocover error = "ERROR when evaluating %r expression %r as YAML: %s" % ( key, expression, e ) print(error) if interpreter.get("ignore_error", False): evaluated = error else: exit(1) else: # pragma: nocover print("Unknown interpreter name '{}'.".format(interpreter["name"])) exit(1) set_path(item, evaluated) update_paths = [] for update_path in used.get("update_paths", []): split_path = update_path.split(".") for i in range(len(split_path)): update_paths.append(".".join(split_path[:i + 1])) update_vars(current_vars, new_vars, set(update_paths)) return current_vars def update_vars(current_vars, new_vars, update_paths, path=None): for key, value in new_vars.items(): if "." in key: # pragma: nocover print("WARNING: the key '%s' has a dot" % key) key_path = key if path is None else "%s.%s" % (path, key) if key_path in update_paths: if isinstance(value, dict) and isinstance(current_vars.get(key), dict): update_vars(current_vars.get(key), value, update_paths, key_path) elif isinstance(value, list) and isinstance(current_vars.get(key), list): current_vars.get(key).extend(value) else: # pragma: nocover print("ERROR: Unable to update the path '%s', types '%r', '%r'." % ( key_path, type(value), type(current_vars.get(key)) )) else: current_vars[key] = value PK4@xHJ# # ,c2c.template-1.2.0.dist-info/DESCRIPTION.rstc2c.template ============ Supported template Jinja, Mako, Template. Tools that collect some vars and get them to a template engine. Supported template: `Jinja `_, `Mako `_ and `Template `_. Use ``c2c-template --help`` to get the command line help. Vars file ========= The vars collector gets the vars from YAML files like this one: .. code:: yaml extends: inherit.yaml vars: string_var: a string int_var: 42 interpreted_var: __import__('datetime').date.today() combined_var: 'Today: {interpreted_var:%Y-%m-%d}' facter_json: /usr/bin/facter --json facter_yaml: /usr/bin/facter --yaml pi: console.log(Math.PI.toPrecision(3)) obj: v1: 1 v2: '2' v3: [1, 2, 3] interpreted: python: - interpreted_var bash: - facter_json - facter_yaml json: - facter_json yaml: - facter_yaml node: vars: ["pi"] cmd: ["node", "-e"] update_path: - obj The ``inherit.yaml`` is an other file with the same syntax that will provide initial vars. The ``vars`` section is where we define the vars values, the YAML files support typing, than ``42`` will be an integer. The ``interpreted`` configuration to interpret some vars, ``python``, ``bash``, ``environ``, ``json``, ``yaml`` are predefined interpreter, ``node`` is a custom interpreter. The ``update_path`` is a list of '.'-separated paths that will be updated (for dicts) or appended (for lists), instead of overwritten. The sub path will be implicitly added. We can reuse predefined variables and format them (see ``combined_var``), See: `str.format() `_. Example of usage ================ Interpret variable in a template -------------------------------- .. code:: bash c2c-template --vars vars.yaml --engine jinja --files template.jinja The result will be stored in a file named ``template``. Get the vars ------------ It can be useful to get the variable outside. .. code:: bash `c2c-template --vars vars.yaml --get-vars INT_VAR=int_var string_var` That will set the bash variable ``INT_VAR`` to 42, and ``STRING_VAR`` to 'a string'. Get a configuration file ------------------------ .. code:: bash c2c-template --vars vars.yaml --get-config config.yaml string-var int-var combined-var Will create a file named ``config.yaml`` this: .. code:: yaml string-var: a string int-var: 42 combined-var: Today: 2014-12-12 Build a set of file based on a template --------------------------------------- Create the following vars file (``vars.yaml``): .. code:: yaml vars: var1: common iter: - name: one var2: first - name: two var2: second And the following template (``template.jinja``): .. code:: var1: {{ var1 }} var2: {{ var2 }} And run the following command: .. code:: bash c2c-template --vars vars.yaml --files-builder template.jinja {name}.txt iter This will create two files: the ``one.txt`` file, with:: var1: common var2: first The ``two.txt`` file, with:: var1: common var2: second PK3@xH،44-c2c.template-1.2.0.dist-info/entry_points.txt[console_scripts] c2c-template = c2c.template:main PK4@xHϮ``*c2c.template-1.2.0.dist-info/metadata.json{"classifiers": ["Programming Language :: Python", "Environment :: Console", "Framework :: Bottle", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Topic :: Utilities", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4"], "extensions": {"python.commands": {"wrap_console": {"c2c-template": "c2c.template:main"}}, "python.details": {"contacts": [{"email": "info@camptocamp.com", "name": "camptocamp", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "http://www.camptocamp.com/geospatial-solutions"}}, "python.exports": {"console_scripts": {"c2c-template": "c2c.template:main"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "keywords": ["template"], "metadata_version": "2.0", "name": "c2c.template", "run_requires": [{"requires": ["Jinja2", "Mako", "PyYAML", "bottle"]}], "summary": "Vars collector and template runner.", "version": "1.2.0"}PK3@xHug=3c2c.template-1.2.0.dist-info/namespace_packages.txtc2c PK3@xHug=*c2c.template-1.2.0.dist-info/top_level.txtc2c PK4@xH''\\"c2c.template-1.2.0.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py2-none-any PK4@xHD%ۙ%c2c.template-1.2.0.dist-info/METADATAMetadata-Version: 2.0 Name: c2c.template Version: 1.2.0 Summary: Vars collector and template runner. Home-page: http://www.camptocamp.com/geospatial-solutions Author: camptocamp Author-email: info@camptocamp.com License: UNKNOWN Keywords: template Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Environment :: Console Classifier: Framework :: Bottle Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Topic :: Utilities Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Requires-Dist: Jinja2 Requires-Dist: Mako Requires-Dist: PyYAML Requires-Dist: bottle c2c.template ============ Supported template Jinja, Mako, Template. Tools that collect some vars and get them to a template engine. Supported template: `Jinja `_, `Mako `_ and `Template `_. Use ``c2c-template --help`` to get the command line help. Vars file ========= The vars collector gets the vars from YAML files like this one: .. code:: yaml extends: inherit.yaml vars: string_var: a string int_var: 42 interpreted_var: __import__('datetime').date.today() combined_var: 'Today: {interpreted_var:%Y-%m-%d}' facter_json: /usr/bin/facter --json facter_yaml: /usr/bin/facter --yaml pi: console.log(Math.PI.toPrecision(3)) obj: v1: 1 v2: '2' v3: [1, 2, 3] interpreted: python: - interpreted_var bash: - facter_json - facter_yaml json: - facter_json yaml: - facter_yaml node: vars: ["pi"] cmd: ["node", "-e"] update_path: - obj The ``inherit.yaml`` is an other file with the same syntax that will provide initial vars. The ``vars`` section is where we define the vars values, the YAML files support typing, than ``42`` will be an integer. The ``interpreted`` configuration to interpret some vars, ``python``, ``bash``, ``environ``, ``json``, ``yaml`` are predefined interpreter, ``node`` is a custom interpreter. The ``update_path`` is a list of '.'-separated paths that will be updated (for dicts) or appended (for lists), instead of overwritten. The sub path will be implicitly added. We can reuse predefined variables and format them (see ``combined_var``), See: `str.format() `_. Example of usage ================ Interpret variable in a template -------------------------------- .. code:: bash c2c-template --vars vars.yaml --engine jinja --files template.jinja The result will be stored in a file named ``template``. Get the vars ------------ It can be useful to get the variable outside. .. code:: bash `c2c-template --vars vars.yaml --get-vars INT_VAR=int_var string_var` That will set the bash variable ``INT_VAR`` to 42, and ``STRING_VAR`` to 'a string'. Get a configuration file ------------------------ .. code:: bash c2c-template --vars vars.yaml --get-config config.yaml string-var int-var combined-var Will create a file named ``config.yaml`` this: .. code:: yaml string-var: a string int-var: 42 combined-var: Today: 2014-12-12 Build a set of file based on a template --------------------------------------- Create the following vars file (``vars.yaml``): .. code:: yaml vars: var1: common iter: - name: one var2: first - name: two var2: second And the following template (``template.jinja``): .. code:: var1: {{ var1 }} var2: {{ var2 }} And run the following command: .. code:: bash c2c-template --vars vars.yaml --files-builder template.jinja {name}.txt iter This will create two files: the ``one.txt`` file, with:: var1: common var2: first The ``two.txt`` file, with:: var1: common var2: second PK4@xHhnyy#c2c.template-1.2.0.dist-info/RECORDc2c.template-1.2.0-nspkg.pth,sha256=hmGwcSup_BxULuyoaQob_j6EKXEslxN6jkCkxOjQc0c,296 c2c/template.py,sha256=YqBN-YYpNnVTxa4-QWuK2DGfJ2sjlxagwC0XI3GzU38,15698 c2c.template-1.2.0.dist-info/DESCRIPTION.rst,sha256=i-n9QPES_WEcWZXAkjrvFSg3p_Qk2lfq1IZXC3jqhQk,3363 c2c.template-1.2.0.dist-info/METADATA,sha256=UjNiGmvLhv7cv1qiiY5I6oiXWrzwfSceweEtZLYgr3Q,4249 c2c.template-1.2.0.dist-info/RECORD,, c2c.template-1.2.0.dist-info/WHEEL,sha256=JTb7YztR8fkPg6aSjc571Q4eiVHCwmUDlX8PhuuqIIE,92 c2c.template-1.2.0.dist-info/entry_points.txt,sha256=Ksu_rpE94GGC8xYeIsmmhen-3EMiqAAXuMOZ2ckEEhw,52 c2c.template-1.2.0.dist-info/metadata.json,sha256=ZY54ehRXgLL-_dwSLgLhHg43z1SnJT3sTotgEtMYiT4,1120 c2c.template-1.2.0.dist-info/namespace_packages.txt,sha256=WKT_POy7Qj_8h5UKZmZv4253SztKmT1HvVc3hCV8Wso,4 c2c.template-1.2.0.dist-info/top_level.txt,sha256=WKT_POy7Qj_8h5UKZmZv4253SztKmT1HvVc3hCV8Wso,4 PK4@xHԬ((c2c.template-1.2.0-nspkg.pthPK{^Gߏ8R=R=bc2c/template.pyPK4@xHJ# # ,>c2c.template-1.2.0.dist-info/DESCRIPTION.rstPK3@xH،44-NLc2c.template-1.2.0.dist-info/entry_points.txtPK4@xHϮ``*Lc2c.template-1.2.0.dist-info/metadata.jsonPK3@xHug=3uQc2c.template-1.2.0.dist-info/namespace_packages.txtPK3@xHug=*Qc2c.template-1.2.0.dist-info/top_level.txtPK4@xH''\\"Rc2c.template-1.2.0.dist-info/WHEELPK4@xHD%ۙ%Rc2c.template-1.2.0.dist-info/METADATAPK4@xHhnyy#cc2c.template-1.2.0.dist-info/RECORDPK AHg