Parse match rules
The 'pimgen.py' parser will parse one or more yaml files containing
inventory manager match rules and generate the required c++ header
file.
Change-Id: Id3b116450bd56487e266590dd339b93db9bc7d27
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/pimgen.py b/pimgen.py
new file mode 100755
index 0000000..f59e320
--- /dev/null
+++ b/pimgen.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+
+import sys
+import os
+import re
+import argparse
+import yaml
+
+valid_c_name_pattern = re.compile('[\W_]+')
+ignore_list = ['description']
+all_names = []
+
+
+def get_parser(x, fmt, lmbda=lambda x: x.capitalize()):
+ try:
+ return getattr(
+ sys.modules[__name__],
+ '%s' % (fmt.format(lmbda(x))))
+ except AttributeError:
+ raise NotImplementedError("Don't know how to parse '%s'" % x)
+
+
+class RenderList(list):
+ def __init__(self, renderers):
+ self.extend(renderers)
+
+ def __call__(self, fd):
+ for x in self:
+ x(fd)
+
+
+class ParseList(list):
+ def __init__(self, parsers):
+ self.extend(parsers)
+
+ def __call__(self):
+ return RenderList([x() for x in self])
+
+
+class MatchRender(object):
+ def __init__(self, name, signature):
+ self.name = valid_c_name_pattern.sub('_', name).lower()
+ self.signature = signature
+
+ if self.name in all_names:
+ raise RuntimeError('The name "%s" is not unique.' % name)
+ else:
+ all_names.append(self.name)
+
+ def __call__(self, fd):
+ sig = ['%s=\'%s\'' % (k, v) for k, v in self.signature.iteritems()]
+ sig = ['%s,' % x for x in sig[:-1]] + [sig[-1]]
+ sig = ['"%s"' % x for x in sig]
+ sig = ['%s\n' % x for x in sig[:-1]] + [sig[-1]]
+
+ fd.write(' {\n')
+ fd.write(' "%s",\n' % self.name)
+ fd.write(' {\n')
+ for s in sig:
+ fd.write(' %s' % s)
+ fd.write(',\n')
+ fd.write(' },\n')
+ fd.write(' },\n')
+
+
+class MatchEventParse(object):
+ def __init__(self, match):
+ self.name = match['name']
+ self.signature = match['signature']
+
+ def __call__(self):
+ return MatchRender(
+ self.name,
+ self.signature)
+
+
+class EventsParse(object):
+ def __init__(self, event):
+ self.delegate = None
+ cls = event['type']
+ if cls not in ignore_list:
+ fmt = '{0}EventParse'
+ self.delegate = get_parser(cls, fmt)(event)
+
+ def __call__(self):
+ if self.delegate:
+ return self.delegate()
+ return lambda x: None
+
+
+class DictParse(ParseList):
+ def __init__(self, data):
+ fmt = '{0}Parse'
+ parse = set(data.iterkeys()).difference(ignore_list)
+ ParseList.__init__(
+ self, [get_parser(x, fmt)(*data[x]) for x in parse])
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(
+ description='Phosphor Inventory Manager (PIM) YAML '
+ 'scanner and code generator.')
+ parser.add_argument(
+ '-o', '--output', dest='output',
+ default='generated.hpp', help='Output file name.')
+ parser.add_argument(
+ '-d', '--dir', dest='inputdir',
+ default='examples', help='Location of files to process.')
+
+ args = parser.parse_args()
+
+ yaml_files = filter(
+ lambda x: x.endswith('.yaml'),
+ os.listdir(args.inputdir))
+
+ def get_parsers(x):
+ with open(os.path.join(args.inputdir, x), 'r') as fd:
+ return DictParse(yaml.load(fd.read()))
+
+ head = """// This file was auto generated. Do not edit.
+
+#pragma once
+
+const Manager::Events Manager::_events{
+"""
+
+ tail = """};
+"""
+
+ r = ParseList([get_parsers(x) for x in yaml_files])()
+ r.insert(0, lambda x: x.write(head))
+ r.append(lambda x: x.write(tail))
+
+ with open(args.output, 'w') as fd:
+ r(fd)
+
+# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4