blob: b0e09084b08aed78e267e12a4b06ba100aa32f6e [file] [log] [blame]
Marri Devender Rao44fd7e82020-03-08 09:51:34 -05001#!/usr/bin/env python3
Matthew Barthdb440d42017-04-17 15:49:37 -05002
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 Bishop01079892017-05-26 10:56:45 -040087class Cast(object):
88 '''Decorate an argument by casting it.'''
89
90 def __init__(self, cast, target):
91 '''cast is the cast type (static, const, etc...).
92 target is the cast target type.'''
93 self.cast = cast
94 self.target = target
95
96 def __call__(self, arg):
97 return '{0}_cast<{1}>({2})'.format(self.cast, self.target, arg)
98
99
100class Literal(object):
101 '''Decorate an argument with a literal operator.'''
102
103 integer_types = [
Brad Bishop01079892017-05-26 10:56:45 -0400104 'int16',
105 'int32',
106 'int64',
Brad Bishop01079892017-05-26 10:56:45 -0400107 'uint16',
108 'uint32',
109 'uint64'
110 ]
111
112 def __init__(self, type):
113 self.type = type
114
115 def __call__(self, arg):
116 if 'uint' in self.type:
117 arg = '{0}ull'.format(arg)
118 elif 'int' in self.type:
119 arg = '{0}ll'.format(arg)
120
121 if self.type in self.integer_types:
122 return Cast('static', '{0}_t'.format(self.type))(arg)
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400123 elif self.type == 'byte':
124 return Cast('static', 'uint8_t'.format(self.type))(arg)
Brad Bishop01079892017-05-26 10:56:45 -0400125
126 if self.type == 'string':
127 return '{0}s'.format(arg)
128
129 return arg
130
131
132class FixBool(object):
133 '''Un-capitalize booleans.'''
134
135 def __call__(self, arg):
136 return '{0}'.format(arg.lower())
137
138
139class Quote(object):
140 '''Decorate an argument by quoting it.'''
141
142 def __call__(self, arg):
143 return '"{0}"'.format(arg)
144
145
146class Argument(NamedElement, Renderer):
Gunnar Mills06fdaff2018-04-08 16:28:18 -0500147 '''Define argument type interface.'''
Brad Bishop01079892017-05-26 10:56:45 -0400148
149 def __init__(self, **kw):
150 self.type = kw.pop('type', None)
151 super(Argument, self).__init__(**kw)
152
153 def argument(self, loader, indent):
154 raise NotImplementedError
155
156
157class TrivialArgument(Argument):
158 '''Non-array type arguments.'''
159
160 def __init__(self, **kw):
161 self.value = kw.pop('value')
162 self.decorators = kw.pop('decorators', [])
163 if kw.get('type', None):
164 self.decorators.insert(0, Literal(kw['type']))
165 if kw.get('type', None) == 'string':
166 self.decorators.insert(0, Quote())
167 if kw.get('type', None) == 'boolean':
168 self.decorators.insert(0, FixBool())
169
170 super(TrivialArgument, self).__init__(**kw)
171
172 def argument(self, loader, indent):
173 a = str(self.value)
174 for d in self.decorators:
175 a = d(a)
176
177 return a
178
Matt Spinler80e9b652017-11-02 14:21:04 -0500179
Gunnar Mills30474cf2017-08-11 09:38:54 -0500180class Metadata(Argument):
181 '''Metadata type arguments.'''
182
183 def __init__(self, **kw):
184 self.value = kw.pop('value')
185 self.decorators = kw.pop('decorators', [])
186 if kw.get('type', None) == 'string':
187 self.decorators.insert(0, Quote())
188
189 super(Metadata, self).__init__(**kw)
190
191 def argument(self, loader, indent):
192 a = str(self.value)
193 for d in self.decorators:
194 a = d(a)
195
196 return a
Brad Bishop01079892017-05-26 10:56:45 -0400197
Matt Spinler80e9b652017-11-02 14:21:04 -0500198
Matthew Barthae786ef2019-09-04 15:46:13 -0500199class OpArgument(Argument):
200 '''Operation type arguments.'''
201
202 def __init__(self, **kw):
203 self.op = kw.pop('op')
204 self.bound = kw.pop('bound')
205 self.decorators = kw.pop('decorators', [])
206 if kw.get('type', None):
207 self.decorators.insert(0, Literal(kw['type']))
208 if kw.get('type', None) == 'string':
209 self.decorators.insert(0, Quote())
210 if kw.get('type', None) == 'boolean':
211 self.decorators.insert(0, FixBool())
212
213 super(OpArgument, self).__init__(**kw)
214
215 def argument(self, loader, indent):
216 a = str(self.bound)
217 for d in self.decorators:
218 a = d(a)
219
220 return a
221
222
Brad Bishop34a7acd2017-04-27 23:47:23 -0400223class Indent(object):
224 '''Help templates be depth agnostic.'''
Matthew Barthdb440d42017-04-17 15:49:37 -0500225
Brad Bishop34a7acd2017-04-27 23:47:23 -0400226 def __init__(self, depth=0):
227 self.depth = depth
Matthew Barthdb440d42017-04-17 15:49:37 -0500228
Brad Bishop34a7acd2017-04-27 23:47:23 -0400229 def __add__(self, depth):
230 return Indent(self.depth + depth)
231
232 def __call__(self, depth):
233 '''Render an indent at the current depth plus depth.'''
234 return 4*' '*(depth + self.depth)
235
236
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400237class ConfigEntry(NamedElement):
238 '''Base interface for rendered items.'''
239
240 def __init__(self, *a, **kw):
241 '''Pop the configfile/class/subclass keywords.'''
242
243 self.configfile = kw.pop('configfile')
244 self.cls = kw.pop('class')
245 self.subclass = kw.pop(self.cls)
Patrick Williamscfdfa0d2021-09-20 18:32:17 -0500246
247 # TODO: NamedElement requires 'name' to be a string, but in many cases
248 # this script treats 'name' as a dict. Save the property off and
249 # insert it after ConfigEntry does its own thing to avoid
250 # exceptions. This should be refactored throughout the whole
251 # script to not overload 'name' as a dict.
252 name_save = kw.pop('name')
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400253 super(ConfigEntry, self).__init__(**kw)
Patrick Williamscfdfa0d2021-09-20 18:32:17 -0500254 self.name = name_save
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400255
256 def factory(self, objs):
257 ''' Optional factory interface for subclasses to add
258 additional items to be rendered.'''
259
260 pass
261
262 def setup(self, objs):
263 ''' Optional setup interface for subclasses, invoked
264 after all factory methods have been run.'''
265
266 pass
267
268
Brad Bishop0e7df132017-05-23 17:58:12 -0400269class Path(ConfigEntry):
270 '''Path/metadata association.'''
271
272 def __init__(self, *a, **kw):
273 super(Path, self).__init__(**kw)
274
Brad Bishopbabf3b72017-05-31 19:44:53 -0400275 if self.name['meta'].upper() != self.name['meta']:
276 raise InvalidConfigError(
277 self.configfile,
278 'Metadata tag "{0}" must be upper case.'.format(
279 self.name['meta']))
280
Brad Bishop0e7df132017-05-23 17:58:12 -0400281 def factory(self, objs):
282 '''Create path and metadata elements.'''
283
284 args = {
285 'class': 'pathname',
286 'pathname': 'element',
287 'name': self.name['path']
288 }
289 add_unique(ConfigEntry(
290 configfile=self.configfile, **args), objs)
291
292 args = {
293 'class': 'meta',
294 'meta': 'element',
295 'name': self.name['meta']
296 }
297 add_unique(ConfigEntry(
298 configfile=self.configfile, **args), objs)
299
300 super(Path, self).factory(objs)
301
302 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500303 '''Resolve path and metadata names to indices.'''
Brad Bishop0e7df132017-05-23 17:58:12 -0400304
305 self.path = get_index(
306 objs, 'pathname', self.name['path'])
307 self.meta = get_index(
308 objs, 'meta', self.name['meta'])
309
310 super(Path, self).setup(objs)
311
312
Brad Bishope73b2c32017-05-23 18:01:54 -0400313class Property(ConfigEntry):
314 '''Property/interface/metadata association.'''
315
316 def __init__(self, *a, **kw):
317 super(Property, self).__init__(**kw)
318
Brad Bishopbabf3b72017-05-31 19:44:53 -0400319 if self.name['meta'].upper() != self.name['meta']:
320 raise InvalidConfigError(
321 self.configfile,
322 'Metadata tag "{0}" must be upper case.'.format(
323 self.name['meta']))
324
Brad Bishope73b2c32017-05-23 18:01:54 -0400325 def factory(self, objs):
326 '''Create interface, property name and metadata elements.'''
327
328 args = {
329 'class': 'interface',
330 'interface': 'element',
331 'name': self.name['interface']
332 }
333 add_unique(ConfigEntry(
334 configfile=self.configfile, **args), objs)
335
336 args = {
337 'class': 'propertyname',
338 'propertyname': 'element',
339 'name': self.name['property']
340 }
341 add_unique(ConfigEntry(
342 configfile=self.configfile, **args), objs)
343
344 args = {
345 'class': 'meta',
346 'meta': 'element',
347 'name': self.name['meta']
348 }
349 add_unique(ConfigEntry(
350 configfile=self.configfile, **args), objs)
351
352 super(Property, self).factory(objs)
353
354 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500355 '''Resolve interface, property and metadata to indices.'''
Brad Bishope73b2c32017-05-23 18:01:54 -0400356
357 self.interface = get_index(
358 objs, 'interface', self.name['interface'])
359 self.prop = get_index(
360 objs, 'propertyname', self.name['property'])
361 self.meta = get_index(
362 objs, 'meta', self.name['meta'])
363
364 super(Property, self).setup(objs)
365
366
Brad Bishop4b916f12017-05-23 18:06:38 -0400367class Instance(ConfigEntry):
368 '''Property/Path association.'''
369
370 def __init__(self, *a, **kw):
371 super(Instance, self).__init__(**kw)
372
373 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500374 '''Resolve elements to indices.'''
Brad Bishop4b916f12017-05-23 18:06:38 -0400375
376 self.interface = get_index(
377 objs, 'interface', self.name['property']['interface'])
378 self.prop = get_index(
379 objs, 'propertyname', self.name['property']['property'])
380 self.propmeta = get_index(
381 objs, 'meta', self.name['property']['meta'])
382 self.path = get_index(
383 objs, 'pathname', self.name['path']['path'])
384 self.pathmeta = get_index(
385 objs, 'meta', self.name['path']['meta'])
386
387 super(Instance, self).setup(objs)
388
Marri Devender Rao80c70612018-04-12 09:22:55 -0500389class PathInstance(ConfigEntry):
390 '''Path association.'''
391
392 def __init__(self, *a, **kw):
393 super(PathInstance, self).__init__(**kw)
394
395 def setup(self, objs):
396 '''Resolve elements to indices.'''
397 self.path = self.name['path']['path']
398 self.pathmeta = self.name['path']['meta']
399 super(PathInstance, self).setup(objs)
Brad Bishop4b916f12017-05-23 18:06:38 -0400400
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400401class Group(ConfigEntry):
402 '''Pop the members keyword for groups.'''
403
404 def __init__(self, *a, **kw):
405 self.members = kw.pop('members')
406 super(Group, self).__init__(**kw)
407
408
409class ImplicitGroup(Group):
410 '''Provide a factory method for groups whose members are
411 not explicitly declared in the config files.'''
412
413 def __init__(self, *a, **kw):
414 super(ImplicitGroup, self).__init__(**kw)
415
416 def factory(self, objs):
417 '''Create group members.'''
418
419 factory = Everything.classmap(self.subclass, 'element')
420 for m in self.members:
421 args = {
422 'class': self.subclass,
423 self.subclass: 'element',
424 'name': m
425 }
426
427 obj = factory(configfile=self.configfile, **args)
428 add_unique(obj, objs)
429 obj.factory(objs)
430
431 super(ImplicitGroup, self).factory(objs)
432
433
Brad Bishop0e7df132017-05-23 17:58:12 -0400434class GroupOfPaths(ImplicitGroup):
435 '''Path group config file directive.'''
436
437 def __init__(self, *a, **kw):
438 super(GroupOfPaths, self).__init__(**kw)
439
440 def setup(self, objs):
441 '''Resolve group members.'''
442
443 def map_member(x):
444 path = get_index(
445 objs, 'pathname', x['path'])
446 meta = get_index(
447 objs, 'meta', x['meta'])
448 return (path, meta)
449
450 self.members = map(
451 map_member,
452 self.members)
453
454 super(GroupOfPaths, self).setup(objs)
455
456
Brad Bishope73b2c32017-05-23 18:01:54 -0400457class GroupOfProperties(ImplicitGroup):
458 '''Property group config file directive.'''
459
460 def __init__(self, *a, **kw):
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400461 self.type = kw.pop('type')
Brad Bishope73b2c32017-05-23 18:01:54 -0400462 self.datatype = sdbusplus.property.Property(
463 name=kw.get('name'),
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400464 type=self.type).cppTypeName
Brad Bishope73b2c32017-05-23 18:01:54 -0400465
466 super(GroupOfProperties, self).__init__(**kw)
467
468 def setup(self, objs):
469 '''Resolve group members.'''
470
471 def map_member(x):
472 iface = get_index(
473 objs, 'interface', x['interface'])
474 prop = get_index(
475 objs, 'propertyname', x['property'])
476 meta = get_index(
477 objs, 'meta', x['meta'])
478
479 return (iface, prop, meta)
480
481 self.members = map(
482 map_member,
483 self.members)
484
485 super(GroupOfProperties, self).setup(objs)
486
487
Brad Bishop4b916f12017-05-23 18:06:38 -0400488class GroupOfInstances(ImplicitGroup):
489 '''A group of property instances.'''
490
491 def __init__(self, *a, **kw):
492 super(GroupOfInstances, self).__init__(**kw)
493
494 def setup(self, objs):
495 '''Resolve group members.'''
496
497 def map_member(x):
498 path = get_index(objs, 'pathname', x['path']['path'])
499 pathmeta = get_index(objs, 'meta', x['path']['meta'])
500 interface = get_index(
501 objs, 'interface', x['property']['interface'])
502 prop = get_index(objs, 'propertyname', x['property']['property'])
503 propmeta = get_index(objs, 'meta', x['property']['meta'])
504 instance = get_index(objs, 'instance', x)
505
506 return (path, pathmeta, interface, prop, propmeta, instance)
507
508 self.members = map(
509 map_member,
510 self.members)
511
512 super(GroupOfInstances, self).setup(objs)
513
Marri Devender Rao80c70612018-04-12 09:22:55 -0500514class GroupOfPathInstances(ImplicitGroup):
515 '''A group of path instances.'''
516
517 def __init__(self, *a, **kw):
518 super(GroupOfPathInstances, self).__init__(**kw)
519
520 def setup(self, objs):
521 '''Resolve group members.'''
522
523 def map_member(x):
524 path = get_index(objs, 'pathname', x['path']['path'])
525 pathmeta = get_index(objs, 'meta', x['path']['meta'])
526 pathinstance = get_index(objs, 'pathinstance', x)
527 return (path, pathmeta, pathinstance)
528
529 self.members = map(
530 map_member,
531 self.members)
532
533 super(GroupOfPathInstances, self).setup(objs)
534
Brad Bishop4b916f12017-05-23 18:06:38 -0400535
536class HasPropertyIndex(ConfigEntry):
537 '''Handle config file directives that require an index to be
538 constructed.'''
539
540 def __init__(self, *a, **kw):
541 self.paths = kw.pop('paths')
542 self.properties = kw.pop('properties')
543 super(HasPropertyIndex, self).__init__(**kw)
544
545 def factory(self, objs):
546 '''Create a group of instances for this index.'''
547
548 members = []
549 path_group = get_index(
550 objs, 'pathgroup', self.paths, config=self.configfile)
551 property_group = get_index(
552 objs, 'propertygroup', self.properties, config=self.configfile)
553
554 for path in objs['pathgroup'][path_group].members:
555 for prop in objs['propertygroup'][property_group].members:
556 member = {
557 'path': path,
558 'property': prop,
559 }
560 members.append(member)
561
562 args = {
563 'members': members,
564 'class': 'instancegroup',
565 'instancegroup': 'instance',
566 'name': '{0} {1}'.format(self.paths, self.properties)
567 }
568
569 group = GroupOfInstances(configfile=self.configfile, **args)
570 add_unique(group, objs, config=self.configfile)
571 group.factory(objs)
572
573 super(HasPropertyIndex, self).factory(objs)
574
575 def setup(self, objs):
576 '''Resolve path, property, and instance groups.'''
577
578 self.instances = get_index(
579 objs,
580 'instancegroup',
581 '{0} {1}'.format(self.paths, self.properties),
582 config=self.configfile)
583 self.paths = get_index(
584 objs,
585 'pathgroup',
586 self.paths,
587 config=self.configfile)
588 self.properties = get_index(
589 objs,
590 'propertygroup',
591 self.properties,
592 config=self.configfile)
593 self.datatype = objs['propertygroup'][self.properties].datatype
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400594 self.type = objs['propertygroup'][self.properties].type
Brad Bishop4b916f12017-05-23 18:06:38 -0400595
596 super(HasPropertyIndex, self).setup(objs)
597
Marri Devender Rao80c70612018-04-12 09:22:55 -0500598class HasPathIndex(ConfigEntry):
599 '''Handle config file directives that require an index to be
600 constructed.'''
601
602 def __init__(self, *a, **kw):
603 self.paths = kw.pop('paths')
604 super(HasPathIndex, self).__init__(**kw)
605
606 def factory(self, objs):
607 '''Create a group of instances for this index.'''
608
609 members = []
610 path_group = get_index(
611 objs, 'pathgroup', self.paths, config=self.configfile)
612
613 for path in objs['pathgroup'][path_group].members:
614 member = {
615 'path': path,
616 }
617 members.append(member)
618
619 args = {
620 'members': members,
621 'class': 'pathinstancegroup',
622 'pathinstancegroup': 'pathinstance',
623 'name': '{0}'.format(self.paths)
624 }
625
626 group = GroupOfPathInstances(configfile=self.configfile, **args)
627 add_unique(group, objs, config=self.configfile)
628 group.factory(objs)
629
630 super(HasPathIndex, self).factory(objs)
631
632 def setup(self, objs):
633 '''Resolve path and instance groups.'''
634
635 self.pathinstances = get_index(
636 objs,
637 'pathinstancegroup',
638 '{0}'.format(self.paths),
639 config=self.configfile)
640 self.paths = get_index(
641 objs,
642 'pathgroup',
643 self.paths,
644 config=self.configfile)
645 super(HasPathIndex, self).setup(objs)
Brad Bishop4b916f12017-05-23 18:06:38 -0400646
Matthew Barthefe01582019-09-09 15:22:37 -0500647class GroupOfFilters(ConfigEntry):
648 '''Handle config file directives that require an index for filters.'''
649
650 def __init__(self, *a, **kw):
651 # Pop filters data for adding to the available filters array
652 self.type = kw.pop('type')
653 self.datatype = kw.pop('datatype', None)
654 self.filters = kw.pop('filters', None)
655
656 super(GroupOfFilters, self).__init__(**kw)
657
658 def factory(self, objs):
659 '''Modify filters to add the property value type and
660 make them of operation argument type.'''
661 if self.filters:
662 # 'type' used within OpArgument to generate filter
663 # argument values so add to each filter
664 for f in self.filters:
665 f['type'] = self.type
666 self.filters = [OpArgument(**x) for x in self.filters]
667
668 super(GroupOfFilters, self).factory(objs)
669
Brad Bishop4b916f12017-05-23 18:06:38 -0400670class PropertyWatch(HasPropertyIndex):
671 '''Handle the property watch config file directive.'''
672
673 def __init__(self, *a, **kw):
Matthew Barthefe01582019-09-09 15:22:37 -0500674 # Pop optional filters for the properties being watched
675 self.filters = kw.pop('filters', None)
Brad Bishopfccdc392017-05-22 21:11:09 -0400676 self.callback = kw.pop('callback', None)
Brad Bishop4b916f12017-05-23 18:06:38 -0400677 super(PropertyWatch, self).__init__(**kw)
678
Matthew Barthefe01582019-09-09 15:22:37 -0500679 def factory(self, objs):
680 '''Create any filters for this property watch.'''
681
682 if self.filters:
683 # Get the datatype(i.e. "int64_t") of the properties in this watch
684 # (Made available after all `super` classes init'd)
685 datatype = objs['propertygroup'][get_index(
686 objs,
687 'propertygroup',
688 self.properties,
689 config=self.configfile)].datatype
690 # Get the type(i.e. "int64") of the properties in this watch
691 # (Made available after all `super` classes init'd)
692 type = objs['propertygroup'][get_index(
693 objs,
694 'propertygroup',
695 self.properties,
696 config=self.configfile)].type
697 # Construct the data needed to make the filters for
698 # this watch available.
699 # *Note: 'class', 'subclass', 'name' are required for
700 # storing the filter data(i.e. 'type', 'datatype', & 'filters')
701 args = {
702 'type': type,
703 'datatype': datatype,
704 'filters': self.filters,
705 'class': 'filtersgroup',
706 'filtersgroup': 'filters',
707 'name': self.name,
708 }
709 # Init GroupOfFilters class with this watch's filters' arguments
710 group = GroupOfFilters(configfile=self.configfile, **args)
711 # Store this group of filters so it can be indexed later
712 add_unique(group, objs, config=self.configfile)
713 group.factory(objs)
714
715 super(PropertyWatch, self).factory(objs)
716
Brad Bishopfccdc392017-05-22 21:11:09 -0400717 def setup(self, objs):
Matthew Barthefe01582019-09-09 15:22:37 -0500718 '''Resolve optional filters and callback.'''
719
720 if self.filters:
721 # Watch has filters, provide array index to access them
722 self.filters = get_index(
723 objs,
724 'filtersgroup',
725 self.name,
726 config=self.configfile)
Brad Bishopfccdc392017-05-22 21:11:09 -0400727
728 if self.callback:
729 self.callback = get_index(
730 objs,
731 'callback',
732 self.callback,
733 config=self.configfile)
734
735 super(PropertyWatch, self).setup(objs)
736
Marri Devender Rao80c70612018-04-12 09:22:55 -0500737class PathWatch(HasPathIndex):
738 '''Handle the path watch config file directive.'''
739
740 def __init__(self, *a, **kw):
741 self.pathcallback = kw.pop('pathcallback', None)
742 super(PathWatch, self).__init__(**kw)
743
744 def setup(self, objs):
745 '''Resolve optional callback.'''
746 if self.pathcallback:
747 self.pathcallback = get_index(
748 objs,
749 'pathcallback',
750 self.pathcallback,
751 config=self.configfile)
752 super(PathWatch, self).setup(objs)
753
Brad Bishopc1283ae2017-05-20 21:42:38 -0400754class Callback(HasPropertyIndex):
755 '''Interface and common logic for callbacks.'''
756
757 def __init__(self, *a, **kw):
758 super(Callback, self).__init__(**kw)
759
Marri Devender Rao80c70612018-04-12 09:22:55 -0500760class PathCallback(HasPathIndex):
761 '''Interface and common logic for callbacks.'''
762
763 def __init__(self, *a, **kw):
764 super(PathCallback, self).__init__(**kw)
Brad Bishopc1283ae2017-05-20 21:42:38 -0400765
Brad Bishop4041d722017-05-21 10:06:07 -0400766class ConditionCallback(ConfigEntry, Renderer):
767 '''Handle the journal callback config file directive.'''
768
769 def __init__(self, *a, **kw):
770 self.condition = kw.pop('condition')
771 self.instance = kw.pop('instance')
Brad Bishop3539db62017-05-30 14:21:12 -0400772 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400773 super(ConditionCallback, self).__init__(**kw)
774
775 def factory(self, objs):
776 '''Create a graph instance for this callback.'''
777
778 args = {
779 'configfile': self.configfile,
780 'members': [self.instance],
781 'class': 'callbackgroup',
782 'callbackgroup': 'callback',
783 'name': [self.instance]
784 }
785
786 entry = CallbackGraphEntry(**args)
787 add_unique(entry, objs, config=self.configfile)
788
789 super(ConditionCallback, self).factory(objs)
790
791 def setup(self, objs):
792 '''Resolve condition and graph entry.'''
793
794 self.graph = get_index(
795 objs,
796 'callbackgroup',
797 [self.instance],
798 config=self.configfile)
799
800 self.condition = get_index(
801 objs,
802 'condition',
803 self.name,
804 config=self.configfile)
805
806 super(ConditionCallback, self).setup(objs)
807
808 def construct(self, loader, indent):
809 return self.render(
810 loader,
811 'conditional.mako.cpp',
812 c=self,
813 indent=indent)
814
815
816class Condition(HasPropertyIndex):
817 '''Interface and common logic for conditions.'''
818
819 def __init__(self, *a, **kw):
820 self.callback = kw.pop('callback')
Brad Bishop3539db62017-05-30 14:21:12 -0400821 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400822 super(Condition, self).__init__(**kw)
823
824 def factory(self, objs):
825 '''Create a callback instance for this conditional.'''
826
827 args = {
828 'configfile': self.configfile,
829 'condition': self.name,
830 'class': 'callback',
831 'callback': 'conditional',
832 'instance': self.callback,
833 'name': self.name,
Brad Bishop3539db62017-05-30 14:21:12 -0400834 'defer': self.defer
Brad Bishop4041d722017-05-21 10:06:07 -0400835 }
836
837 callback = ConditionCallback(**args)
838 add_unique(callback, objs, config=self.configfile)
839 callback.factory(objs)
840
841 super(Condition, self).factory(objs)
842
843
844class CountCondition(Condition, Renderer):
845 '''Handle the count condition config file directive.'''
846
847 def __init__(self, *a, **kw):
848 self.countop = kw.pop('countop')
849 self.countbound = kw.pop('countbound')
850 self.op = kw.pop('op')
851 self.bound = kw.pop('bound')
Matt Spinlerc458dee2018-02-19 13:09:10 -0600852 self.oneshot = TrivialArgument(
853 type='boolean',
854 value=kw.pop('oneshot', False))
Brad Bishop4041d722017-05-21 10:06:07 -0400855 super(CountCondition, self).__init__(**kw)
856
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400857 def setup(self, objs):
858 '''Resolve type.'''
859
860 super(CountCondition, self).setup(objs)
861 self.bound = TrivialArgument(
862 type=self.type,
863 value=self.bound)
864
Brad Bishop4041d722017-05-21 10:06:07 -0400865 def construct(self, loader, indent):
866 return self.render(
867 loader,
868 'count.mako.cpp',
869 c=self,
870 indent=indent)
871
872
Matthew Barthefdd03c2019-09-04 15:44:35 -0500873class MedianCondition(Condition, Renderer):
874 '''Handle the median condition config file directive.'''
875
876 def __init__(self, *a, **kw):
877 self.op = kw.pop('op')
878 self.bound = kw.pop('bound')
879 self.oneshot = TrivialArgument(
880 type='boolean',
881 value=kw.pop('oneshot', False))
882 super(MedianCondition, self).__init__(**kw)
883
884 def setup(self, objs):
885 '''Resolve type.'''
886
887 super(MedianCondition, self).setup(objs)
888 self.bound = TrivialArgument(
889 type=self.type,
890 value=self.bound)
891
892 def construct(self, loader, indent):
893 return self.render(
894 loader,
895 'median.mako.cpp',
896 c=self,
897 indent=indent)
898
899
Brad Bishopc1283ae2017-05-20 21:42:38 -0400900class Journal(Callback, Renderer):
901 '''Handle the journal callback config file directive.'''
902
903 def __init__(self, *a, **kw):
904 self.severity = kw.pop('severity')
905 self.message = kw.pop('message')
906 super(Journal, self).__init__(**kw)
907
908 def construct(self, loader, indent):
909 return self.render(
910 loader,
911 'journal.mako.cpp',
912 c=self,
913 indent=indent)
914
915
Gunnar Millsd5faea32017-08-08 14:19:36 -0500916class Elog(Callback, Renderer):
917 '''Handle the elog callback config file directive.'''
918
919 def __init__(self, *a, **kw):
920 self.error = kw.pop('error')
Gunnar Mills30474cf2017-08-11 09:38:54 -0500921 self.metadata = [Metadata(**x) for x in kw.pop('metadata', {})]
Gunnar Millsd5faea32017-08-08 14:19:36 -0500922 super(Elog, self).__init__(**kw)
923
924 def construct(self, loader, indent):
Gunnar Millsd5faea32017-08-08 14:19:36 -0500925 with open('errors.hpp', 'a') as fd:
926 fd.write(
927 self.render(
928 loader,
929 'errors.mako.hpp',
930 c=self))
931 return self.render(
932 loader,
933 'elog.mako.cpp',
934 c=self,
935 indent=indent)
936
Ratan Gupta90bfaea2017-10-06 20:56:31 +0530937class Event(Callback, Renderer):
938 '''Handle the event callback config file directive.'''
939
940 def __init__(self, *a, **kw):
941 self.eventName = kw.pop('eventName')
942 self.eventMessage = kw.pop('eventMessage')
943 super(Event, self).__init__(**kw)
944
945 def construct(self, loader, indent):
946 return self.render(
947 loader,
948 'event.mako.cpp',
949 c=self,
950 indent=indent)
Gunnar Millsd5faea32017-08-08 14:19:36 -0500951
Marri Devender Rao80c70612018-04-12 09:22:55 -0500952class EventPath(PathCallback, Renderer):
953 '''Handle the event path callback config file directive.'''
954
955 def __init__(self, *a, **kw):
956 self.eventType = kw.pop('eventType')
957 super(EventPath, self).__init__(**kw)
958
959 def construct(self, loader, indent):
960 return self.render(
961 loader,
962 'eventpath.mako.cpp',
963 c=self,
964 indent=indent)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600965
966class ElogWithMetadata(Callback, Renderer):
967 '''Handle the elog_with_metadata callback config file directive.'''
968
969 def __init__(self, *a, **kw):
970 self.error = kw.pop('error')
971 self.metadata = kw.pop('metadata')
972 super(ElogWithMetadata, self).__init__(**kw)
973
974 def construct(self, loader, indent):
975 with open('errors.hpp', 'a') as fd:
976 fd.write(
977 self.render(
978 loader,
979 'errors.mako.hpp',
980 c=self))
981 return self.render(
982 loader,
983 'elog_with_metadata.mako.cpp',
984 c=self,
985 indent=indent)
986
987
Matt Spinler1d6ca482017-11-01 10:48:02 -0500988class ResolveCallout(Callback, Renderer):
989 '''Handle the 'resolve callout' callback config file directive.'''
990
991 def __init__(self, *a, **kw):
992 self.callout = kw.pop('callout')
993 super(ResolveCallout, self).__init__(**kw)
994
995 def construct(self, loader, indent):
996 return self.render(
997 loader,
998 'resolve_errors.mako.cpp',
999 c=self,
1000 indent=indent)
1001
1002
Brad Bishop0df00be2017-05-25 23:38:37 -04001003class Method(ConfigEntry, Renderer):
1004 '''Handle the method callback config file directive.'''
1005
1006 def __init__(self, *a, **kw):
1007 self.service = kw.pop('service')
1008 self.path = kw.pop('path')
1009 self.interface = kw.pop('interface')
1010 self.method = kw.pop('method')
1011 self.args = [TrivialArgument(**x) for x in kw.pop('args', {})]
1012 super(Method, self).__init__(**kw)
1013
1014 def factory(self, objs):
1015 args = {
1016 'class': 'interface',
1017 'interface': 'element',
1018 'name': self.service
1019 }
1020 add_unique(ConfigEntry(
1021 configfile=self.configfile, **args), objs)
1022
1023 args = {
1024 'class': 'pathname',
1025 'pathname': 'element',
1026 'name': self.path
1027 }
1028 add_unique(ConfigEntry(
1029 configfile=self.configfile, **args), objs)
1030
1031 args = {
1032 'class': 'interface',
1033 'interface': 'element',
1034 'name': self.interface
1035 }
1036 add_unique(ConfigEntry(
1037 configfile=self.configfile, **args), objs)
1038
1039 args = {
1040 'class': 'propertyname',
1041 'propertyname': 'element',
1042 'name': self.method
1043 }
1044 add_unique(ConfigEntry(
1045 configfile=self.configfile, **args), objs)
1046
1047 super(Method, self).factory(objs)
1048
1049 def setup(self, objs):
1050 '''Resolve elements.'''
1051
1052 self.service = get_index(
1053 objs,
1054 'interface',
1055 self.service)
1056
1057 self.path = get_index(
1058 objs,
1059 'pathname',
1060 self.path)
1061
1062 self.interface = get_index(
1063 objs,
1064 'interface',
1065 self.interface)
1066
1067 self.method = get_index(
1068 objs,
1069 'propertyname',
1070 self.method)
1071
1072 super(Method, self).setup(objs)
1073
1074 def construct(self, loader, indent):
1075 return self.render(
1076 loader,
1077 'method.mako.cpp',
1078 c=self,
1079 indent=indent)
1080
1081
Brad Bishop49e66172017-05-23 19:16:21 -04001082class CallbackGraphEntry(Group):
1083 '''An entry in a traversal list for groups of callbacks.'''
1084
1085 def __init__(self, *a, **kw):
1086 super(CallbackGraphEntry, self).__init__(**kw)
1087
1088 def setup(self, objs):
1089 '''Resolve group members.'''
1090
1091 def map_member(x):
1092 return get_index(
1093 objs, 'callback', x, config=self.configfile)
1094
1095 self.members = map(
1096 map_member,
1097 self.members)
1098
1099 super(CallbackGraphEntry, self).setup(objs)
1100
Marri Devender Rao80c70612018-04-12 09:22:55 -05001101class PathCallbackGraphEntry(Group):
1102 '''An entry in a traversal list for groups of callbacks.'''
1103
1104 def __init__(self, *a, **kw):
1105 super(PathCallbackGraphEntry, self).__init__(**kw)
1106
1107 def setup(self, objs):
1108 '''Resolve group members.'''
1109
1110 def map_member(x):
1111 return get_index(
1112 objs, 'pathcallback', x, config=self.configfile)
1113
1114 self.members = map(
1115 map_member,
1116 self.members)
1117
1118 super(PathCallbackGraphEntry, self).setup(objs)
Brad Bishop49e66172017-05-23 19:16:21 -04001119
1120class GroupOfCallbacks(ConfigEntry, Renderer):
1121 '''Handle the callback group config file directive.'''
1122
1123 def __init__(self, *a, **kw):
1124 self.members = kw.pop('members')
1125 super(GroupOfCallbacks, self).__init__(**kw)
1126
1127 def factory(self, objs):
1128 '''Create a graph instance for this group of callbacks.'''
1129
1130 args = {
1131 'configfile': self.configfile,
1132 'members': self.members,
1133 'class': 'callbackgroup',
1134 'callbackgroup': 'callback',
1135 'name': self.members
1136 }
1137
1138 entry = CallbackGraphEntry(**args)
1139 add_unique(entry, objs, config=self.configfile)
1140
1141 super(GroupOfCallbacks, self).factory(objs)
1142
1143 def setup(self, objs):
1144 '''Resolve graph entry.'''
1145
1146 self.graph = get_index(
1147 objs, 'callbackgroup', self.members, config=self.configfile)
1148
1149 super(GroupOfCallbacks, self).setup(objs)
1150
1151 def construct(self, loader, indent):
1152 return self.render(
1153 loader,
1154 'callbackgroup.mako.cpp',
1155 c=self,
1156 indent=indent)
1157
Marri Devender Rao80c70612018-04-12 09:22:55 -05001158class GroupOfPathCallbacks(ConfigEntry, Renderer):
1159 '''Handle the callback group config file directive.'''
1160
1161 def __init__(self, *a, **kw):
1162 self.members = kw.pop('members')
1163 super(GroupOfPathCallbacks, self).__init__(**kw)
1164
1165 def factory(self, objs):
1166 '''Create a graph instance for this group of callbacks.'''
1167
1168 args = {
1169 'configfile': self.configfile,
1170 'members': self.members,
1171 'class': 'pathcallbackgroup',
1172 'pathcallbackgroup': 'pathcallback',
1173 'name': self.members
1174 }
1175
1176 entry = PathCallbackGraphEntry(**args)
1177 add_unique(entry, objs, config=self.configfile)
1178 super(GroupOfPathCallbacks, self).factory(objs)
1179
1180 def setup(self, objs):
1181 '''Resolve graph entry.'''
1182
1183 self.graph = get_index(
1184 objs, 'callbackpathgroup', self.members, config=self.configfile)
1185
1186 super(GroupOfPathCallbacks, self).setup(objs)
1187
1188 def construct(self, loader, indent):
1189 return self.render(
1190 loader,
1191 'callbackpathgroup.mako.cpp',
1192 c=self,
1193 indent=indent)
Brad Bishop49e66172017-05-23 19:16:21 -04001194
Brad Bishop34a7acd2017-04-27 23:47:23 -04001195class Everything(Renderer):
1196 '''Parse/render entry point.'''
1197
1198 @staticmethod
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001199 def classmap(cls, sub=None):
1200 '''Map render item class and subclass entries to the appropriate
1201 handler methods.'''
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001202 class_map = {
Brad Bishop0e7df132017-05-23 17:58:12 -04001203 'path': {
1204 'element': Path,
1205 },
1206 'pathgroup': {
1207 'path': GroupOfPaths,
1208 },
Brad Bishope73b2c32017-05-23 18:01:54 -04001209 'propertygroup': {
1210 'property': GroupOfProperties,
1211 },
1212 'property': {
1213 'element': Property,
1214 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001215 'watch': {
1216 'property': PropertyWatch,
1217 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001218 'pathwatch': {
1219 'path': PathWatch,
1220 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001221 'instance': {
1222 'element': Instance,
1223 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001224 'pathinstance': {
1225 'element': PathInstance,
1226 },
Brad Bishopc1283ae2017-05-20 21:42:38 -04001227 'callback': {
1228 'journal': Journal,
Gunnar Millsd5faea32017-08-08 14:19:36 -05001229 'elog': Elog,
Matt Spinler3c5318d2018-02-19 14:03:05 -06001230 'elog_with_metadata': ElogWithMetadata,
Ratan Gupta90bfaea2017-10-06 20:56:31 +05301231 'event': Event,
Brad Bishop49e66172017-05-23 19:16:21 -04001232 'group': GroupOfCallbacks,
Brad Bishop0df00be2017-05-25 23:38:37 -04001233 'method': Method,
Matt Spinler1d6ca482017-11-01 10:48:02 -05001234 'resolve callout': ResolveCallout,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001235 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001236 'pathcallback': {
1237 'eventpath': EventPath,
1238 'grouppath': GroupOfPathCallbacks,
1239 },
Brad Bishop4041d722017-05-21 10:06:07 -04001240 'condition': {
1241 'count': CountCondition,
Matthew Barthefdd03c2019-09-04 15:44:35 -05001242 'median': MedianCondition,
Brad Bishop4041d722017-05-21 10:06:07 -04001243 },
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001244 }
1245
1246 if cls not in class_map:
1247 raise NotImplementedError('Unknown class: "{0}"'.format(cls))
1248 if sub not in class_map[cls]:
1249 raise NotImplementedError('Unknown {0} type: "{1}"'.format(
1250 cls, sub))
1251
1252 return class_map[cls][sub]
1253
1254 @staticmethod
1255 def load_one_yaml(path, fd, objs):
1256 '''Parse a single YAML file. Parsing occurs in three phases.
1257 In the first phase a factory method associated with each
1258 configuration file directive is invoked. These factory
1259 methods generate more factory methods. In the second
1260 phase the factory methods created in the first phase
1261 are invoked. In the last phase a callback is invoked on
1262 each object created in phase two. Typically the callback
1263 resolves references to other configuration file directives.'''
1264
1265 factory_objs = {}
1266 for x in yaml.safe_load(fd.read()) or {}:
1267
1268 # Create factory object for this config file directive.
1269 cls = x['class']
1270 sub = x.get(cls)
1271 if cls == 'group':
1272 cls = '{0}group'.format(sub)
1273
1274 factory = Everything.classmap(cls, sub)
1275 obj = factory(configfile=path, **x)
1276
1277 # For a given class of directive, validate the file
1278 # doesn't have any duplicate names (duplicates are
1279 # ok across config files).
1280 if exists(factory_objs, obj.cls, obj.name, config=path):
1281 raise NotUniqueError(path, cls, obj.name)
1282
1283 factory_objs.setdefault(cls, []).append(obj)
1284 objs.setdefault(cls, []).append(obj)
1285
1286 for cls, items in factory_objs.items():
1287 for obj in items:
1288 # Add objects for template consumption.
1289 obj.factory(objs)
1290
1291 @staticmethod
Brad Bishop34a7acd2017-04-27 23:47:23 -04001292 def load(args):
1293 '''Aggregate all the YAML in the input directory
1294 into a single aggregate.'''
1295
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001296 objs = {}
1297 yaml_files = filter(
1298 lambda x: x.endswith('.yaml'),
1299 os.listdir(args.inputdir))
Brad Bishop34a7acd2017-04-27 23:47:23 -04001300
Marri Devender Rao44fd7e82020-03-08 09:51:34 -05001301 for x in sorted(yaml_files):
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001302 path = os.path.join(args.inputdir, x)
1303 with open(path, 'r') as fd:
1304 Everything.load_one_yaml(path, fd, objs)
1305
1306 # Configuration file directives reference each other via
1307 # the name attribute; however, when rendered the reference
1308 # is just an array index.
1309 #
1310 # At this point all objects have been created but references
Gunnar Mills78199b42017-10-25 16:30:18 -05001311 # have not been resolved to array indices. Instruct objects
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001312 # to do that now.
1313 for cls, items in objs.items():
1314 for obj in items:
1315 obj.setup(objs)
1316
1317 return Everything(**objs)
Brad Bishop34a7acd2017-04-27 23:47:23 -04001318
1319 def __init__(self, *a, **kw):
Brad Bishop0e7df132017-05-23 17:58:12 -04001320 self.pathmeta = kw.pop('path', [])
1321 self.paths = kw.pop('pathname', [])
1322 self.meta = kw.pop('meta', [])
1323 self.pathgroups = kw.pop('pathgroup', [])
Brad Bishope73b2c32017-05-23 18:01:54 -04001324 self.interfaces = kw.pop('interface', [])
1325 self.properties = kw.pop('property', [])
1326 self.propertynames = kw.pop('propertyname', [])
1327 self.propertygroups = kw.pop('propertygroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001328 self.instances = kw.pop('instance', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001329 self.pathinstances = kw.pop('pathinstance', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001330 self.instancegroups = kw.pop('instancegroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001331 self.pathinstancegroups = kw.pop('pathinstancegroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001332 self.watches = kw.pop('watch', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001333 self.pathwatches = kw.pop('pathwatch', [])
Brad Bishopc1283ae2017-05-20 21:42:38 -04001334 self.callbacks = kw.pop('callback', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001335 self.pathcallbacks = kw.pop('pathcallback', [])
Brad Bishop49e66172017-05-23 19:16:21 -04001336 self.callbackgroups = kw.pop('callbackgroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001337 self.pathcallbackgroups = kw.pop('pathcallbackgroup', [])
Brad Bishop4041d722017-05-21 10:06:07 -04001338 self.conditions = kw.pop('condition', [])
Matthew Barthefe01582019-09-09 15:22:37 -05001339 self.filters = kw.pop('filtersgroup', [])
Brad Bishop0e7df132017-05-23 17:58:12 -04001340
Brad Bishop34a7acd2017-04-27 23:47:23 -04001341 super(Everything, self).__init__(**kw)
1342
1343 def generate_cpp(self, loader):
1344 '''Render the template with the provided data.'''
Gunnar Millsd5faea32017-08-08 14:19:36 -05001345 # errors.hpp is used by generated.hpp to included any error.hpp files
1346 open('errors.hpp', 'w+')
1347
Brad Bishope3a01af2017-05-15 17:09:04 -04001348 with open(args.output, 'w') as fd:
Brad Bishop34a7acd2017-04-27 23:47:23 -04001349 fd.write(
1350 self.render(
1351 loader,
Brad Bishope3a01af2017-05-15 17:09:04 -04001352 args.template,
Brad Bishop0e7df132017-05-23 17:58:12 -04001353 meta=self.meta,
Brad Bishope73b2c32017-05-23 18:01:54 -04001354 properties=self.properties,
1355 propertynames=self.propertynames,
1356 interfaces=self.interfaces,
Brad Bishop0e7df132017-05-23 17:58:12 -04001357 paths=self.paths,
1358 pathmeta=self.pathmeta,
1359 pathgroups=self.pathgroups,
Brad Bishope73b2c32017-05-23 18:01:54 -04001360 propertygroups=self.propertygroups,
Brad Bishop4b916f12017-05-23 18:06:38 -04001361 instances=self.instances,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001362 pathinstances=self.pathinstances,
Brad Bishop4b916f12017-05-23 18:06:38 -04001363 watches=self.watches,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001364 pathwatches=self.pathwatches,
Brad Bishop4b916f12017-05-23 18:06:38 -04001365 instancegroups=self.instancegroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001366 pathinstancegroups=self.pathinstancegroups,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001367 callbacks=self.callbacks,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001368 pathcallbacks=self.pathcallbacks,
Brad Bishop49e66172017-05-23 19:16:21 -04001369 callbackgroups=self.callbackgroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001370 pathcallbackgroups=self.pathcallbackgroups,
Brad Bishop4041d722017-05-21 10:06:07 -04001371 conditions=self.conditions,
Matthew Barthefe01582019-09-09 15:22:37 -05001372 filters=self.filters,
Brad Bishop34a7acd2017-04-27 23:47:23 -04001373 indent=Indent()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001374
1375if __name__ == '__main__':
Brad Bishop34a7acd2017-04-27 23:47:23 -04001376 script_dir = os.path.dirname(os.path.realpath(__file__))
1377 valid_commands = {
1378 'generate-cpp': 'generate_cpp',
1379 }
1380
1381 parser = ArgumentParser(
1382 description='Phosphor DBus Monitor (PDM) YAML '
1383 'scanner and code generator.')
1384
Matthew Barthdb440d42017-04-17 15:49:37 -05001385 parser.add_argument(
Brad Bishope3a01af2017-05-15 17:09:04 -04001386 "-o", "--out", dest="output",
1387 default='generated.cpp',
1388 help="Generated output file name and path.")
1389 parser.add_argument(
1390 '-t', '--template', dest='template',
Brad Bishop870c3fc2017-05-22 23:23:13 -04001391 default='generated.mako.hpp',
Brad Bishope3a01af2017-05-15 17:09:04 -04001392 help='The top level template to render.')
1393 parser.add_argument(
1394 '-p', '--template-path', dest='template_search',
1395 default=script_dir,
1396 help='The space delimited mako template search path.')
Brad Bishop34a7acd2017-04-27 23:47:23 -04001397 parser.add_argument(
1398 '-d', '--dir', dest='inputdir',
1399 default=os.path.join(script_dir, 'example'),
1400 help='Location of files to process.')
1401 parser.add_argument(
1402 'command', metavar='COMMAND', type=str,
1403 choices=valid_commands.keys(),
1404 help='%s.' % " | ".join(valid_commands.keys()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001405
Brad Bishop34a7acd2017-04-27 23:47:23 -04001406 args = parser.parse_args()
1407
1408 if sys.version_info < (3, 0):
1409 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001410 directories=args.template_search.split(),
Brad Bishop34a7acd2017-04-27 23:47:23 -04001411 disable_unicode=True)
1412 else:
1413 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001414 directories=args.template_search.split())
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001415 try:
1416 function = getattr(
1417 Everything.load(args),
1418 valid_commands[args.command])
1419 function(lookup)
1420 except InvalidConfigError as e:
1421 sys.stdout.write('{0}: {1}\n\n'.format(e.config, e.msg))
1422 raise