From 4e64d9e3405d79393978a07b6a385b525f4b3882 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 19 May 2015 13:16:16 +0100 Subject: [PATCH] Start fleshing out build script --- templating/build.py | 98 +++++++++++++++++++++++++++++---- templating/internal/__init__.py | 21 +++++++ templating/internal/sections.py | 18 ++++++ templating/internal/units.py | 24 ++++++++ 4 files changed, 149 insertions(+), 12 deletions(-) mode change 100644 => 100755 templating/build.py create mode 100644 templating/internal/__init__.py create mode 100644 templating/internal/sections.py create mode 100644 templating/internal/units.py diff --git a/templating/build.py b/templating/build.py old mode 100644 new mode 100755 index b2e4266d..4510fa65 --- a/templating/build.py +++ b/templating/build.py @@ -1,18 +1,92 @@ +#!/usr/bin/env python +""" +Builds the Matrix Specification as restructed text (RST). + +Architecture +============ ++-------+ +----------+ +| units |-+ | sections |-+ ++-------+ |-+ === used to create ==> +----------- | === used to create ==> SPEC + +-------+ | +----------+ + +--------+ +RAW DATA (e.g. json) Blobs of RST + +Units +===== +Units are random bits of unprocessed data, e.g. schema JSON files. Anything can +be done to them, from processing it with Jinja to arbitrary python processing. +They are dicts. + +Sections +======== +Sections are short segments of RST. They will be in the final spec, but they +are unordered. They typically use a combination of templates + units to +construct bits of RST. + +Skeleton +======== +The skeleton is a single RST file which is passed through a templating system to +replace variable names with sections. + +Processing +========== +- Execute all unit functions to load units into memory and process them. +- Execute all section functions (which can now be done because the units exist) +- Execute the skeleton function to bring it into a single file. + +Checks +====== +- Any units made which were not used at least once will produce a warning. +- Any sections made but not used in the skeleton will produce a warning. +""" + from jinja2 import Environment, FileSystemLoader +import internal.units +import internal.sections import json -def jsonify(input): - return json.dumps(input, indent=4) +def load_units(): + print "Loading units..." + return internal.units.load() + +def load_sections(env, units): + print "Loading sections..." + return internal.sections.load(env, units) + +def create_from_skeleton(skeleton, sections): + print "Creating spec from skeleton..." + +def check_unaccessed(name, store): + unaccessed_keys = store.get_unaccessed_set() + if len(unaccessed_keys) > 0: + print "Found %s unused %s keys." % (len(unaccessed_keys), name) + print unaccessed_keys + +def main(): + # add a template filter to produce pretty pretty JSON + def jsonify(input): + return json.dumps(input, indent=4) + + # make Jinja aware of the templates and filters + env = Environment(loader=FileSystemLoader("templates")) + env.filters["jsonify"] = jsonify + + # load up and parse the lowest single units possible: we don't know or care + # which spec section will use it, we just need it there in memory for when + # they want it. + units = load_units() + + # use the units to create RST sections + sections = load_sections(env, units) + + # combine all the RST sections into a coherent spec + skeleton = "foo" + spec = create_from_skeleton(skeleton, sections) -env = Environment(loader=FileSystemLoader("templates")) -env.filters["jsonify"] = jsonify + check_unaccessed("units", units) + check_unaccessed("sections", sections) + print spec -example = {} -with open("../example.json", "r") as f: - example = json.loads(f.read()) -event = {} -with open("../event_schema.json", "r") as f: - event = json.loads(f.read()) -template = env.get_template("events.tmpl") -print template.render(example=example, event=event) +if __name__ == '__main__': + main() diff --git a/templating/internal/__init__.py b/templating/internal/__init__.py new file mode 100644 index 00000000..e14e1ecd --- /dev/null +++ b/templating/internal/__init__.py @@ -0,0 +1,21 @@ +from sets import Set + + +class AccessKeyStore(object): + """Storage for arbitrary data. Monitors get calls so we know if they + were used or not.""" + + def __init__(self): + self.data = {} + self.accessed_set = Set() + + def add(self, key, unit_dict): + self.data[key] = unit_dict + + def get(self, key): + self.accessed_set.add(key) + return self.data[key] + + def get_unaccessed_set(self): + data_list = Set(self.data.keys()) + return data_list - self.accessed_set \ No newline at end of file diff --git a/templating/internal/sections.py b/templating/internal/sections.py new file mode 100644 index 00000000..758e0b6f --- /dev/null +++ b/templating/internal/sections.py @@ -0,0 +1,18 @@ +"""Contains all the sections for the spec.""" +from . import AccessKeyStore +import os + +def _render_section_room_events(env, units): + template = env.get_template("events.tmpl") + return template.render(example=example, event=event) + +SECTION_DICT = { + "room-events": _render_section_room_events +} + +def load(env, units): + store = AccessKeyStore() + for unit_key in SECTION_DICT: + unit = SECTION_DICT[unit_key](env, units) + store.add(unit_key, unit) + return store \ No newline at end of file diff --git a/templating/internal/units.py b/templating/internal/units.py new file mode 100644 index 00000000..cae113ff --- /dev/null +++ b/templating/internal/units.py @@ -0,0 +1,24 @@ +"""Contains all the units for the spec.""" +from . import AccessKeyStore +import os + +def _load_examples(): + path = "../event-schemas/examples" + examples = {} + for filename in os.listdir(path): + with open(filename, "r") as f: + print filename + return examples + + +UNIT_DICT = { + "event-examples": _load_examples +} + + +def load(): + store = AccessKeyStore() + for unit_key in UNIT_DICT: + unit = UNIT_DICT[unit_key]() + store.add(unit_key, unit) + return store