#!/usr/bin/env python3 import importlib import json import os import os.path import sys import jinja2 import yaml J2_MODULES_DEFAULT = 'os os.path sys netaddr psutil re wcmatch' J2_SUFFIX_DEFAULT = '.j2' J2_CFG_PATHS = [ '/angie/jinja', '/etc/angie/jinja', ] J2_CFG_EXTS = [ 'yml', 'yaml', 'json', ] J2_SEARCH_PATH = [ '.', '/etc/angie', ] J2_EXT_LIST = [ 'jinja2.ext.do', 'jinja2.ext.loopcontrols', ] J2_MODULES = sorted(set(os.getenv('NGX_JINJA_MODULES', J2_MODULES_DEFAULT).split(sep=' '))) ME = sys.argv[0] J2_SUFFIX = os.getenv('NGX_JINJA_SUFFIX', J2_SUFFIX_DEFAULT) if J2_SUFFIX == '': raise ValueError('NGX_JINJA_SUFFIX is empty') if not J2_SUFFIX.startswith('.'): raise ValueError('NGX_JINJA_SUFFIX does not start with dot (".")') J2_CONFIG = os.getenv('NGX_JINJA_CONFIG', '') if (J2_CONFIG != '') and (not os.path.exists(J2_CONFIG)): print(f'{ME}: config does not exist, skipping: {J2_CONFIG}', file=sys.stderr) if len(sys.argv) < 2: raise ValueError('not enough arguments (needed: 2)') if len(sys.argv) > 3: raise ValueError('too many arguments (needed: 2)') if not sys.argv[1]: raise ValueError('specify input file') input_file = sys.argv[1] if not os.path.exists(input_file): raise ValueError('input file does not exist') if len(sys.argv) == 3: if not sys.argv[2]: raise ValueError('specify output file') output_file = sys.argv[2] else: output_file, ext = os.path.splitext(input_file) if ext != J2_SUFFIX: raise ValueError(f'input file name extension mismatch (not a "{J2_SUFFIX}")') if input_file == output_file: raise ValueError('unable to process template inplace') kwargs = {} for m in J2_MODULES: kwargs[m] = importlib.import_module(m) kwargs['env'] = os.environ kwargs['cfg'] = {} def merge_dict_from_file(filename): if not filename: return False if not isinstance(filename, str): return False if filename == '': return False if not os.path.exists(filename): return False if not os.path.isfile(filename): print(f'{ME}: not a file, skipping: {filename}', file=sys.stderr) return False if filename.endswith('.yml') or filename.endswith('.yaml'): with open(filename, mode='r', encoding='utf-8') as fx: x = yaml.safe_load(fx) kwargs['cfg'] = kwargs['cfg'] | x return True if filename.endswith('.json'): with open(filename, mode='r', encoding='utf-8') as fx: x = json.load(fx) kwargs['cfg'] = kwargs['cfg'] | x return True print(f'{ME}: non-recognized name extension: {filename}', file=sys.stderr) return False if (J2_CONFIG != '') and (os.path.isfile(J2_CONFIG)): merge_dict_from_file(J2_CONFIG) else: for base in J2_CFG_PATHS: for full in [ base + '.' + ext for ext in J2_CFG_EXTS ]: if merge_dict_from_file(full): break continue j2_loader = jinja2.FileSystemLoader(J2_SEARCH_PATH, followlinks=True) j2_environ = jinja2.Environment(loader=j2_loader, extensions=J2_EXT_LIST) j2_template = j2_environ.get_template(input_file) j2_stream = j2_template.stream(**kwargs) j2_stream.disable_buffering() j2_stream.dump(output_file, encoding='utf-8')