blob: 4a958e1679e340b4e470425b587eb56fa15c5b3c [file] [log] [blame]
Matthew Barthdb440d42017-04-17 15:49:37 -05001#!/usr/bin/env python
2
Brad Bishop34a7acd2017-04-27 23:47:23 -04003'''Phosphor DBus Monitor YAML parser and code generator.
4
5The parser workflow is broken down as follows:
6 1 - Import YAML files as native python type(s) instance(s).
7 2 - Create an instance of the Everything class from the
8 native python type instance(s) with the Everything.load
9 method.
10 3 - The Everything class constructor orchestrates conversion of the
11 native python type(s) instances(s) to render helper types.
12 Each render helper type constructor imports its attributes
13 from the native python type(s) instances(s).
14 4 - Present the converted YAML to the command processing method
15 requested by the script user.
16'''
17
Matthew Barthdb440d42017-04-17 15:49:37 -050018import os
19import sys
20import yaml
Brad Bishop34a7acd2017-04-27 23:47:23 -040021import mako.lookup
Matthew Barthdb440d42017-04-17 15:49:37 -050022from argparse import ArgumentParser
Brad Bishop34a7acd2017-04-27 23:47:23 -040023from sdbusplus.renderer import Renderer
Brad Bishop05b0c1e2017-05-23 00:24:01 -040024from sdbusplus.namedelement import NamedElement
Brad Bishope73b2c32017-05-23 18:01:54 -040025import sdbusplus.property
Brad Bishop05b0c1e2017-05-23 00:24:01 -040026
27
28class InvalidConfigError(BaseException):
29 '''General purpose config file parsing error.'''
30
31 def __init__(self, path, msg):
32 '''Display configuration file with the syntax
33 error and the error message.'''
34
35 self.config = path
36 self.msg = msg
37
38
39class NotUniqueError(InvalidConfigError):
40 '''Within a config file names must be unique.
41 Display the config file with the duplicate and
42 the duplicate itself.'''
43
44 def __init__(self, path, cls, *names):
45 fmt = 'Duplicate {0}: "{1}"'
46 super(NotUniqueError, self).__init__(
47 path, fmt.format(cls, ' '.join(names)))
48
49
50def get_index(objs, cls, name, config=None):
51 '''Items are usually rendered as C++ arrays and as
52 such are stored in python lists. Given an item name
53 its class, and an optional config file filter, find
54 the item index.'''
55
56 for i, x in enumerate(objs.get(cls, [])):
57 if config and x.configfile != config:
58 continue
59 if x.name != name:
60 continue
61
62 return i
63 raise InvalidConfigError(config, 'Could not find name: "{0}"'.format(name))
64
65
66def exists(objs, cls, name, config=None):
67 '''Check to see if an item already exists in a list given
68 the item name.'''
69
70 try:
71 get_index(objs, cls, name, config)
72 except:
73 return False
74
75 return True
76
77
78def add_unique(obj, *a, **kw):
79 '''Add an item to one or more lists unless already present,
80 with an option to constrain the search to a specific config file.'''
81
82 for container in a:
83 if not exists(container, obj.cls, obj.name, config=kw.get('config')):
84 container.setdefault(obj.cls, []).append(obj)
Matthew Barthdb440d42017-04-17 15:49:37 -050085
86
Brad Bishop34a7acd2017-04-27 23:47:23 -040087class Indent(object):
88 '''Help templates be depth agnostic.'''
Matthew Barthdb440d42017-04-17 15:49:37 -050089
Brad Bishop34a7acd2017-04-27 23:47:23 -040090 def __init__(self, depth=0):
91 self.depth = depth
Matthew Barthdb440d42017-04-17 15:49:37 -050092
Brad Bishop34a7acd2017-04-27 23:47:23 -040093 def __add__(self, depth):
94 return Indent(self.depth + depth)
95
96 def __call__(self, depth):
97 '''Render an indent at the current depth plus depth.'''
98 return 4*' '*(depth + self.depth)
99
100
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400101class ConfigEntry(NamedElement):
102 '''Base interface for rendered items.'''
103
104 def __init__(self, *a, **kw):
105 '''Pop the configfile/class/subclass keywords.'''
106
107 self.configfile = kw.pop('configfile')
108 self.cls = kw.pop('class')
109 self.subclass = kw.pop(self.cls)
110 super(ConfigEntry, self).__init__(**kw)
111
112 def factory(self, objs):
113 ''' Optional factory interface for subclasses to add
114 additional items to be rendered.'''
115
116 pass
117
118 def setup(self, objs):
119 ''' Optional setup interface for subclasses, invoked
120 after all factory methods have been run.'''
121
122 pass
123
124
Brad Bishop0e7df132017-05-23 17:58:12 -0400125class Path(ConfigEntry):
126 '''Path/metadata association.'''
127
128 def __init__(self, *a, **kw):
129 super(Path, self).__init__(**kw)
130
131 def factory(self, objs):
132 '''Create path and metadata elements.'''
133
134 args = {
135 'class': 'pathname',
136 'pathname': 'element',
137 'name': self.name['path']
138 }
139 add_unique(ConfigEntry(
140 configfile=self.configfile, **args), objs)
141
142 args = {
143 'class': 'meta',
144 'meta': 'element',
145 'name': self.name['meta']
146 }
147 add_unique(ConfigEntry(
148 configfile=self.configfile, **args), objs)
149
150 super(Path, self).factory(objs)
151
152 def setup(self, objs):
153 '''Resolve path and metadata names to indicies.'''
154
155 self.path = get_index(
156 objs, 'pathname', self.name['path'])
157 self.meta = get_index(
158 objs, 'meta', self.name['meta'])
159
160 super(Path, self).setup(objs)
161
162
Brad Bishope73b2c32017-05-23 18:01:54 -0400163class Property(ConfigEntry):
164 '''Property/interface/metadata association.'''
165
166 def __init__(self, *a, **kw):
167 super(Property, self).__init__(**kw)
168
169 def factory(self, objs):
170 '''Create interface, property name and metadata elements.'''
171
172 args = {
173 'class': 'interface',
174 'interface': 'element',
175 'name': self.name['interface']
176 }
177 add_unique(ConfigEntry(
178 configfile=self.configfile, **args), objs)
179
180 args = {
181 'class': 'propertyname',
182 'propertyname': 'element',
183 'name': self.name['property']
184 }
185 add_unique(ConfigEntry(
186 configfile=self.configfile, **args), objs)
187
188 args = {
189 'class': 'meta',
190 'meta': 'element',
191 'name': self.name['meta']
192 }
193 add_unique(ConfigEntry(
194 configfile=self.configfile, **args), objs)
195
196 super(Property, self).factory(objs)
197
198 def setup(self, objs):
199 '''Resolve interface, property and metadata to indicies.'''
200
201 self.interface = get_index(
202 objs, 'interface', self.name['interface'])
203 self.prop = get_index(
204 objs, 'propertyname', self.name['property'])
205 self.meta = get_index(
206 objs, 'meta', self.name['meta'])
207
208 super(Property, self).setup(objs)
209
210
Brad Bishop4b916f12017-05-23 18:06:38 -0400211class Instance(ConfigEntry):
212 '''Property/Path association.'''
213
214 def __init__(self, *a, **kw):
215 super(Instance, self).__init__(**kw)
216
217 def setup(self, objs):
218 '''Resolve elements to indicies.'''
219
220 self.interface = get_index(
221 objs, 'interface', self.name['property']['interface'])
222 self.prop = get_index(
223 objs, 'propertyname', self.name['property']['property'])
224 self.propmeta = get_index(
225 objs, 'meta', self.name['property']['meta'])
226 self.path = get_index(
227 objs, 'pathname', self.name['path']['path'])
228 self.pathmeta = get_index(
229 objs, 'meta', self.name['path']['meta'])
230
231 super(Instance, self).setup(objs)
232
233
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400234class Group(ConfigEntry):
235 '''Pop the members keyword for groups.'''
236
237 def __init__(self, *a, **kw):
238 self.members = kw.pop('members')
239 super(Group, self).__init__(**kw)
240
241
242class ImplicitGroup(Group):
243 '''Provide a factory method for groups whose members are
244 not explicitly declared in the config files.'''
245
246 def __init__(self, *a, **kw):
247 super(ImplicitGroup, self).__init__(**kw)
248
249 def factory(self, objs):
250 '''Create group members.'''
251
252 factory = Everything.classmap(self.subclass, 'element')
253 for m in self.members:
254 args = {
255 'class': self.subclass,
256 self.subclass: 'element',
257 'name': m
258 }
259
260 obj = factory(configfile=self.configfile, **args)
261 add_unique(obj, objs)
262 obj.factory(objs)
263
264 super(ImplicitGroup, self).factory(objs)
265
266
Brad Bishop0e7df132017-05-23 17:58:12 -0400267class GroupOfPaths(ImplicitGroup):
268 '''Path group config file directive.'''
269
270 def __init__(self, *a, **kw):
271 super(GroupOfPaths, self).__init__(**kw)
272
273 def setup(self, objs):
274 '''Resolve group members.'''
275
276 def map_member(x):
277 path = get_index(
278 objs, 'pathname', x['path'])
279 meta = get_index(
280 objs, 'meta', x['meta'])
281 return (path, meta)
282
283 self.members = map(
284 map_member,
285 self.members)
286
287 super(GroupOfPaths, self).setup(objs)
288
289
Brad Bishope73b2c32017-05-23 18:01:54 -0400290class GroupOfProperties(ImplicitGroup):
291 '''Property group config file directive.'''
292
293 def __init__(self, *a, **kw):
294 self.datatype = sdbusplus.property.Property(
295 name=kw.get('name'),
296 type=kw.pop('type')).cppTypeName
297
298 super(GroupOfProperties, self).__init__(**kw)
299
300 def setup(self, objs):
301 '''Resolve group members.'''
302
303 def map_member(x):
304 iface = get_index(
305 objs, 'interface', x['interface'])
306 prop = get_index(
307 objs, 'propertyname', x['property'])
308 meta = get_index(
309 objs, 'meta', x['meta'])
310
311 return (iface, prop, meta)
312
313 self.members = map(
314 map_member,
315 self.members)
316
317 super(GroupOfProperties, self).setup(objs)
318
319
Brad Bishop4b916f12017-05-23 18:06:38 -0400320class GroupOfInstances(ImplicitGroup):
321 '''A group of property instances.'''
322
323 def __init__(self, *a, **kw):
324 super(GroupOfInstances, self).__init__(**kw)
325
326 def setup(self, objs):
327 '''Resolve group members.'''
328
329 def map_member(x):
330 path = get_index(objs, 'pathname', x['path']['path'])
331 pathmeta = get_index(objs, 'meta', x['path']['meta'])
332 interface = get_index(
333 objs, 'interface', x['property']['interface'])
334 prop = get_index(objs, 'propertyname', x['property']['property'])
335 propmeta = get_index(objs, 'meta', x['property']['meta'])
336 instance = get_index(objs, 'instance', x)
337
338 return (path, pathmeta, interface, prop, propmeta, instance)
339
340 self.members = map(
341 map_member,
342 self.members)
343
344 super(GroupOfInstances, self).setup(objs)
345
346
347class HasPropertyIndex(ConfigEntry):
348 '''Handle config file directives that require an index to be
349 constructed.'''
350
351 def __init__(self, *a, **kw):
352 self.paths = kw.pop('paths')
353 self.properties = kw.pop('properties')
354 super(HasPropertyIndex, self).__init__(**kw)
355
356 def factory(self, objs):
357 '''Create a group of instances for this index.'''
358
359 members = []
360 path_group = get_index(
361 objs, 'pathgroup', self.paths, config=self.configfile)
362 property_group = get_index(
363 objs, 'propertygroup', self.properties, config=self.configfile)
364
365 for path in objs['pathgroup'][path_group].members:
366 for prop in objs['propertygroup'][property_group].members:
367 member = {
368 'path': path,
369 'property': prop,
370 }
371 members.append(member)
372
373 args = {
374 'members': members,
375 'class': 'instancegroup',
376 'instancegroup': 'instance',
377 'name': '{0} {1}'.format(self.paths, self.properties)
378 }
379
380 group = GroupOfInstances(configfile=self.configfile, **args)
381 add_unique(group, objs, config=self.configfile)
382 group.factory(objs)
383
384 super(HasPropertyIndex, self).factory(objs)
385
386 def setup(self, objs):
387 '''Resolve path, property, and instance groups.'''
388
389 self.instances = get_index(
390 objs,
391 'instancegroup',
392 '{0} {1}'.format(self.paths, self.properties),
393 config=self.configfile)
394 self.paths = get_index(
395 objs,
396 'pathgroup',
397 self.paths,
398 config=self.configfile)
399 self.properties = get_index(
400 objs,
401 'propertygroup',
402 self.properties,
403 config=self.configfile)
404 self.datatype = objs['propertygroup'][self.properties].datatype
405
406 super(HasPropertyIndex, self).setup(objs)
407
408
409class PropertyWatch(HasPropertyIndex):
410 '''Handle the property watch config file directive.'''
411
412 def __init__(self, *a, **kw):
413 super(PropertyWatch, self).__init__(**kw)
414
415
Brad Bishopc1283ae2017-05-20 21:42:38 -0400416class Callback(HasPropertyIndex):
417 '''Interface and common logic for callbacks.'''
418
419 def __init__(self, *a, **kw):
420 super(Callback, self).__init__(**kw)
421
422
Brad Bishop4041d722017-05-21 10:06:07 -0400423class ConditionCallback(ConfigEntry, Renderer):
424 '''Handle the journal callback config file directive.'''
425
426 def __init__(self, *a, **kw):
427 self.condition = kw.pop('condition')
428 self.instance = kw.pop('instance')
429 super(ConditionCallback, self).__init__(**kw)
430
431 def factory(self, objs):
432 '''Create a graph instance for this callback.'''
433
434 args = {
435 'configfile': self.configfile,
436 'members': [self.instance],
437 'class': 'callbackgroup',
438 'callbackgroup': 'callback',
439 'name': [self.instance]
440 }
441
442 entry = CallbackGraphEntry(**args)
443 add_unique(entry, objs, config=self.configfile)
444
445 super(ConditionCallback, self).factory(objs)
446
447 def setup(self, objs):
448 '''Resolve condition and graph entry.'''
449
450 self.graph = get_index(
451 objs,
452 'callbackgroup',
453 [self.instance],
454 config=self.configfile)
455
456 self.condition = get_index(
457 objs,
458 'condition',
459 self.name,
460 config=self.configfile)
461
462 super(ConditionCallback, self).setup(objs)
463
464 def construct(self, loader, indent):
465 return self.render(
466 loader,
467 'conditional.mako.cpp',
468 c=self,
469 indent=indent)
470
471
472class Condition(HasPropertyIndex):
473 '''Interface and common logic for conditions.'''
474
475 def __init__(self, *a, **kw):
476 self.callback = kw.pop('callback')
477 super(Condition, self).__init__(**kw)
478
479 def factory(self, objs):
480 '''Create a callback instance for this conditional.'''
481
482 args = {
483 'configfile': self.configfile,
484 'condition': self.name,
485 'class': 'callback',
486 'callback': 'conditional',
487 'instance': self.callback,
488 'name': self.name,
489 }
490
491 callback = ConditionCallback(**args)
492 add_unique(callback, objs, config=self.configfile)
493 callback.factory(objs)
494
495 super(Condition, self).factory(objs)
496
497
498class CountCondition(Condition, Renderer):
499 '''Handle the count condition config file directive.'''
500
501 def __init__(self, *a, **kw):
502 self.countop = kw.pop('countop')
503 self.countbound = kw.pop('countbound')
504 self.op = kw.pop('op')
505 self.bound = kw.pop('bound')
506 super(CountCondition, self).__init__(**kw)
507
508 def construct(self, loader, indent):
509 return self.render(
510 loader,
511 'count.mako.cpp',
512 c=self,
513 indent=indent)
514
515
Brad Bishopc1283ae2017-05-20 21:42:38 -0400516class Journal(Callback, Renderer):
517 '''Handle the journal callback config file directive.'''
518
519 def __init__(self, *a, **kw):
520 self.severity = kw.pop('severity')
521 self.message = kw.pop('message')
522 super(Journal, self).__init__(**kw)
523
524 def construct(self, loader, indent):
525 return self.render(
526 loader,
527 'journal.mako.cpp',
528 c=self,
529 indent=indent)
530
531
Brad Bishop49e66172017-05-23 19:16:21 -0400532class CallbackGraphEntry(Group):
533 '''An entry in a traversal list for groups of callbacks.'''
534
535 def __init__(self, *a, **kw):
536 super(CallbackGraphEntry, self).__init__(**kw)
537
538 def setup(self, objs):
539 '''Resolve group members.'''
540
541 def map_member(x):
542 return get_index(
543 objs, 'callback', x, config=self.configfile)
544
545 self.members = map(
546 map_member,
547 self.members)
548
549 super(CallbackGraphEntry, self).setup(objs)
550
551
552class GroupOfCallbacks(ConfigEntry, Renderer):
553 '''Handle the callback group config file directive.'''
554
555 def __init__(self, *a, **kw):
556 self.members = kw.pop('members')
557 super(GroupOfCallbacks, self).__init__(**kw)
558
559 def factory(self, objs):
560 '''Create a graph instance for this group of callbacks.'''
561
562 args = {
563 'configfile': self.configfile,
564 'members': self.members,
565 'class': 'callbackgroup',
566 'callbackgroup': 'callback',
567 'name': self.members
568 }
569
570 entry = CallbackGraphEntry(**args)
571 add_unique(entry, objs, config=self.configfile)
572
573 super(GroupOfCallbacks, self).factory(objs)
574
575 def setup(self, objs):
576 '''Resolve graph entry.'''
577
578 self.graph = get_index(
579 objs, 'callbackgroup', self.members, config=self.configfile)
580
581 super(GroupOfCallbacks, self).setup(objs)
582
583 def construct(self, loader, indent):
584 return self.render(
585 loader,
586 'callbackgroup.mako.cpp',
587 c=self,
588 indent=indent)
589
590
Brad Bishop34a7acd2017-04-27 23:47:23 -0400591class Everything(Renderer):
592 '''Parse/render entry point.'''
593
594 @staticmethod
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400595 def classmap(cls, sub=None):
596 '''Map render item class and subclass entries to the appropriate
597 handler methods.'''
598
599 class_map = {
Brad Bishop0e7df132017-05-23 17:58:12 -0400600 'path': {
601 'element': Path,
602 },
603 'pathgroup': {
604 'path': GroupOfPaths,
605 },
Brad Bishope73b2c32017-05-23 18:01:54 -0400606 'propertygroup': {
607 'property': GroupOfProperties,
608 },
609 'property': {
610 'element': Property,
611 },
Brad Bishop4b916f12017-05-23 18:06:38 -0400612 'watch': {
613 'property': PropertyWatch,
614 },
615 'instance': {
616 'element': Instance,
617 },
Brad Bishopc1283ae2017-05-20 21:42:38 -0400618 'callback': {
619 'journal': Journal,
Brad Bishop49e66172017-05-23 19:16:21 -0400620 'group': GroupOfCallbacks,
Brad Bishopc1283ae2017-05-20 21:42:38 -0400621 },
Brad Bishop4041d722017-05-21 10:06:07 -0400622 'condition': {
623 'count': CountCondition,
624 },
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400625 }
626
627 if cls not in class_map:
628 raise NotImplementedError('Unknown class: "{0}"'.format(cls))
629 if sub not in class_map[cls]:
630 raise NotImplementedError('Unknown {0} type: "{1}"'.format(
631 cls, sub))
632
633 return class_map[cls][sub]
634
635 @staticmethod
636 def load_one_yaml(path, fd, objs):
637 '''Parse a single YAML file. Parsing occurs in three phases.
638 In the first phase a factory method associated with each
639 configuration file directive is invoked. These factory
640 methods generate more factory methods. In the second
641 phase the factory methods created in the first phase
642 are invoked. In the last phase a callback is invoked on
643 each object created in phase two. Typically the callback
644 resolves references to other configuration file directives.'''
645
646 factory_objs = {}
647 for x in yaml.safe_load(fd.read()) or {}:
648
649 # Create factory object for this config file directive.
650 cls = x['class']
651 sub = x.get(cls)
652 if cls == 'group':
653 cls = '{0}group'.format(sub)
654
655 factory = Everything.classmap(cls, sub)
656 obj = factory(configfile=path, **x)
657
658 # For a given class of directive, validate the file
659 # doesn't have any duplicate names (duplicates are
660 # ok across config files).
661 if exists(factory_objs, obj.cls, obj.name, config=path):
662 raise NotUniqueError(path, cls, obj.name)
663
664 factory_objs.setdefault(cls, []).append(obj)
665 objs.setdefault(cls, []).append(obj)
666
667 for cls, items in factory_objs.items():
668 for obj in items:
669 # Add objects for template consumption.
670 obj.factory(objs)
671
672 @staticmethod
Brad Bishop34a7acd2017-04-27 23:47:23 -0400673 def load(args):
674 '''Aggregate all the YAML in the input directory
675 into a single aggregate.'''
676
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400677 objs = {}
678 yaml_files = filter(
679 lambda x: x.endswith('.yaml'),
680 os.listdir(args.inputdir))
Brad Bishop34a7acd2017-04-27 23:47:23 -0400681
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400682 yaml_files.sort()
Brad Bishop34a7acd2017-04-27 23:47:23 -0400683
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400684 for x in yaml_files:
685 path = os.path.join(args.inputdir, x)
686 with open(path, 'r') as fd:
687 Everything.load_one_yaml(path, fd, objs)
688
689 # Configuration file directives reference each other via
690 # the name attribute; however, when rendered the reference
691 # is just an array index.
692 #
693 # At this point all objects have been created but references
694 # have not been resolved to array indicies. Instruct objects
695 # to do that now.
696 for cls, items in objs.items():
697 for obj in items:
698 obj.setup(objs)
699
700 return Everything(**objs)
Brad Bishop34a7acd2017-04-27 23:47:23 -0400701
702 def __init__(self, *a, **kw):
Brad Bishop0e7df132017-05-23 17:58:12 -0400703 self.pathmeta = kw.pop('path', [])
704 self.paths = kw.pop('pathname', [])
705 self.meta = kw.pop('meta', [])
706 self.pathgroups = kw.pop('pathgroup', [])
Brad Bishope73b2c32017-05-23 18:01:54 -0400707 self.interfaces = kw.pop('interface', [])
708 self.properties = kw.pop('property', [])
709 self.propertynames = kw.pop('propertyname', [])
710 self.propertygroups = kw.pop('propertygroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -0400711 self.instances = kw.pop('instance', [])
712 self.instancegroups = kw.pop('instancegroup', [])
713 self.watches = kw.pop('watch', [])
Brad Bishopc1283ae2017-05-20 21:42:38 -0400714 self.callbacks = kw.pop('callback', [])
Brad Bishop49e66172017-05-23 19:16:21 -0400715 self.callbackgroups = kw.pop('callbackgroup', [])
Brad Bishop4041d722017-05-21 10:06:07 -0400716 self.conditions = kw.pop('condition', [])
Brad Bishop0e7df132017-05-23 17:58:12 -0400717
Brad Bishop34a7acd2017-04-27 23:47:23 -0400718 super(Everything, self).__init__(**kw)
719
720 def generate_cpp(self, loader):
721 '''Render the template with the provided data.'''
Brad Bishope3a01af2017-05-15 17:09:04 -0400722 with open(args.output, 'w') as fd:
Brad Bishop34a7acd2017-04-27 23:47:23 -0400723 fd.write(
724 self.render(
725 loader,
Brad Bishope3a01af2017-05-15 17:09:04 -0400726 args.template,
Brad Bishop0e7df132017-05-23 17:58:12 -0400727 meta=self.meta,
Brad Bishope73b2c32017-05-23 18:01:54 -0400728 properties=self.properties,
729 propertynames=self.propertynames,
730 interfaces=self.interfaces,
Brad Bishop0e7df132017-05-23 17:58:12 -0400731 paths=self.paths,
732 pathmeta=self.pathmeta,
733 pathgroups=self.pathgroups,
Brad Bishope73b2c32017-05-23 18:01:54 -0400734 propertygroups=self.propertygroups,
Brad Bishop4b916f12017-05-23 18:06:38 -0400735 instances=self.instances,
736 watches=self.watches,
737 instancegroups=self.instancegroups,
Brad Bishopc1283ae2017-05-20 21:42:38 -0400738 callbacks=self.callbacks,
Brad Bishop49e66172017-05-23 19:16:21 -0400739 callbackgroups=self.callbackgroups,
Brad Bishop4041d722017-05-21 10:06:07 -0400740 conditions=self.conditions,
Brad Bishop34a7acd2017-04-27 23:47:23 -0400741 indent=Indent()))
Matthew Barthdb440d42017-04-17 15:49:37 -0500742
743if __name__ == '__main__':
Brad Bishop34a7acd2017-04-27 23:47:23 -0400744 script_dir = os.path.dirname(os.path.realpath(__file__))
745 valid_commands = {
746 'generate-cpp': 'generate_cpp',
747 }
748
749 parser = ArgumentParser(
750 description='Phosphor DBus Monitor (PDM) YAML '
751 'scanner and code generator.')
752
Matthew Barthdb440d42017-04-17 15:49:37 -0500753 parser.add_argument(
Brad Bishope3a01af2017-05-15 17:09:04 -0400754 "-o", "--out", dest="output",
755 default='generated.cpp',
756 help="Generated output file name and path.")
757 parser.add_argument(
758 '-t', '--template', dest='template',
Brad Bishop870c3fc2017-05-22 23:23:13 -0400759 default='generated.mako.hpp',
Brad Bishope3a01af2017-05-15 17:09:04 -0400760 help='The top level template to render.')
761 parser.add_argument(
762 '-p', '--template-path', dest='template_search',
763 default=script_dir,
764 help='The space delimited mako template search path.')
Brad Bishop34a7acd2017-04-27 23:47:23 -0400765 parser.add_argument(
766 '-d', '--dir', dest='inputdir',
767 default=os.path.join(script_dir, 'example'),
768 help='Location of files to process.')
769 parser.add_argument(
770 'command', metavar='COMMAND', type=str,
771 choices=valid_commands.keys(),
772 help='%s.' % " | ".join(valid_commands.keys()))
Matthew Barthdb440d42017-04-17 15:49:37 -0500773
Brad Bishop34a7acd2017-04-27 23:47:23 -0400774 args = parser.parse_args()
775
776 if sys.version_info < (3, 0):
777 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -0400778 directories=args.template_search.split(),
Brad Bishop34a7acd2017-04-27 23:47:23 -0400779 disable_unicode=True)
780 else:
781 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -0400782 directories=args.template_search.split())
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400783 try:
784 function = getattr(
785 Everything.load(args),
786 valid_commands[args.command])
787 function(lookup)
788 except InvalidConfigError as e:
789 sys.stdout.write('{0}: {1}\n\n'.format(e.config, e.msg))
790 raise