# Copyright (c) 2016 Comcast Cable Communications Management, LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at: # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Generation template class import logging, os,sys, cgi, json, jinja2, HTMLParser # Classes register themselves in this dictionary """Mapping of known processors to their classes""" siphons = {} """Mapping of known output formats to their classes""" formats = {} """Generate rendered output for siphoned data.""" class Siphon(object): # Set by subclasses """Our siphon name""" name = None # Set by subclasses """Name of an identifier used by this siphon""" identifier = None # Set by subclasses """The pyparsing object to use to parse with""" _parser = None """The input data""" _cmds = None """Group key to (directory,file) mapping""" _group = None """Logging handler""" log = None """Directory to look for siphon rendering templates""" template_directory = None """Template environment, if we're using templates""" _tplenv = None def __init__(self, template_directory, format): super(Siphon, self).__init__() self.log = logging.getLogger("siphon.process.%s" % self.name) # Get our output format details fmt_klass = formats[format] fmt = fmt_klass() self._format = fmt # Sort out the template search path def _tpldir(name): return os.sep.join((template_directory, fmt.name, name)) self.template_directory = template_directory searchpath = [ _tpldir(self.name), _tpldir("default"), ] loader = jinja2.FileSystemLoader(searchpath=searchpath) self._tplenv = jinja2.Environment( loader=loader, trim_blocks=True, keep_trailing_newline=True) # Convenience, get a reference to the internal escape and # unescape methods in cgi and HTMLParser. These then become # available to templates to use, if needed. self._h = HTMLParser.HTMLParser() self.escape = cgi.escape self.unescape = self._h.unescape # Output renderers """Returns an object to be used as the sorting key in the item index.""" def index_sort_key(self, group): return group """Returns a string to use as the header at the top of the item index.""" def index_header(self): return self.template("index_header") """Returns the string fragment to use for each section in the item index.""" def index_section(self, group): return self.template("index_section", group=group) """Returns the string fragment to use for each entry in the item index.""" def index_entry(self, meta, item): return self.template("index_entry", meta=meta, item=item) """Returns an object, typically a string, to be used as the sorting key for items within a section.""" def item_sort_key(self, item): return item['name'] """Returns a key for grouping items together.""" def group_key(self, directory, file, macro, name): _global = self._cmds['_global'] if file in _global and 'group_label' in _global[file]: self._group[file] = (directory, file) return file self._group[directory] = (directory, None) return directory """Returns a key for identifying items within a grouping.""" def item_key(self, directory, file, macro, name): return name """Returns a string to use as the header when rendering the item.""" def item_header(self, group): return self.template("item_header", group=group) """Returns a string to use as the body when rendering the item.""" def item_format(self, meta, item): return self.template("item_format", meta=meta, item=item) """Returns a string to use as the label for the page reference.""" def page_label(self, group): return "_".join(( self.name, self.sanitize_label(group) )) """Returns a title to use for a page.""" def page_title(self, group): _global = self._cmds['_global'] (directory, file) = self._group[group] if file and file in _global and 'group_label' in _global[file]: return _global[file]['group_label'] if directory in _global and 'group_label' in _global[directory]: return _global[directory]['group_label'] return directory """Returns a string to use as the label for the section reference.""" def item_label(self, group, item): return "__".join(( self.name, item )) """Label sanitizer; for creating Doxygen references""" def sanitize_label(self, value): return value.replace(" ", "_") \ .replace("/", "_") \ .replace(".", "_") """Template processor""" def template(self, name, **kwargs): tpl = self._tplenv.get_template(name + self._format.extension) return tpl.render( this=self, **kwargs) # Processing methods """Parse the input file into a more usable dictionary structure.""" def load_json(self, files): self._cmds = {} self._group = {} line_num = 0 line_start = 0 for filename in files: filename = os.path.relpath(filename) self.log.info("Parsing items in file \"%s\"." % filename) data = None with open(filename, "r") as fd: data = json.load(fd) self._cmds['_global'] = data['global'] # iterate the items loaded and regroup it for item in data["items"]: try: o = self._parser.parse(item['block']) except: self.log.error("Exception parsing item: %s\n%s" \ % (json.dumps(item, separators=(',', ': '), indent=4), item['block'])) raise # Augment the item with metadata o["meta"] = {} for key in item