Skip to content
Snippets Groups Projects
compiler.py 4.36 KiB
""" Short compilation script from the website
    (essentially just stitches together a bunch of jinja templates)
    
    Created 16-08-2017 by Josh Borrow (joshua.borrow@durham.ac.uk)
"""

import os
from distutils.dir_util import copy_tree

import jinja2
import yaml


def get_from_filesystem(template_names, template_dir=".", data_dir="../data"):
    """ Takes a list of template names and returns a zipped list of template
    objects and associated data values that are ready for rendering wih the
    render_template function. """

    template_loader = jinja2.FileSystemLoader(searchpath=template_dir)
    template_env = jinja2.Environment(loader=template_loader)

    templates = list(map(template_env.get_template, template_names))
    data = get_associated_data(template_names, data_dir)

    return zip(templates, data)


def get_associated_data(template_names, data_dir="../data"):
    """ Grabs the data from yaml files within the data directory if they exist,
        and if not returns an empty dictionary for that item. """

    data = []

    for template in template_names:
        # swap that .html for a .yaml
        stub = template.split(".")[0]
        filename = f"{data_dir}/{stub}.yaml"

        try:
            with open(filename, "r") as f:
                data.append(yaml.load(f))

        except FileNotFoundError:
            data.append({})

    return data


def render_template(template, args, data_dir="../data"):
    """ Args is a dictionary of the local variables required for
        rendering the template. """

    # Interestingly this is the fastest way to concatenate two dictionaries,
    # see https://stackoverflow.com/questions/1781571
    args = dict(global_variables(template, data_dir), **args)

    return template.render(**args)


def process_navbar(raw, active):
    """ Processes the navbar from our favourite friends over at global.yaml """

    output = []

    for key, item in enumerate(raw["navbar"]):
        classes = []

        if key != len(raw["navbar"])-1:        # Lines between items are handled
            classes.append("rightborder")   # by borders on the right of items
        
        if item[1] == active:  # If current template
            classes.append("active")

        output.append([item[0], item[1], " ".join(classes)])

    raw["navbar"] = output

    return raw
    

def global_variables(active, data_dir="../data"):
    """ Grabs the global variables from the data directory and sticks them into
        a dicitonary ready for template rendering.
        
        Active is the name of the current page's template and is used in the
        production of the processed navbar. """

    with open("{}/global.yaml".format(data_dir), "r") as f:
        raw = yaml.load(f)  # We need to process the navbar.

    return process_navbar(raw, active)


def render(render_pages, data_dir, template_dir, output_dir):
    """ Main rendering function for all of the pages. """

    data = get_from_filesystem(render_pages, template_dir, data_dir)
    output = [render_template(page, args, data_dir) for page, args in data]

    # Save the files into the output_dir
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    for page, data in zip(render_pages, output):
        with open("{}/{}".format(output_dir, page), "w") as f:
            f.write(data)

    return


def copy_static(directories, output_dir):
    """ Copies the (static) files from the original directory to the output """
    if type(directories) == list:
        for directory in directories: 
            copy_tree(directory, output_dir)
    else:
        copy_tree(directories, output_dir)

    return
    

if __name__ == "__main__":
    import about

    DATA_DIR = "./data"
    TEMPLATE_DIR = "./templates"
    OUTPUT_DIR = "./compiled"

    PAGES = [
        "index.html",
        "pubs.html",
        "talks.html",
        "about.html",
    ]

    STATIC = [
        "stylesheets",
        "images",
    ]

    print("Compiling markdown to HTML and saving in the about.yaml file...")

    about.compile_to_yaml(
        in_filename="about_meta.yaml",
        out_filename="about.yaml",
        data_dir=DATA_DIR
    )

    print("Rendering templates...")

    render(
        render_pages=PAGES,
        data_dir=DATA_DIR,
        template_dir=TEMPLATE_DIR,
        output_dir=OUTPUT_DIR,
    )

    print("Copying static files...")

    copy_static(
        STATIC,
        OUTPUT_DIR
    )