1 # Copyright (c) 2016 Comcast Cable Communications Management, LLC.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Generation template class
17 import logging, os,sys, cgi, json, jinja2, HTMLParser
19 # Classes register themselves in this dictionary
20 """Mapping of known processors to their classes"""
24 """Generate rendered output for siphoned data."""
32 """Name of an identifier used by this siphon"""
36 """The pyparsing object to use to parse with"""
42 """Group key to (directory,file) mapping"""
48 """Directory to look for siphon rendering templates"""
49 template_directory = None
51 """Template environment, if we're using templates"""
54 def __init__(self, template_directory=None):
55 super(Siphon, self).__init__()
56 self.log = logging.getLogger("siphon.process.%s" % self.name)
58 if template_directory is not None:
59 self.template_directory = template_directory
61 template_directory + "/" + self.name,
62 template_directory + "/" + "default",
64 loader = jinja2.FileSystemLoader(searchpath=searchpath)
65 self._tplenv = jinja2.Environment(
68 keep_trailing_newline=True)
70 # Convenience, get a reference to the internal escape and
71 # unescape methods in cgi and HTMLParser. These then become
72 # available to templates to use, if needed.
73 self._h = HTMLParser.HTMLParser()
74 self.escape = cgi.escape
75 self.unescape = self._h.unescape
80 """Returns an object to be used as the sorting key in the item index."""
81 def index_sort_key(self, group):
84 """Returns a string to use as the header at the top of the item index."""
85 def index_header(self):
86 return self.template("index_header")
88 """Returns the string fragment to use for each section in the item
90 def index_section(self, group):
91 return self.template("index_section", group=group)
93 """Returns the string fragment to use for each entry in the item index."""
94 def index_entry(self, meta, item):
95 return self.template("index_entry", meta=meta, item=item)
97 """Returns an object, typically a string, to be used as the sorting key
98 for items within a section."""
99 def item_sort_key(self, item):
102 """Returns a key for grouping items together."""
103 def group_key(self, directory, file, macro, name):
104 _global = self._cmds['_global']
106 if file in _global and 'group_label' in _global[file]:
107 self._group[file] = (directory, file)
110 self._group[directory] = (directory, None)
113 """Returns a key for identifying items within a grouping."""
114 def item_key(self, directory, file, macro, name):
117 """Returns a string to use as the header when rendering the item."""
118 def item_header(self, group):
119 return self.template("item_header", group=group)
121 """Returns a string to use as the body when rendering the item."""
122 def item_format(self, meta, item):
123 return self.template("item_format", meta=meta, item=item)
125 """Returns a string to use as the label for the page reference."""
126 def page_label(self, group):
129 self.sanitize_label(group)
132 """Returns a title to use for a page."""
133 def page_title(self, group):
134 _global = self._cmds['_global']
135 (directory, file) = self._group[group]
137 if file and file in _global and 'group_label' in _global[file]:
138 return _global[file]['group_label']
140 if directory in _global and 'group_label' in _global[directory]:
141 return _global[directory]['group_label']
145 """Returns a string to use as the label for the section reference."""
146 def item_label(self, group, item):
152 """Label sanitizer; for creating Doxygen references"""
153 def sanitize_label(self, value):
154 return value.replace(" ", "_") \
158 """Template processor"""
159 def template(self, name, **kwargs):
160 tpl = self._tplenv.get_template(name + ".md")
168 """Parse the input file into a more usable dictionary structure."""
169 def load_json(self, files):
175 for filename in files:
176 filename = os.path.relpath(filename)
177 self.log.info("Parsing items in file \"%s\"." % filename)
179 with open(filename, "r") as fd:
182 self._cmds['_global'] = data['global']
184 # iterate the items loaded and regroup it
185 for item in data["items"]:
187 o = self._parser.parse(item['block'])
189 self.log.error("Exception parsing item: %s\n%s" \
190 % (json.dumps(item, separators=(',', ': '),
195 # Augment the item with metadata
200 o['meta'][key] = item[key]
202 # Load some interesting fields
203 directory = item['directory']
208 # Generate keys to group items by
209 group_key = self.group_key(directory, file, macro, name)
210 item_key = self.item_key(directory, file, macro, name)
212 if group_key not in self._cmds:
213 self._cmds[group_key] = {}
215 self._cmds[group_key][item_key] = o
217 """Iterate over the input data, calling render methods to generate the
219 def process(self, out=None):
224 # Accumulated body contents
227 # Write the header for this siphon type
228 out.write(self.index_header())
230 # Sort key helper for the index
231 def group_sort_key(group):
232 return self.index_sort_key(group)
234 # Iterate the dictionary and process it
235 for group in sorted(self._cmds.keys(), key=group_sort_key):
236 if group.startswith('_'):
239 self.log.info("Processing items in group \"%s\" (%s)." % \
240 (group, group_sort_key(group)))
242 # Generate the section index entry (write it now)
243 out.write(self.index_section(group))
245 # Generate the item header (save for later)
246 contents += self.item_header(group)
248 def item_sort_key(key):
249 return self.item_sort_key(self._cmds[group][key])
251 for key in sorted(self._cmds[group].keys(), key=item_sort_key):
252 self.log.debug("--- Processing key \"%s\" (%s)." % \
253 (key, item_sort_key(key)))
255 o = self._cmds[group][key]
257 "directory": o['meta']['directory'],
258 "file": o['meta']['file'],
262 "label": self.item_label(group, key),
265 # Generate the index entry for the item (write it now)
266 out.write(self.index_entry(meta, o))
268 # Generate the item itself (save for later)
269 contents += self.item_format(meta, o)
271 # Deliver the accumulated body output