167 lines
3.5 KiB
Python
167 lines
3.5 KiB
Python
import codecs, traceback, os, json
|
|
|
|
from os import listdir, makedirs
|
|
from os.path import isfile, isdir, getmtime, abspath
|
|
|
|
from jinja2 import Environment, FileSystemLoader, ChoiceLoader
|
|
from hamlpy.hamlpy import Compiler
|
|
from markdown import markdown
|
|
|
|
from . import logging
|
|
|
|
|
|
__all__ = ['addSearchPath', 'delSearchPath', 'addBuildPath', 'delSearchPath', 'setup', 'render_template', 'build_templates']
|
|
|
|
|
|
env = None
|
|
|
|
global_variables = {
|
|
'markdown': markdown,
|
|
'lighten': color().lighten,
|
|
'darken': color().darken,
|
|
'saturate': color().saturate,
|
|
'desaturate': color().desaturate,
|
|
'rgba': color().rgba
|
|
}
|
|
|
|
config = {
|
|
search_path: str(),
|
|
build_path_pairs: dict()
|
|
}
|
|
|
|
|
|
def addSearchPath(path):
|
|
tplPath = abspath(path)
|
|
|
|
if tplPath not in search_path:
|
|
search_path.append(tplPath)
|
|
|
|
|
|
def delSearchPath(path):
|
|
tplPath = abspath(path)
|
|
|
|
if tplPath in search_path:
|
|
search_path.remove(tplPath)
|
|
|
|
|
|
def addBuildPath(name, source, destination):
|
|
src = abspath(source)
|
|
dest = abspath(destination)
|
|
|
|
if not isdir(src):
|
|
raise FileNotFoundError('Source path doesn\'t exist: {src}')
|
|
|
|
build_path_pairs.update({
|
|
name: {
|
|
'source': src,
|
|
'destination': dest
|
|
}
|
|
})
|
|
|
|
addSearchPath(dest)
|
|
|
|
|
|
def delBuildPath(name):
|
|
if not build_path_pairs.get(name):
|
|
raise ValueError(f'"{name}" not in build paths')
|
|
|
|
del build_path_pairs(src)
|
|
|
|
|
|
def getBuildPath(name=None):
|
|
paths = list()
|
|
template = build_path_pairs.get(name)
|
|
|
|
if name:
|
|
if template:
|
|
paths.append((template['source'], template['destination']))
|
|
|
|
else:
|
|
raise ValueError(f'"{name}" not in build paths')
|
|
|
|
else:
|
|
for k, tpl in build_path_pairs.items():
|
|
paths.append((tpl['source'], tpl['destination']))
|
|
|
|
return paths
|
|
|
|
|
|
def setup():
|
|
env = Environment(
|
|
loader=ChoiceLoader([FileSystemLoader(path) for path in tpl_paths])
|
|
)
|
|
|
|
|
|
def render_template(tplfile, context, headers=None, cookies=None, status=200):
|
|
data = global_variables.copy()
|
|
data.update(context)
|
|
|
|
if headers:
|
|
data['headers'] = request
|
|
|
|
if cookies:
|
|
data['cookies'] = cookies
|
|
|
|
if not isinstance(context, dict):
|
|
raise TypeError(f'Context for {tplfile} not a dict')
|
|
|
|
return env.get_template(tplfile).render(data)
|
|
|
|
|
|
def build_templates(name=None):
|
|
paths = getBuildPath(name)
|
|
|
|
for tplPaths in paths:
|
|
src = tplPaths['source']
|
|
dest = tplPaths['destination']
|
|
|
|
timefile = f'{dest}/times.json'
|
|
updated = False
|
|
|
|
if not isdir(f'{dest}'):
|
|
makedirs(f'{dest}')
|
|
|
|
if isfile(timefile):
|
|
try:
|
|
times = json.load(open(timefile))
|
|
|
|
except:
|
|
times = {}
|
|
|
|
else:
|
|
times = {}
|
|
|
|
for filename in listdir(f'{src}/templates'):
|
|
fullPath = f'{src}/{filename}'
|
|
modtime = getmtime(fullPath)
|
|
base, ext = filename.split('.')
|
|
|
|
if ext != 'haml':
|
|
pass
|
|
|
|
elif base not in times or times.get(base) != modtime:
|
|
updated = True
|
|
logging.verbose(f"Template '{filename}' was changed. Building...")
|
|
|
|
try:
|
|
destination = f'{dest}/{base}.html'
|
|
haml_lines = codecs.open(fullPath, 'r', encoding='utf-8').read().splitlines()
|
|
|
|
compiler = Compiler()
|
|
output = compiler.process_lines(haml_lines)
|
|
outfile = codecs.open(destination, 'w', encoding='utf-8')
|
|
outfile.write(output)
|
|
|
|
logging.info(f"Template '{filename}' has been built")
|
|
|
|
except Exception as e:
|
|
'''I'm actually not sure what sort of errors can happen here, so generic catch-all for now'''
|
|
traceback.print_exc()
|
|
logging.error(f'Failed to build {filename}: {e}')
|
|
|
|
times[base] = modtime
|
|
|
|
if updated:
|
|
with open(timefile, 'w') as filename:
|
|
filename.write(json.dumps(times))
|