ansible-doctor/ansibledoctor/DocumentationGenerator.py

142 lines
6.1 KiB
Python

#!/usr/bin/env python3
import codecs
import glob
import json
import ntpath
import os
import pprint
import sys
import jinja2.exceptions
import ruamel.yaml
from jinja2 import Environment
from jinja2 import FileSystemLoader
from six import binary_type
from six import text_type
from ansibledoctor.Config import SingleConfig
from ansibledoctor.Utils import FileUtils
from ansibledoctor.Utils import SingleLog
class Generator:
def __init__(self, doc_parser):
self.template_files = []
self.extension = "j2"
self._parser = None
self.config = SingleConfig()
self.log = SingleLog()
self.log.info("Using template dir: " + self.config.get_template_base_dir())
self._parser = doc_parser
self._scan_template()
def _scan_template(self):
"""
Search for Jinja2 (.j2) files to apply to the destination.
:return: None
"""
base_dir = self.config.get_template_base_dir()
for file in glob.iglob(base_dir + "/**/*." + self.extension, recursive=True):
relative_file = file[len(base_dir) + 1:]
if ntpath.basename(file)[:1] != "_":
self.log.trace("[GENERATOR] found template file: " + relative_file)
self.template_files.append(relative_file)
else:
self.log.debug("[GENERATOR] ignoring template file: " + relative_file)
def _create_dir(self, directory):
if not self.config.dry_run:
os.makedirs(directory, exist_ok=True)
else:
self.log.info("[GENERATOR][DRY] Creating dir: " + dir)
def _write_doc(self):
files_to_overwite = []
for file in self.template_files:
doc_file = self.config.get_output_dir() + "/" + file[:-len(self.extension) - 1]
if os.path.isfile(doc_file):
files_to_overwite.append(doc_file)
if len(files_to_overwite) > 0 and self.config.template_overwrite is False:
SingleLog.print("This files will be overwritten:", files_to_overwite)
if not self.config.dry_run:
resulst = FileUtils.query_yes_no("Do you want to continue?")
if resulst != "yes":
sys.exit()
for file in self.template_files:
doc_file = self.config.get_output_dir() + "/" + file[:-len(self.extension) - 1]
source_file = self.config.get_template_base_dir() + "/" + file
self.log.trace("[GENERATOR] Writing doc output to: " + doc_file + " from: " + source_file)
# make sure the directory exists
self._create_dir(os.path.dirname(os.path.realpath(doc_file)))
if os.path.exists(source_file) and os.path.isfile(source_file):
with open(source_file, "r") as template:
data = template.read()
if data is not None:
try:
print(json.dumps(self._parser.get_data(), indent=4, sort_keys=True))
jenv = Environment(loader=FileSystemLoader(self.config.get_template_base_dir()), lstrip_blocks=True, trim_blocks=True, autoescape=True)
jenv.filters["to_nice_yaml"] = self._to_nice_yaml
data = jenv.from_string(data).render(self._parser.get_data(), role=self._parser.get_data())
if not self.config.dry_run:
with open(doc_file, "w") as outfile:
outfile.write(data)
self.log.info("Writing to: " + doc_file)
else:
self.log.info("[GENERATOR][DRY] Writing to: " + doc_file)
except jinja2.exceptions.UndefinedError as e:
self.log.error("Jinja2 templating error: <" + str(e) + "> when loading file: '" + file + "', run in debug mode to see full except")
if self.log.log_level < 1:
raise
except UnicodeEncodeError as e:
self.log.error("At the moment I'm unable to print special chars: <" + str(e) + ">, run in debug mode to see full except")
if self.log.log_level < 1:
raise
sys.exit()
def _to_nice_yaml(self, a, indent=4, *args, **kw):
"""Make verbose, human readable yaml."""
yaml = ruamel.yaml.YAML()
yaml.indent(mapping=indent, sequence=(indent * 2), offset=indent)
stream = ruamel.yaml.compat.StringIO()
yaml.dump(a, stream, **kw)
return stream.getvalue().rstrip()
def print_to_cli(self):
for file in self.template_files:
source_file = self.config.get_template_base_dir() + "/" + file
with open(source_file, "r") as template:
data = template.read()
if data is not None:
try:
data = Environment(loader=FileSystemLoader(self.config.get_template_base_dir()), lstrip_blocks=True, trim_blocks=True, autoescape=True).from_string(data).render(self._parser.get_data(), r=self._parser)
print(data)
except jinja2.exceptions.UndefinedError as e:
self.log.error("Jinja2 templating error: <" + str(e) + "> when loading file: '" + file + "', run in debug mode to see full except")
if self.log.log_level < 1:
raise
except UnicodeEncodeError as e:
self.log.error("At the moment I'm unable to print special chars: <" + str(e) + ">, run in debug mode to see full except")
if self.log.log_level < 1:
raise
except Exception:
print("Unexpected error:", sys.exc_info()[0])
raise
def render(self):
if self.config.use_print_template:
self.print_to_cli()
else:
self.log.info("Using output dir: " + self.config.get_output_dir())
self._write_doc()