|
#!/usr/bin/env python |
|
# -*- coding: utf-8 -*- |
|
|
|
from jinja2 import Environment, FileSystemLoader |
|
import yaml |
|
import logging |
|
import os |
|
import errno |
|
import argparse |
|
|
|
|
|
def write_file(filepath, data): |
|
'''Write data to file, creating folders if don't exist''' |
|
|
|
logging.info("Writing {0}".format(filepath)) |
|
|
|
try: |
|
os.makedirs(os.path.dirname(filepath)) |
|
except OSError as e: |
|
if e.errno != errno.EEXIST: |
|
raise |
|
|
|
with open(filepath, 'w') as fd: |
|
fd.write(data) |
|
fd.write("\n") |
|
|
|
|
|
class J2RenderError(Exception): |
|
pass |
|
|
|
|
|
class Env(): |
|
|
|
ITEM_EXT = ['yml', 'yaml'] |
|
TMPL_EXT = ['j2', 'jinja'] |
|
|
|
def __init__(self, output, templates, variables): |
|
'''Initialize the configuration env |
|
|
|
- parse templates tree to get the list of resources |
|
- parse variables tree to get a dictionary of common data |
|
''' |
|
|
|
self.output = output |
|
self.templates = templates |
|
self.variables = variables |
|
|
|
self.resources = next(os.walk(self.templates))[1] |
|
|
|
common_files = [ |
|
filename for filename in next(os.walk(self.variables))[2] |
|
if filename.endswith(tuple(self.ITEM_EXT)) |
|
] |
|
self.common = { |
|
'system': os.environ, |
|
} |
|
|
|
for filename in common_files: |
|
key = os.path.splitext(os.path.basename(filename))[0] |
|
with open(os.path.join(self.variables, filename)) as fd: |
|
logging.info("Register common file: {0}".format(key)) |
|
self.common[key] = yaml.load(fd) |
|
|
|
def render_resource(self, resource, items): |
|
'''Render all templates under $templates/$resource/ folder |
|
|
|
For every item in the items list, create a rendered variant of |
|
the resource folder. |
|
''' |
|
|
|
tmpl_path = os.path.join(self.templates, resource) |
|
item_path = os.path.join(self.variables, resource) |
|
|
|
for item in items: |
|
|
|
with open(os.path.join(item_path, item)) as fd: |
|
item_data = yaml.load(fd) |
|
|
|
J2Env = Environment(loader=FileSystemLoader(tmpl_path)) |
|
|
|
for template in J2Env.list_templates(extensions=self.TMPL_EXT): |
|
output_data = J2Env.get_template(template).render( |
|
data=item_data, |
|
**self.common |
|
) |
|
output_file = os.path.join( |
|
self.output, |
|
resource, |
|
os.path.splitext(item)[0], |
|
os.path.splitext(template)[0], |
|
) |
|
write_file(output_file, output_data) |
|
|
|
def render(self, resource=None, item=None): |
|
|
|
if resource: |
|
if resource not in self.resources: |
|
raise(J2RenderError("unknown resource {0}".format(resource))) |
|
else: |
|
resources = [resource] |
|
else: |
|
resources = self.resources |
|
|
|
for resource in resources: |
|
if not item: |
|
items = [] |
|
|
|
item_path = os.path.join(self.variables, resource) |
|
if os.path.isdir(item_path): |
|
for filename in next(os.walk(item_path))[2]: |
|
if filename.endswith(tuple(self.ITEM_EXT)): |
|
items.append(filename) |
|
|
|
else: |
|
items = [item] |
|
|
|
self.render_resource(resource, items) |
|
|
|
|
|
def cli(): |
|
|
|
parser = argparse.ArgumentParser( |
|
description='Render resource templates with items', |
|
) |
|
|
|
parser.add_argument('-d', '--debug', action='store_true', |
|
help='enable debug output') |
|
|
|
parser.add_argument('-o', '--output', default='_output', |
|
help='path to results') |
|
parser.add_argument('-t', '--templates', default='templates', |
|
help='path to templates') |
|
parser.add_argument('-v', '--variables', default='variables', |
|
help='path to variables') |
|
parser.add_argument('-r', '--resource', default=None, |
|
help='resource to render') |
|
parser.add_argument('-i', '--item', default=None, |
|
help='name of the item file') |
|
|
|
args = parser.parse_args() |
|
|
|
if args.debug: |
|
logging.basicConfig(level=logging.DEBUG) |
|
|
|
env = Env( |
|
output=args.output, |
|
templates=args.templates, |
|
variables=args.variables, |
|
) |
|
|
|
env.render(args.resource, args.item) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
cli() |