blob: 54790bbcc009ffba120d079c388d0a384514d86f [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):
Brad Bishopfccdc392017-05-22 21:11:09 -0400413 self.callback = kw.pop('callback', None)
Brad Bishop4b916f12017-05-23 18:06:38 -0400414 super(PropertyWatch, self).__init__(**kw)
415
Brad Bishopfccdc392017-05-22 21:11:09 -0400416 def setup(self, objs):
417 '''Resolve optional callback.'''
418
419 if self.callback:
420 self.callback = get_index(
421 objs,
422 'callback',
423 self.callback,
424 config=self.configfile)
425
426 super(PropertyWatch, self).setup(objs)
427
Brad Bishop4b916f12017-05-23 18:06:38 -0400428
Brad Bishopc1283ae2017-05-20 21:42:38 -0400429class Callback(HasPropertyIndex):
430 '''Interface and common logic for callbacks.'''
431
432 def __init__(self, *a, **kw):
433 super(Callback, self).__init__(**kw)
434
435
Brad Bishop4041d722017-05-21 10:06:07 -0400436class ConditionCallback(ConfigEntry, Renderer):
437 '''Handle the journal callback config file directive.'''
438
439 def __init__(self, *a, **kw):
440 self.condition = kw.pop('condition')
441 self.instance = kw.pop('instance')
442 super(ConditionCallback, self).__init__(**kw)
443
444 def factory(self, objs):
445 '''Create a graph instance for this callback.'''
446
447 args = {
448 'configfile': self.configfile,
449 'members': [self.instance],
450 'class': 'callbackgroup',
451 'callbackgroup': 'callback',
452 'name': [self.instance]
453 }
454
455 entry = CallbackGraphEntry(**args)
456 add_unique(entry, objs, config=self.configfile)
457
458 super(ConditionCallback, self).factory(objs)
459
460 def setup(self, objs):
461 '''Resolve condition and graph entry.'''
462
463 self.graph = get_index(
464 objs,
465 'callbackgroup',
466 [self.instance],
467 config=self.configfile)
468
469 self.condition = get_index(
470 objs,
471 'condition',
472 self.name,
473 config=self.configfile)
474
475 super(ConditionCallback, self).setup(objs)
476
477 def construct(self, loader, indent):
478 return self.render(
479 loader,
480 'conditional.mako.cpp',
481 c=self,
482 indent=indent)
483
484
485class Condition(HasPropertyIndex):
486 '''Interface and common logic for conditions.'''
487
488 def __init__(self, *a, **kw):
489 self.callback = kw.pop('callback')
490 super(Condition, self).__init__(**kw)
491
492 def factory(self, objs):
493 '''Create a callback instance for this conditional.'''
494
495 args = {
496 'configfile': self.configfile,
497 'condition': self.name,
498 'class': 'callback',
499 'callback': 'conditional',
500 'instance': self.callback,
501 'name': self.name,
502 }
503
504 callback = ConditionCallback(**args)
505 add_unique(callback, objs, config=self.configfile)
506 callback.factory(objs)
507
508 super(Condition, self).factory(objs)
509
510
511class CountCondition(Condition, Renderer):
512 '''Handle the count condition config file directive.'''
513
514 def __init__(self, *a, **kw):
515 self.countop = kw.pop('countop')
516 self.countbound = kw.pop('countbound')
517 self.op = kw.pop('op')
518 self.bound = kw.pop('bound')
519 super(CountCondition, self).__init__(**kw)
520
521 def construct(self, loader, indent):
522 return self.render(
523 loader,
524 'count.mako.cpp',
525 c=self,
526 indent=indent)
527
528
Brad Bishopc1283ae2017-05-20 21:42:38 -0400529class Journal(Callback, Renderer):
530 '''Handle the journal callback config file directive.'''
531
532 def __init__(self, *a, **kw):
533 self.severity = kw.pop('severity')
534 self.message = kw.pop('message')
535 super(Journal, self).__init__(**kw)
536
537 def construct(self, loader, indent):
538 return self.render(
539 loader,
540 'journal.mako.cpp',
541 c=self,
542 indent=indent)
543
544
Brad Bishop49e66172017-05-23 19:16:21 -0400545class CallbackGraphEntry(Group):
546 '''An entry in a traversal list for groups of callbacks.'''
547
548 def __init__(self, *a, **kw):
549 super(CallbackGraphEntry, self).__init__(**kw)
550
551 def setup(self, objs):
552 '''Resolve group members.'''
553
554 def map_member(x):
555 return get_index(
556 objs, 'callback', x, config=self.configfile)
557
558 self.members = map(
559 map_member,
560 self.members)
561
562 super(CallbackGraphEntry, self).setup(objs)
563
564
565class GroupOfCallbacks(ConfigEntry, Renderer):
566 '''Handle the callback group config file directive.'''
567
568 def __init__(self, *a, **kw):
569 self.members = kw.pop('members')
570 super(GroupOfCallbacks, self).__init__(**kw)
571
572 def factory(self, objs):
573 '''Create a graph instance for this group of callbacks.'''
574
575 args = {
576 'configfile': self.configfile,
577 'members': self.members,
578 'class': 'callbackgroup',
579 'callbackgroup': 'callback',
580 'name': self.members
581 }
582
583 entry = CallbackGraphEntry(**args)
584 add_unique(entry, objs, config=self.configfile)
585
586 super(GroupOfCallbacks, self).factory(objs)
587
588 def setup(self, objs):
589 '''Resolve graph entry.'''
590
591 self.graph = get_index(
592 objs, 'callbackgroup', self.members, config=self.configfile)
593
594 super(GroupOfCallbacks, self).setup(objs)
595
596 def construct(self, loader, indent):
597 return self.render(
598 loader,
599 'callbackgroup.mako.cpp',
600 c=self,
601 indent=indent)
602
603
Brad Bishop34a7acd2017-04-27 23:47:23 -0400604class Everything(Renderer):
605 '''Parse/render entry point.'''
606
607 @staticmethod
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400608 def classmap(cls, sub=None):
609 '''Map render item class and subclass entries to the appropriate
610 handler methods.'''
611
612 class_map = {
Brad Bishop0e7df132017-05-23 17:58:12 -0400613 'path': {
614 'element': Path,
615 },
616 'pathgroup': {
617 'path': GroupOfPaths,
618 },
Brad Bishope73b2c32017-05-23 18:01:54 -0400619 'propertygroup': {
620 'property': GroupOfProperties,
621 },
622 'property': {
623 'element': Property,
624 },
Brad Bishop4b916f12017-05-23 18:06:38 -0400625 'watch': {
626 'property': PropertyWatch,
627 },
628 'instance': {
629 'element': Instance,
630 },
Brad Bishopc1283ae2017-05-20 21:42:38 -0400631 'callback': {
632 'journal': Journal,
Brad Bishop49e66172017-05-23 19:16:21 -0400633 'group': GroupOfCallbacks,
Brad Bishopc1283ae2017-05-20 21:42:38 -0400634 },
Brad Bishop4041d722017-05-21 10:06:07 -0400635 'condition': {
636 'count': CountCondition,
637 },
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400638 }
639
640 if cls not in class_map:
641 raise NotImplementedError('Unknown class: "{0}"'.format(cls))
642 if sub not in class_map[cls]:
643 raise NotImplementedError('Unknown {0} type: "{1}"'.format(
644 cls, sub))
645
646 return class_map[cls][sub]
647
648 @staticmethod
649 def load_one_yaml(path, fd, objs):
650 '''Parse a single YAML file. Parsing occurs in three phases.
651 In the first phase a factory method associated with each
652 configuration file directive is invoked. These factory
653 methods generate more factory methods. In the second
654 phase the factory methods created in the first phase
655 are invoked. In the last phase a callback is invoked on
656 each object created in phase two. Typically the callback
657 resolves references to other configuration file directives.'''
658
659 factory_objs = {}
660 for x in yaml.safe_load(fd.read()) or {}:
661
662 # Create factory object for this config file directive.
663 cls = x['class']
664 sub = x.get(cls)
665 if cls == 'group':
666 cls = '{0}group'.format(sub)
667
668 factory = Everything.classmap(cls, sub)
669 obj = factory(configfile=path, **x)
670
671 # For a given class of directive, validate the file
672 # doesn't have any duplicate names (duplicates are
673 # ok across config files).
674 if exists(factory_objs, obj.cls, obj.name, config=path):
675 raise NotUniqueError(path, cls, obj.name)
676
677 factory_objs.setdefault(cls, []).append(obj)
678 objs.setdefault(cls, []).append(obj)
679
680 for cls, items in factory_objs.items():
681 for obj in items:
682 # Add objects for template consumption.
683 obj.factory(objs)
684
685 @staticmethod
Brad Bishop34a7acd2017-04-27 23:47:23 -0400686 def load(args):
687 '''Aggregate all the YAML in the input directory
688 into a single aggregate.'''
689
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400690 objs = {}
691 yaml_files = filter(
692 lambda x: x.endswith('.yaml'),
693 os.listdir(args.inputdir))
Brad Bishop34a7acd2017-04-27 23:47:23 -0400694
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400695 yaml_files.sort()
Brad Bishop34a7acd2017-04-27 23:47:23 -0400696
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400697 for x in yaml_files:
698 path = os.path.join(args.inputdir, x)
699 with open(path, 'r') as fd:
700 Everything.load_one_yaml(path, fd, objs)
701
702 # Configuration file directives reference each other via
703 # the name attribute; however, when rendered the reference
704 # is just an array index.
705 #
706 # At this point all objects have been created but references
707 # have not been resolved to array indicies. Instruct objects
708 # to do that now.
709 for cls, items in objs.items():
710 for obj in items:
711 obj.setup(objs)
712
713 return Everything(**objs)
Brad Bishop34a7acd2017-04-27 23:47:23 -0400714
715 def __init__(self, *a, **kw):
Brad Bishop0e7df132017-05-23 17:58:12 -0400716 self.pathmeta = kw.pop('path', [])
717 self.paths = kw.pop('pathname', [])
718 self.meta = kw.pop('meta', [])
719 self.pathgroups = kw.pop('pathgroup', [])
Brad Bishope73b2c32017-05-23 18:01:54 -0400720 self.interfaces = kw.pop('interface', [])
721 self.properties = kw.pop('property', [])
722 self.propertynames = kw.pop('propertyname', [])
723 self.propertygroups = kw.pop('propertygroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -0400724 self.instances = kw.pop('instance', [])
725 self.instancegroups = kw.pop('instancegroup', [])
726 self.watches = kw.pop('watch', [])
Brad Bishopc1283ae2017-05-20 21:42:38 -0400727 self.callbacks = kw.pop('callback', [])
Brad Bishop49e66172017-05-23 19:16:21 -0400728 self.callbackgroups = kw.pop('callbackgroup', [])
Brad Bishop4041d722017-05-21 10:06:07 -0400729 self.conditions = kw.pop('condition', [])
Brad Bishop0e7df132017-05-23 17:58:12 -0400730
Brad Bishop34a7acd2017-04-27 23:47:23 -0400731 super(Everything, self).__init__(**kw)
732
733 def generate_cpp(self, loader):
734 '''Render the template with the provided data.'''
Brad Bishope3a01af2017-05-15 17:09:04 -0400735 with open(args.output, 'w') as fd:
Brad Bishop34a7acd2017-04-27 23:47:23 -0400736 fd.write(
737 self.render(
738 loader,
Brad Bishope3a01af2017-05-15 17:09:04 -0400739 args.template,
Brad Bishop0e7df132017-05-23 17:58:12 -0400740 meta=self.meta,
Brad Bishope73b2c32017-05-23 18:01:54 -0400741 properties=self.properties,
742 propertynames=self.propertynames,
743 interfaces=self.interfaces,
Brad Bishop0e7df132017-05-23 17:58:12 -0400744 paths=self.paths,
745 pathmeta=self.pathmeta,
746 pathgroups=self.pathgroups,
Brad Bishope73b2c32017-05-23 18:01:54 -0400747 propertygroups=self.propertygroups,
Brad Bishop4b916f12017-05-23 18:06:38 -0400748 instances=self.instances,
749 watches=self.watches,
750 instancegroups=self.instancegroups,
Brad Bishopc1283ae2017-05-20 21:42:38 -0400751 callbacks=self.callbacks,
Brad Bishop49e66172017-05-23 19:16:21 -0400752 callbackgroups=self.callbackgroups,
Brad Bishop4041d722017-05-21 10:06:07 -0400753 conditions=self.conditions,
Brad Bishop34a7acd2017-04-27 23:47:23 -0400754 indent=Indent()))
Matthew Barthdb440d42017-04-17 15:49:37 -0500755
756if __name__ == '__main__':
Brad Bishop34a7acd2017-04-27 23:47:23 -0400757 script_dir = os.path.dirname(os.path.realpath(__file__))
758 valid_commands = {
759 'generate-cpp': 'generate_cpp',
760 }
761
762 parser = ArgumentParser(
763 description='Phosphor DBus Monitor (PDM) YAML '
764 'scanner and code generator.')
765
Matthew Barthdb440d42017-04-17 15:49:37 -0500766 parser.add_argument(
Brad Bishope3a01af2017-05-15 17:09:04 -0400767 "-o", "--out", dest="output",
768 default='generated.cpp',
769 help="Generated output file name and path.")
770 parser.add_argument(
771 '-t', '--template', dest='template',
Brad Bishop870c3fc2017-05-22 23:23:13 -0400772 default='generated.mako.hpp',
Brad Bishope3a01af2017-05-15 17:09:04 -0400773 help='The top level template to render.')
774 parser.add_argument(
775 '-p', '--template-path', dest='template_search',
776 default=script_dir,
777 help='The space delimited mako template search path.')
Brad Bishop34a7acd2017-04-27 23:47:23 -0400778 parser.add_argument(
779 '-d', '--dir', dest='inputdir',
780 default=os.path.join(script_dir, 'example'),
781 help='Location of files to process.')
782 parser.add_argument(
783 'command', metavar='COMMAND', type=str,
784 choices=valid_commands.keys(),
785 help='%s.' % " | ".join(valid_commands.keys()))
Matthew Barthdb440d42017-04-17 15:49:37 -0500786
Brad Bishop34a7acd2017-04-27 23:47:23 -0400787 args = parser.parse_args()
788
789 if sys.version_info < (3, 0):
790 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -0400791 directories=args.template_search.split(),
Brad Bishop34a7acd2017-04-27 23:47:23 -0400792 disable_unicode=True)
793 else:
794 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -0400795 directories=args.template_search.split())
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400796 try:
797 function = getattr(
798 Everything.load(args),
799 valid_commands[args.command])
800 function(lookup)
801 except InvalidConfigError as e:
802 sys.stdout.write('{0}: {1}\n\n'.format(e.config, e.msg))
803 raise