2024-07-11 13:37:35 +03:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
import importlib
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import os.path
|
|
|
|
import sys
|
|
|
|
|
|
|
|
import jinja2
|
|
|
|
import yaml
|
|
|
|
|
2024-07-15 21:51:40 +03:00
|
|
|
|
|
|
|
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=' ')))
|
2024-07-11 13:37:35 +03:00
|
|
|
|
|
|
|
ME = sys.argv[0]
|
|
|
|
|
2024-07-15 21:51:40 +03:00
|
|
|
J2_SUFFIX = os.getenv('NGX_JINJA_SUFFIX', J2_SUFFIX_DEFAULT)
|
|
|
|
if J2_SUFFIX == '':
|
2024-07-11 13:37:35 +03:00
|
|
|
raise ValueError('NGX_JINJA_SUFFIX is empty')
|
2024-07-15 21:51:40 +03:00
|
|
|
if not J2_SUFFIX.startswith('.'):
|
2024-07-11 13:37:35 +03:00
|
|
|
raise ValueError('NGX_JINJA_SUFFIX does not start with dot (".")')
|
|
|
|
|
2024-07-15 21:51:40 +03:00
|
|
|
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)
|
2024-07-11 13:37:35 +03:00
|
|
|
|
|
|
|
|
|
|
|
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)
|
2024-07-15 21:51:40 +03:00
|
|
|
if ext != J2_SUFFIX:
|
|
|
|
raise ValueError(f'input file name extension mismatch (not a "{J2_SUFFIX}")')
|
2024-07-11 13:37:35 +03:00
|
|
|
|
|
|
|
if input_file == output_file:
|
|
|
|
raise ValueError('unable to process template inplace')
|
|
|
|
|
|
|
|
kwargs = {}
|
2024-07-15 21:51:40 +03:00
|
|
|
for m in J2_MODULES:
|
2024-07-11 13:37:35 +03:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2024-07-15 21:51:40 +03:00
|
|
|
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')
|