You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
5.0 KiB
140 lines
5.0 KiB
5 years ago
|
#!/usr/bin/env python3
|
||
|
"""Simple tex jinja2 Precompiler.
|
||
|
With slightly different syntax:
|
||
|
{{ ... }} => \VAR{ ... } for Expressions to print to the template output
|
||
|
{% ... %} => \BLOCK{ ... } for Statements
|
||
|
{# ... #} => \#{ ... } for Comments not included in the template output
|
||
|
# ... ## => %$ ... %# for Line Statements
|
||
|
|
||
|
Usage:
|
||
|
pretex [<templates>] --data=<yamlfile> [options]
|
||
|
|
||
|
Arguments:
|
||
|
<templates> Compiles every given file ending with ".j2.tex" into
|
||
|
respective ".tex" file. [default: "**/*.j2.tex"]
|
||
|
|
||
|
Options:
|
||
|
-h --help Show this screen.
|
||
|
-p --pdf Also compiles rendered ".tex" file to pdf.
|
||
|
-o --out=<file> Save output to file.
|
||
|
-d --data=<yamlfile> YAML files with data for the template.
|
||
|
-t --tex=<compiler> LaTeX compiler to use [default: pdflatex]
|
||
|
-a --arg=<args> LaTeX compiler arguments
|
||
|
[default: -synctex=1 -interaction=nonstopmode -file-line-error]
|
||
|
-b --bib=<bib> bibTeX compiler to use. [default: bibtex]
|
||
|
-c --copy=<dir> Gather copies of all resulting pdf files in a folder.
|
||
|
--chain=<chain> Define the render command.
|
||
|
[default: {TEX} {ARG} {document}.tex, {BIB} {document}, {TEX} {ARG} {document}.tex, {TEX} {ARG} {document}.tex]
|
||
|
--clean Clean aux files.
|
||
|
-f --files=<end> Files to clean.
|
||
|
[default: *.aux, *.bbl, *.blg, *.idx, *.ind, *.lof, *.lot, *.out, *.toc, *.acn, *.acr, *.alg, *.glg, *.glo, *.gls, *.ist, *.fls, *.log, *.fdb_latexmk, *.synctex.gz]
|
||
|
"""
|
||
|
|
||
|
import yaml
|
||
|
import glob
|
||
|
import jinja2
|
||
|
import os
|
||
|
from docopt import docopt
|
||
|
import dateparser
|
||
|
import datetime
|
||
|
import subprocess
|
||
|
import functools
|
||
|
import shlex
|
||
|
from shutil import copyfile
|
||
|
|
||
|
|
||
|
class RelEnvironment(jinja2.Environment):
|
||
|
"""Override join_path() to enable relative template paths."""
|
||
|
def join_path(self, template, parent):
|
||
|
return os.path.normpath(os.path.join(os.path.dirname(parent), template))
|
||
|
|
||
|
|
||
|
def datetime_filter(dt, format=None):
|
||
|
"""Jinja template filter to format a datetime object."""
|
||
|
if dt is None:
|
||
|
# By default, render an empty string.
|
||
|
return ''
|
||
|
if not isinstance(dt, datetime.datetime):
|
||
|
dt = dateparser.parse(dt, settings={'DATE_ORDER': 'DMY'})
|
||
|
if format is None:
|
||
|
# No format is given in the template call.
|
||
|
# Use a default format.
|
||
|
formatted_date = dt.strftime('%Y-%m-%d - %A')
|
||
|
formatted_time =\
|
||
|
dt.strftime('%I:%M%p').lstrip('0').lower()
|
||
|
formatted = '%s at %s' %\
|
||
|
(formatted_date, formatted_time)
|
||
|
else:
|
||
|
formatted = dt.strftime(format)
|
||
|
return formatted
|
||
|
|
||
|
|
||
|
def get_latex_toolchain(arguments, document):
|
||
|
return arguments["--chain"].format(
|
||
|
TEX=arguments["--tex"],
|
||
|
ARG=arguments["--arg"],
|
||
|
BIB=arguments["--bib"],
|
||
|
document=document).split(",")
|
||
|
|
||
|
|
||
|
def compile_all(data, templates, pdf, cmd, copy, clean):
|
||
|
if templates is None:
|
||
|
templates = "**/*.j2.tex"
|
||
|
for tex_file in glob.glob(templates, recursive=True):
|
||
|
if tex_file[-7:] == ".j2.tex":
|
||
|
compiled_file = f"{tex_file[:-7]}.tex"
|
||
|
print(compile_file(tex_file, data, compiled_file))
|
||
|
|
||
|
if not pdf:
|
||
|
continue
|
||
|
path, filename = os.path.split(compiled_file)
|
||
|
for command in cmd(filename[:-4]):
|
||
|
subprocess.call(shlex.split(command), cwd=path, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||
|
|
||
|
if copy:
|
||
|
if not os.path.exists(copy):
|
||
|
os.makedirs(copy)
|
||
|
copyfile(f"{tex_file[:-7]}.pdf", os.path.join(copy, f"{filename[:-4]}.pdf"))
|
||
|
|
||
|
if clean:
|
||
|
for ending in clean.split(","):
|
||
|
for file in glob.glob(os.path.join(path, ending.strip()), recursive=True):
|
||
|
os.remove(file)
|
||
|
|
||
|
|
||
|
def compile_file(tex_file, data, file=None):
|
||
|
template = latex_jinja_env.get_template(tex_file)
|
||
|
rendered = template.render(**data)
|
||
|
if file is None:
|
||
|
return rendered
|
||
|
f = open(file, 'w')
|
||
|
f.write(rendered)
|
||
|
f.close()
|
||
|
return f'"{tex_file}" successful rendered into "{file}"'
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
arguments = docopt(__doc__)
|
||
|
|
||
|
latex_jinja_env = RelEnvironment(
|
||
|
block_start_string = '\\BLOCK{',
|
||
|
block_end_string = '}',
|
||
|
variable_start_string = '\\VAR{',
|
||
|
variable_end_string = '}',
|
||
|
comment_start_string = '\\#{',
|
||
|
comment_end_string = '}',
|
||
|
line_statement_prefix = '%§',
|
||
|
line_comment_prefix = '%#',
|
||
|
trim_blocks = True,
|
||
|
autoescape = False,
|
||
|
loader = jinja2.FileSystemLoader(os.path.abspath('.')),
|
||
|
)
|
||
|
|
||
|
latex_jinja_env.filters['datetime'] = datetime_filter
|
||
|
|
||
|
with open(arguments['--data']) as file:
|
||
|
data = yaml.load(file, Loader=yaml.FullLoader)["data"]
|
||
|
|
||
|
cmd = functools.partial(get_latex_toolchain, arguments)
|
||
|
compile_all(data, arguments['<templates>'], arguments['--pdf'], cmd, arguments['--copy'], arguments['--clean'] and arguments['--files'])
|