#!/usr/bin/env python3 import configparser import json import os import socket import sys import dotenv import toml import yaml from jinja2 import Environment, TemplateError import argparse argsparser = argparse.ArgumentParser(description='Jinja Template Helper') infilegroup = argsparser.add_mutually_exclusive_group(required=False) infilegroup.add_argument('--yaml', dest='yaml_file', type=str, required=False, help='YAML file path') infilegroup.add_argument('--json', dest='json_file', type=str, required=False, help='JSON file path') infilegroup.add_argument('--toml', dest='toml_file', type=str, required=False, help='TOML file path') infilegroup.add_argument('--ini', dest='ini_file', type=str, required=False, help='INI fil path') argsparser.add_argument('--env', dest='env_file', type=bool, required=False, default=False, help='Load .env file from current directory') argsparser.add_argument('--output', default='/dev/stdout', help='Output File') argsparser.add_argument('infile', metavar="input-file", help="Input File") # Print Errors def print_error(*args, **kwargs): print(*args, file=sys.stderr, **kwargs) # Jinja Environment # ----------------- jenv = Environment(autoescape=True, trim_blocks=False, keep_trailing_newline=True, optimized=True) # Jinja Filters # ------------- def filter_env(name, defvalue=""): return os.getenv(name, defvalue) def filter_domain2ldap(value, unit='dc', delimiter='.'): parts = value.split(delimiter) concat_domain = "" for part in parts: if len(concat_domain) > 0: concat_domain += "," concat_domain = concat_domain + unit + "=" + part return concat_domain def filter_hostbyaddr(value): addr = socket.gethostbyaddr(value) if addr: return addr[0] def filter_hostbyname(value): return socket.gethostbyname(value) jenv.filters['env'] = filter_env jenv.filters['ldap_dn'] = filter_domain2ldap jenv.filters['hostbyaddr'] = filter_hostbyaddr jenv.filters['hostbyname'] = filter_hostbyname # Loader # ------ def load_template(filename): try: with open(filename) as file_: template = jenv.from_string(file_.read()) return template except TemplateError as exc: print_error("Template Error:", exc.message) return None def load_yaml_file(filename): if os.path.isfile(filename): with open(filename, 'r') as instream: try: return yaml.safe_load(instream) except yaml.YAMLError as exc: print_error("YAML error:", exc) else: print_error("ERROR:", filename, "- File not found") return None def load_toml_file(filename): if os.path.isfile(filename): with open(filename, 'r') as instream: try: return toml.load(instream) except toml.TomlDecodeError as exc: print_error("TOML error:", exc) else: print_error("ERROR:", filename, "- File not found") return None def load_json_file(filename): if os.path.isfile(filename): with open(filename, 'r') as instream: try: return json.load(instream) except json.JSONDecodeError as exc: print_error("JSON error: [", exc.lineno, ",", exc.colno, "]", exc.msg) else: print_error("ERROR:", filename, "- File not found") return None def load_ini_file(filename): iniparser = configparser.ConfigParser() if os.path.isfile(filename): iniparser.read(filename) return iniparser.items() else: print_error("ERROR:", filename, "- File not found") return None # Render # ------ def render_template(template, outfile, variables=None): try: with open(outfile, 'w') as file_: file_.write(template.render(variables)) if variables else file_.write(template.render()) except TemplateError as exc: print_error("Rendering Error:", exc.message) if __name__ == '__main__': # Read command line arguments args = argsparser.parse_args() tpl = load_template(args.infile) content = None # If template was found if tpl: if args.env_file: dotenv.load_dotenv(dotenv.find_dotenv(raise_error_if_not_found=False)) # Load content from file, if present if args.yaml_file: content = load_yaml_file(args.yaml_file) elif args.json_file: content = load_json_file(args.json_file) elif args.toml_file: content = load_toml_file(args.toml_file) elif args.ini_file: content = load_ini_file(args.ini_file) # Render template with or without external content render_template(tpl, args.output, content) if content else render_template(tpl, args.output) else: exit(1) exit(0)