blob: 0f9a13bc7ebb9ba86ba70898df03fc04ee284c11 [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)
Harvey.Wuafa54c62022-03-30 18:56:36 +0800125 elif self.type == 'double':
126 return Cast('static', 'double'.format(self.type))(arg)
Brad Bishop01079892017-05-26 10:56:45 -0400127
128 if self.type == 'string':
129 return '{0}s'.format(arg)
130
131 return arg
132
133
134class FixBool(object):
135 '''Un-capitalize booleans.'''
136
137 def __call__(self, arg):
138 return '{0}'.format(arg.lower())
139
140
141class Quote(object):
142 '''Decorate an argument by quoting it.'''
143
144 def __call__(self, arg):
145 return '"{0}"'.format(arg)
146
147
148class Argument(NamedElement, Renderer):
Gunnar Mills06fdaff2018-04-08 16:28:18 -0500149 '''Define argument type interface.'''
Brad Bishop01079892017-05-26 10:56:45 -0400150
151 def __init__(self, **kw):
152 self.type = kw.pop('type', None)
153 super(Argument, self).__init__(**kw)
154
155 def argument(self, loader, indent):
156 raise NotImplementedError
157
158
159class TrivialArgument(Argument):
160 '''Non-array type arguments.'''
161
162 def __init__(self, **kw):
163 self.value = kw.pop('value')
164 self.decorators = kw.pop('decorators', [])
165 if kw.get('type', None):
166 self.decorators.insert(0, Literal(kw['type']))
167 if kw.get('type', None) == 'string':
168 self.decorators.insert(0, Quote())
169 if kw.get('type', None) == 'boolean':
170 self.decorators.insert(0, FixBool())
171
172 super(TrivialArgument, self).__init__(**kw)
173
174 def argument(self, loader, indent):
175 a = str(self.value)
176 for d in self.decorators:
177 a = d(a)
178
179 return a
180
Matt Spinler80e9b652017-11-02 14:21:04 -0500181
Gunnar Mills30474cf2017-08-11 09:38:54 -0500182class Metadata(Argument):
183 '''Metadata type arguments.'''
184
185 def __init__(self, **kw):
186 self.value = kw.pop('value')
187 self.decorators = kw.pop('decorators', [])
188 if kw.get('type', None) == 'string':
189 self.decorators.insert(0, Quote())
190
191 super(Metadata, self).__init__(**kw)
192
193 def argument(self, loader, indent):
194 a = str(self.value)
195 for d in self.decorators:
196 a = d(a)
197
198 return a
Brad Bishop01079892017-05-26 10:56:45 -0400199
Matt Spinler80e9b652017-11-02 14:21:04 -0500200
Matthew Barthae786ef2019-09-04 15:46:13 -0500201class OpArgument(Argument):
202 '''Operation type arguments.'''
203
204 def __init__(self, **kw):
205 self.op = kw.pop('op')
206 self.bound = kw.pop('bound')
207 self.decorators = kw.pop('decorators', [])
208 if kw.get('type', None):
209 self.decorators.insert(0, Literal(kw['type']))
210 if kw.get('type', None) == 'string':
211 self.decorators.insert(0, Quote())
212 if kw.get('type', None) == 'boolean':
213 self.decorators.insert(0, FixBool())
214
215 super(OpArgument, self).__init__(**kw)
216
217 def argument(self, loader, indent):
218 a = str(self.bound)
219 for d in self.decorators:
220 a = d(a)
221
222 return a
223
224
Brad Bishop34a7acd2017-04-27 23:47:23 -0400225class Indent(object):
226 '''Help templates be depth agnostic.'''
Matthew Barthdb440d42017-04-17 15:49:37 -0500227
Brad Bishop34a7acd2017-04-27 23:47:23 -0400228 def __init__(self, depth=0):
229 self.depth = depth
Matthew Barthdb440d42017-04-17 15:49:37 -0500230
Brad Bishop34a7acd2017-04-27 23:47:23 -0400231 def __add__(self, depth):
232 return Indent(self.depth + depth)
233
234 def __call__(self, depth):
235 '''Render an indent at the current depth plus depth.'''
236 return 4*' '*(depth + self.depth)
237
238
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400239class ConfigEntry(NamedElement):
240 '''Base interface for rendered items.'''
241
242 def __init__(self, *a, **kw):
243 '''Pop the configfile/class/subclass keywords.'''
244
245 self.configfile = kw.pop('configfile')
246 self.cls = kw.pop('class')
247 self.subclass = kw.pop(self.cls)
Patrick Williamscfdfa0d2021-09-20 18:32:17 -0500248
249 # TODO: NamedElement requires 'name' to be a string, but in many cases
250 # this script treats 'name' as a dict. Save the property off and
251 # insert it after ConfigEntry does its own thing to avoid
252 # exceptions. This should be refactored throughout the whole
253 # script to not overload 'name' as a dict.
254 name_save = kw.pop('name')
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400255 super(ConfigEntry, self).__init__(**kw)
Patrick Williamscfdfa0d2021-09-20 18:32:17 -0500256 self.name = name_save
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400257
258 def factory(self, objs):
259 ''' Optional factory interface for subclasses to add
260 additional items to be rendered.'''
261
262 pass
263
264 def setup(self, objs):
265 ''' Optional setup interface for subclasses, invoked
266 after all factory methods have been run.'''
267
268 pass
269
270
Brad Bishop0e7df132017-05-23 17:58:12 -0400271class Path(ConfigEntry):
272 '''Path/metadata association.'''
273
274 def __init__(self, *a, **kw):
275 super(Path, self).__init__(**kw)
276
Brad Bishopbabf3b72017-05-31 19:44:53 -0400277 if self.name['meta'].upper() != self.name['meta']:
278 raise InvalidConfigError(
279 self.configfile,
280 'Metadata tag "{0}" must be upper case.'.format(
281 self.name['meta']))
282
Brad Bishop0e7df132017-05-23 17:58:12 -0400283 def factory(self, objs):
284 '''Create path and metadata elements.'''
285
286 args = {
287 'class': 'pathname',
288 'pathname': 'element',
289 'name': self.name['path']
290 }
291 add_unique(ConfigEntry(
292 configfile=self.configfile, **args), objs)
293
294 args = {
295 'class': 'meta',
296 'meta': 'element',
297 'name': self.name['meta']
298 }
299 add_unique(ConfigEntry(
300 configfile=self.configfile, **args), objs)
301
302 super(Path, self).factory(objs)
303
304 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500305 '''Resolve path and metadata names to indices.'''
Brad Bishop0e7df132017-05-23 17:58:12 -0400306
307 self.path = get_index(
308 objs, 'pathname', self.name['path'])
309 self.meta = get_index(
310 objs, 'meta', self.name['meta'])
311
312 super(Path, self).setup(objs)
313
314
Brad Bishope73b2c32017-05-23 18:01:54 -0400315class Property(ConfigEntry):
316 '''Property/interface/metadata association.'''
317
318 def __init__(self, *a, **kw):
319 super(Property, self).__init__(**kw)
320
Brad Bishopbabf3b72017-05-31 19:44:53 -0400321 if self.name['meta'].upper() != self.name['meta']:
322 raise InvalidConfigError(
323 self.configfile,
324 'Metadata tag "{0}" must be upper case.'.format(
325 self.name['meta']))
326
Brad Bishope73b2c32017-05-23 18:01:54 -0400327 def factory(self, objs):
328 '''Create interface, property name and metadata elements.'''
329
330 args = {
331 'class': 'interface',
332 'interface': 'element',
333 'name': self.name['interface']
334 }
335 add_unique(ConfigEntry(
336 configfile=self.configfile, **args), objs)
337
338 args = {
339 'class': 'propertyname',
340 'propertyname': 'element',
341 'name': self.name['property']
342 }
343 add_unique(ConfigEntry(
344 configfile=self.configfile, **args), objs)
345
346 args = {
347 'class': 'meta',
348 'meta': 'element',
349 'name': self.name['meta']
350 }
351 add_unique(ConfigEntry(
352 configfile=self.configfile, **args), objs)
353
354 super(Property, self).factory(objs)
355
356 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500357 '''Resolve interface, property and metadata to indices.'''
Brad Bishope73b2c32017-05-23 18:01:54 -0400358
359 self.interface = get_index(
360 objs, 'interface', self.name['interface'])
361 self.prop = get_index(
362 objs, 'propertyname', self.name['property'])
363 self.meta = get_index(
364 objs, 'meta', self.name['meta'])
365
366 super(Property, self).setup(objs)
367
368
Brad Bishop4b916f12017-05-23 18:06:38 -0400369class Instance(ConfigEntry):
370 '''Property/Path association.'''
371
372 def __init__(self, *a, **kw):
373 super(Instance, self).__init__(**kw)
374
375 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500376 '''Resolve elements to indices.'''
Brad Bishop4b916f12017-05-23 18:06:38 -0400377
378 self.interface = get_index(
379 objs, 'interface', self.name['property']['interface'])
380 self.prop = get_index(
381 objs, 'propertyname', self.name['property']['property'])
382 self.propmeta = get_index(
383 objs, 'meta', self.name['property']['meta'])
384 self.path = get_index(
385 objs, 'pathname', self.name['path']['path'])
386 self.pathmeta = get_index(
387 objs, 'meta', self.name['path']['meta'])
388
389 super(Instance, self).setup(objs)
390
Marri Devender Rao80c70612018-04-12 09:22:55 -0500391class PathInstance(ConfigEntry):
392 '''Path association.'''
393
394 def __init__(self, *a, **kw):
395 super(PathInstance, self).__init__(**kw)
396
397 def setup(self, objs):
398 '''Resolve elements to indices.'''
399 self.path = self.name['path']['path']
400 self.pathmeta = self.name['path']['meta']
401 super(PathInstance, self).setup(objs)
Brad Bishop4b916f12017-05-23 18:06:38 -0400402
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400403class Group(ConfigEntry):
404 '''Pop the members keyword for groups.'''
405
406 def __init__(self, *a, **kw):
407 self.members = kw.pop('members')
408 super(Group, self).__init__(**kw)
409
410
411class ImplicitGroup(Group):
412 '''Provide a factory method for groups whose members are
413 not explicitly declared in the config files.'''
414
415 def __init__(self, *a, **kw):
416 super(ImplicitGroup, self).__init__(**kw)
417
418 def factory(self, objs):
419 '''Create group members.'''
420
421 factory = Everything.classmap(self.subclass, 'element')
422 for m in self.members:
423 args = {
424 'class': self.subclass,
425 self.subclass: 'element',
426 'name': m
427 }
428
429 obj = factory(configfile=self.configfile, **args)
430 add_unique(obj, objs)
431 obj.factory(objs)
432
433 super(ImplicitGroup, self).factory(objs)
434
435
Brad Bishop0e7df132017-05-23 17:58:12 -0400436class GroupOfPaths(ImplicitGroup):
437 '''Path group config file directive.'''
438
439 def __init__(self, *a, **kw):
440 super(GroupOfPaths, self).__init__(**kw)
441
442 def setup(self, objs):
443 '''Resolve group members.'''
444
445 def map_member(x):
446 path = get_index(
447 objs, 'pathname', x['path'])
448 meta = get_index(
449 objs, 'meta', x['meta'])
450 return (path, meta)
451
452 self.members = map(
453 map_member,
454 self.members)
455
456 super(GroupOfPaths, self).setup(objs)
457
458
Brad Bishope73b2c32017-05-23 18:01:54 -0400459class GroupOfProperties(ImplicitGroup):
460 '''Property group config file directive.'''
461
462 def __init__(self, *a, **kw):
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400463 self.type = kw.pop('type')
Brad Bishope73b2c32017-05-23 18:01:54 -0400464 self.datatype = sdbusplus.property.Property(
465 name=kw.get('name'),
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400466 type=self.type).cppTypeName
Brad Bishope73b2c32017-05-23 18:01:54 -0400467
468 super(GroupOfProperties, self).__init__(**kw)
469
470 def setup(self, objs):
471 '''Resolve group members.'''
472
473 def map_member(x):
474 iface = get_index(
475 objs, 'interface', x['interface'])
476 prop = get_index(
477 objs, 'propertyname', x['property'])
478 meta = get_index(
479 objs, 'meta', x['meta'])
480
481 return (iface, prop, meta)
482
483 self.members = map(
484 map_member,
485 self.members)
486
487 super(GroupOfProperties, self).setup(objs)
488
489
Brad Bishop4b916f12017-05-23 18:06:38 -0400490class GroupOfInstances(ImplicitGroup):
491 '''A group of property instances.'''
492
493 def __init__(self, *a, **kw):
494 super(GroupOfInstances, self).__init__(**kw)
495
496 def setup(self, objs):
497 '''Resolve group members.'''
498
499 def map_member(x):
500 path = get_index(objs, 'pathname', x['path']['path'])
501 pathmeta = get_index(objs, 'meta', x['path']['meta'])
502 interface = get_index(
503 objs, 'interface', x['property']['interface'])
504 prop = get_index(objs, 'propertyname', x['property']['property'])
505 propmeta = get_index(objs, 'meta', x['property']['meta'])
506 instance = get_index(objs, 'instance', x)
507
508 return (path, pathmeta, interface, prop, propmeta, instance)
509
510 self.members = map(
511 map_member,
512 self.members)
513
514 super(GroupOfInstances, self).setup(objs)
515
Marri Devender Rao80c70612018-04-12 09:22:55 -0500516class GroupOfPathInstances(ImplicitGroup):
517 '''A group of path instances.'''
518
519 def __init__(self, *a, **kw):
520 super(GroupOfPathInstances, self).__init__(**kw)
521
522 def setup(self, objs):
523 '''Resolve group members.'''
524
525 def map_member(x):
526 path = get_index(objs, 'pathname', x['path']['path'])
527 pathmeta = get_index(objs, 'meta', x['path']['meta'])
528 pathinstance = get_index(objs, 'pathinstance', x)
529 return (path, pathmeta, pathinstance)
530
531 self.members = map(
532 map_member,
533 self.members)
534
535 super(GroupOfPathInstances, self).setup(objs)
536
Brad Bishop4b916f12017-05-23 18:06:38 -0400537
538class HasPropertyIndex(ConfigEntry):
539 '''Handle config file directives that require an index to be
540 constructed.'''
541
542 def __init__(self, *a, **kw):
543 self.paths = kw.pop('paths')
544 self.properties = kw.pop('properties')
545 super(HasPropertyIndex, self).__init__(**kw)
546
547 def factory(self, objs):
548 '''Create a group of instances for this index.'''
549
550 members = []
551 path_group = get_index(
552 objs, 'pathgroup', self.paths, config=self.configfile)
553 property_group = get_index(
554 objs, 'propertygroup', self.properties, config=self.configfile)
555
556 for path in objs['pathgroup'][path_group].members:
557 for prop in objs['propertygroup'][property_group].members:
558 member = {
559 'path': path,
560 'property': prop,
561 }
562 members.append(member)
563
564 args = {
565 'members': members,
566 'class': 'instancegroup',
567 'instancegroup': 'instance',
568 'name': '{0} {1}'.format(self.paths, self.properties)
569 }
570
571 group = GroupOfInstances(configfile=self.configfile, **args)
572 add_unique(group, objs, config=self.configfile)
573 group.factory(objs)
574
575 super(HasPropertyIndex, self).factory(objs)
576
577 def setup(self, objs):
578 '''Resolve path, property, and instance groups.'''
579
580 self.instances = get_index(
581 objs,
582 'instancegroup',
583 '{0} {1}'.format(self.paths, self.properties),
584 config=self.configfile)
585 self.paths = get_index(
586 objs,
587 'pathgroup',
588 self.paths,
589 config=self.configfile)
590 self.properties = get_index(
591 objs,
592 'propertygroup',
593 self.properties,
594 config=self.configfile)
595 self.datatype = objs['propertygroup'][self.properties].datatype
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400596 self.type = objs['propertygroup'][self.properties].type
Brad Bishop4b916f12017-05-23 18:06:38 -0400597
598 super(HasPropertyIndex, self).setup(objs)
599
Marri Devender Rao80c70612018-04-12 09:22:55 -0500600class HasPathIndex(ConfigEntry):
601 '''Handle config file directives that require an index to be
602 constructed.'''
603
604 def __init__(self, *a, **kw):
605 self.paths = kw.pop('paths')
606 super(HasPathIndex, self).__init__(**kw)
607
608 def factory(self, objs):
609 '''Create a group of instances for this index.'''
610
611 members = []
612 path_group = get_index(
613 objs, 'pathgroup', self.paths, config=self.configfile)
614
615 for path in objs['pathgroup'][path_group].members:
616 member = {
617 'path': path,
618 }
619 members.append(member)
620
621 args = {
622 'members': members,
623 'class': 'pathinstancegroup',
624 'pathinstancegroup': 'pathinstance',
625 'name': '{0}'.format(self.paths)
626 }
627
628 group = GroupOfPathInstances(configfile=self.configfile, **args)
629 add_unique(group, objs, config=self.configfile)
630 group.factory(objs)
631
632 super(HasPathIndex, self).factory(objs)
633
634 def setup(self, objs):
635 '''Resolve path and instance groups.'''
636
637 self.pathinstances = get_index(
638 objs,
639 'pathinstancegroup',
640 '{0}'.format(self.paths),
641 config=self.configfile)
642 self.paths = get_index(
643 objs,
644 'pathgroup',
645 self.paths,
646 config=self.configfile)
647 super(HasPathIndex, self).setup(objs)
Brad Bishop4b916f12017-05-23 18:06:38 -0400648
Matthew Barthefe01582019-09-09 15:22:37 -0500649class GroupOfFilters(ConfigEntry):
650 '''Handle config file directives that require an index for filters.'''
651
652 def __init__(self, *a, **kw):
653 # Pop filters data for adding to the available filters array
654 self.type = kw.pop('type')
655 self.datatype = kw.pop('datatype', None)
656 self.filters = kw.pop('filters', None)
657
658 super(GroupOfFilters, self).__init__(**kw)
659
660 def factory(self, objs):
661 '''Modify filters to add the property value type and
662 make them of operation argument type.'''
663 if self.filters:
664 # 'type' used within OpArgument to generate filter
665 # argument values so add to each filter
666 for f in self.filters:
667 f['type'] = self.type
668 self.filters = [OpArgument(**x) for x in self.filters]
669
670 super(GroupOfFilters, self).factory(objs)
671
Brad Bishop4b916f12017-05-23 18:06:38 -0400672class PropertyWatch(HasPropertyIndex):
673 '''Handle the property watch config file directive.'''
674
675 def __init__(self, *a, **kw):
Matthew Barthefe01582019-09-09 15:22:37 -0500676 # Pop optional filters for the properties being watched
677 self.filters = kw.pop('filters', None)
Brad Bishopfccdc392017-05-22 21:11:09 -0400678 self.callback = kw.pop('callback', None)
Brad Bishop4b916f12017-05-23 18:06:38 -0400679 super(PropertyWatch, self).__init__(**kw)
680
Matthew Barthefe01582019-09-09 15:22:37 -0500681 def factory(self, objs):
682 '''Create any filters for this property watch.'''
683
684 if self.filters:
685 # Get the datatype(i.e. "int64_t") of the properties in this watch
686 # (Made available after all `super` classes init'd)
687 datatype = objs['propertygroup'][get_index(
688 objs,
689 'propertygroup',
690 self.properties,
691 config=self.configfile)].datatype
692 # Get the type(i.e. "int64") of the properties in this watch
693 # (Made available after all `super` classes init'd)
694 type = objs['propertygroup'][get_index(
695 objs,
696 'propertygroup',
697 self.properties,
698 config=self.configfile)].type
699 # Construct the data needed to make the filters for
700 # this watch available.
701 # *Note: 'class', 'subclass', 'name' are required for
702 # storing the filter data(i.e. 'type', 'datatype', & 'filters')
703 args = {
704 'type': type,
705 'datatype': datatype,
706 'filters': self.filters,
707 'class': 'filtersgroup',
708 'filtersgroup': 'filters',
709 'name': self.name,
710 }
711 # Init GroupOfFilters class with this watch's filters' arguments
712 group = GroupOfFilters(configfile=self.configfile, **args)
713 # Store this group of filters so it can be indexed later
714 add_unique(group, objs, config=self.configfile)
715 group.factory(objs)
716
717 super(PropertyWatch, self).factory(objs)
718
Brad Bishopfccdc392017-05-22 21:11:09 -0400719 def setup(self, objs):
Matthew Barthefe01582019-09-09 15:22:37 -0500720 '''Resolve optional filters and callback.'''
721
722 if self.filters:
723 # Watch has filters, provide array index to access them
724 self.filters = get_index(
725 objs,
726 'filtersgroup',
727 self.name,
728 config=self.configfile)
Brad Bishopfccdc392017-05-22 21:11:09 -0400729
730 if self.callback:
731 self.callback = get_index(
732 objs,
733 'callback',
734 self.callback,
735 config=self.configfile)
736
737 super(PropertyWatch, self).setup(objs)
738
Marri Devender Rao80c70612018-04-12 09:22:55 -0500739class PathWatch(HasPathIndex):
740 '''Handle the path watch config file directive.'''
741
742 def __init__(self, *a, **kw):
743 self.pathcallback = kw.pop('pathcallback', None)
744 super(PathWatch, self).__init__(**kw)
745
746 def setup(self, objs):
747 '''Resolve optional callback.'''
748 if self.pathcallback:
749 self.pathcallback = get_index(
750 objs,
751 'pathcallback',
752 self.pathcallback,
753 config=self.configfile)
754 super(PathWatch, self).setup(objs)
755
Brad Bishopc1283ae2017-05-20 21:42:38 -0400756class Callback(HasPropertyIndex):
757 '''Interface and common logic for callbacks.'''
758
759 def __init__(self, *a, **kw):
760 super(Callback, self).__init__(**kw)
761
Marri Devender Rao80c70612018-04-12 09:22:55 -0500762class PathCallback(HasPathIndex):
763 '''Interface and common logic for callbacks.'''
764
765 def __init__(self, *a, **kw):
766 super(PathCallback, self).__init__(**kw)
Brad Bishopc1283ae2017-05-20 21:42:38 -0400767
Brad Bishop4041d722017-05-21 10:06:07 -0400768class ConditionCallback(ConfigEntry, Renderer):
769 '''Handle the journal callback config file directive.'''
770
771 def __init__(self, *a, **kw):
772 self.condition = kw.pop('condition')
773 self.instance = kw.pop('instance')
Brad Bishop3539db62017-05-30 14:21:12 -0400774 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400775 super(ConditionCallback, self).__init__(**kw)
776
777 def factory(self, objs):
778 '''Create a graph instance for this callback.'''
779
780 args = {
781 'configfile': self.configfile,
782 'members': [self.instance],
783 'class': 'callbackgroup',
784 'callbackgroup': 'callback',
785 'name': [self.instance]
786 }
787
788 entry = CallbackGraphEntry(**args)
789 add_unique(entry, objs, config=self.configfile)
790
791 super(ConditionCallback, self).factory(objs)
792
793 def setup(self, objs):
794 '''Resolve condition and graph entry.'''
795
796 self.graph = get_index(
797 objs,
798 'callbackgroup',
799 [self.instance],
800 config=self.configfile)
801
802 self.condition = get_index(
803 objs,
804 'condition',
805 self.name,
806 config=self.configfile)
807
808 super(ConditionCallback, self).setup(objs)
809
810 def construct(self, loader, indent):
811 return self.render(
812 loader,
813 'conditional.mako.cpp',
814 c=self,
815 indent=indent)
816
817
818class Condition(HasPropertyIndex):
819 '''Interface and common logic for conditions.'''
820
821 def __init__(self, *a, **kw):
822 self.callback = kw.pop('callback')
Brad Bishop3539db62017-05-30 14:21:12 -0400823 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400824 super(Condition, self).__init__(**kw)
825
826 def factory(self, objs):
827 '''Create a callback instance for this conditional.'''
828
829 args = {
830 'configfile': self.configfile,
831 'condition': self.name,
832 'class': 'callback',
833 'callback': 'conditional',
834 'instance': self.callback,
835 'name': self.name,
Brad Bishop3539db62017-05-30 14:21:12 -0400836 'defer': self.defer
Brad Bishop4041d722017-05-21 10:06:07 -0400837 }
838
839 callback = ConditionCallback(**args)
840 add_unique(callback, objs, config=self.configfile)
841 callback.factory(objs)
842
843 super(Condition, self).factory(objs)
844
845
846class CountCondition(Condition, Renderer):
847 '''Handle the count condition config file directive.'''
848
849 def __init__(self, *a, **kw):
850 self.countop = kw.pop('countop')
851 self.countbound = kw.pop('countbound')
852 self.op = kw.pop('op')
853 self.bound = kw.pop('bound')
Matt Spinlerc458dee2018-02-19 13:09:10 -0600854 self.oneshot = TrivialArgument(
855 type='boolean',
856 value=kw.pop('oneshot', False))
Brad Bishop4041d722017-05-21 10:06:07 -0400857 super(CountCondition, self).__init__(**kw)
858
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400859 def setup(self, objs):
860 '''Resolve type.'''
861
862 super(CountCondition, self).setup(objs)
863 self.bound = TrivialArgument(
864 type=self.type,
865 value=self.bound)
866
Brad Bishop4041d722017-05-21 10:06:07 -0400867 def construct(self, loader, indent):
868 return self.render(
869 loader,
870 'count.mako.cpp',
871 c=self,
872 indent=indent)
873
874
Matthew Barthefdd03c2019-09-04 15:44:35 -0500875class MedianCondition(Condition, Renderer):
876 '''Handle the median condition config file directive.'''
877
878 def __init__(self, *a, **kw):
879 self.op = kw.pop('op')
880 self.bound = kw.pop('bound')
881 self.oneshot = TrivialArgument(
882 type='boolean',
883 value=kw.pop('oneshot', False))
884 super(MedianCondition, self).__init__(**kw)
885
886 def setup(self, objs):
887 '''Resolve type.'''
888
889 super(MedianCondition, self).setup(objs)
890 self.bound = TrivialArgument(
891 type=self.type,
892 value=self.bound)
893
894 def construct(self, loader, indent):
895 return self.render(
896 loader,
897 'median.mako.cpp',
898 c=self,
899 indent=indent)
900
901
Brad Bishopc1283ae2017-05-20 21:42:38 -0400902class Journal(Callback, Renderer):
903 '''Handle the journal callback config file directive.'''
904
905 def __init__(self, *a, **kw):
906 self.severity = kw.pop('severity')
907 self.message = kw.pop('message')
908 super(Journal, self).__init__(**kw)
909
910 def construct(self, loader, indent):
911 return self.render(
912 loader,
913 'journal.mako.cpp',
914 c=self,
915 indent=indent)
916
917
Gunnar Millsd5faea32017-08-08 14:19:36 -0500918class Elog(Callback, Renderer):
919 '''Handle the elog callback config file directive.'''
920
921 def __init__(self, *a, **kw):
922 self.error = kw.pop('error')
Gunnar Mills30474cf2017-08-11 09:38:54 -0500923 self.metadata = [Metadata(**x) for x in kw.pop('metadata', {})]
Gunnar Millsd5faea32017-08-08 14:19:36 -0500924 super(Elog, self).__init__(**kw)
925
926 def construct(self, loader, indent):
Gunnar Millsd5faea32017-08-08 14:19:36 -0500927 with open('errors.hpp', 'a') as fd:
928 fd.write(
929 self.render(
930 loader,
931 'errors.mako.hpp',
932 c=self))
933 return self.render(
934 loader,
935 'elog.mako.cpp',
936 c=self,
937 indent=indent)
938
Ratan Gupta90bfaea2017-10-06 20:56:31 +0530939class Event(Callback, Renderer):
940 '''Handle the event callback config file directive.'''
941
942 def __init__(self, *a, **kw):
943 self.eventName = kw.pop('eventName')
944 self.eventMessage = kw.pop('eventMessage')
945 super(Event, self).__init__(**kw)
946
947 def construct(self, loader, indent):
948 return self.render(
949 loader,
950 'event.mako.cpp',
951 c=self,
952 indent=indent)
Gunnar Millsd5faea32017-08-08 14:19:36 -0500953
Marri Devender Rao80c70612018-04-12 09:22:55 -0500954class EventPath(PathCallback, Renderer):
955 '''Handle the event path callback config file directive.'''
956
957 def __init__(self, *a, **kw):
958 self.eventType = kw.pop('eventType')
959 super(EventPath, self).__init__(**kw)
960
961 def construct(self, loader, indent):
962 return self.render(
963 loader,
964 'eventpath.mako.cpp',
965 c=self,
966 indent=indent)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600967
968class ElogWithMetadata(Callback, Renderer):
969 '''Handle the elog_with_metadata callback config file directive.'''
970
971 def __init__(self, *a, **kw):
972 self.error = kw.pop('error')
973 self.metadata = kw.pop('metadata')
974 super(ElogWithMetadata, self).__init__(**kw)
975
976 def construct(self, loader, indent):
977 with open('errors.hpp', 'a') as fd:
978 fd.write(
979 self.render(
980 loader,
981 'errors.mako.hpp',
982 c=self))
983 return self.render(
984 loader,
985 'elog_with_metadata.mako.cpp',
986 c=self,
987 indent=indent)
988
989
Matt Spinler1d6ca482017-11-01 10:48:02 -0500990class ResolveCallout(Callback, Renderer):
991 '''Handle the 'resolve callout' callback config file directive.'''
992
993 def __init__(self, *a, **kw):
994 self.callout = kw.pop('callout')
995 super(ResolveCallout, self).__init__(**kw)
996
997 def construct(self, loader, indent):
998 return self.render(
999 loader,
1000 'resolve_errors.mako.cpp',
1001 c=self,
1002 indent=indent)
1003
1004
Brad Bishop0df00be2017-05-25 23:38:37 -04001005class Method(ConfigEntry, Renderer):
1006 '''Handle the method callback config file directive.'''
1007
1008 def __init__(self, *a, **kw):
1009 self.service = kw.pop('service')
1010 self.path = kw.pop('path')
1011 self.interface = kw.pop('interface')
1012 self.method = kw.pop('method')
1013 self.args = [TrivialArgument(**x) for x in kw.pop('args', {})]
1014 super(Method, self).__init__(**kw)
1015
1016 def factory(self, objs):
1017 args = {
1018 'class': 'interface',
1019 'interface': 'element',
1020 'name': self.service
1021 }
1022 add_unique(ConfigEntry(
1023 configfile=self.configfile, **args), objs)
1024
1025 args = {
1026 'class': 'pathname',
1027 'pathname': 'element',
1028 'name': self.path
1029 }
1030 add_unique(ConfigEntry(
1031 configfile=self.configfile, **args), objs)
1032
1033 args = {
1034 'class': 'interface',
1035 'interface': 'element',
1036 'name': self.interface
1037 }
1038 add_unique(ConfigEntry(
1039 configfile=self.configfile, **args), objs)
1040
1041 args = {
1042 'class': 'propertyname',
1043 'propertyname': 'element',
1044 'name': self.method
1045 }
1046 add_unique(ConfigEntry(
1047 configfile=self.configfile, **args), objs)
1048
1049 super(Method, self).factory(objs)
1050
1051 def setup(self, objs):
1052 '''Resolve elements.'''
1053
1054 self.service = get_index(
1055 objs,
1056 'interface',
1057 self.service)
1058
1059 self.path = get_index(
1060 objs,
1061 'pathname',
1062 self.path)
1063
1064 self.interface = get_index(
1065 objs,
1066 'interface',
1067 self.interface)
1068
1069 self.method = get_index(
1070 objs,
1071 'propertyname',
1072 self.method)
1073
1074 super(Method, self).setup(objs)
1075
1076 def construct(self, loader, indent):
1077 return self.render(
1078 loader,
1079 'method.mako.cpp',
1080 c=self,
1081 indent=indent)
1082
1083
Brad Bishop49e66172017-05-23 19:16:21 -04001084class CallbackGraphEntry(Group):
1085 '''An entry in a traversal list for groups of callbacks.'''
1086
1087 def __init__(self, *a, **kw):
1088 super(CallbackGraphEntry, self).__init__(**kw)
1089
1090 def setup(self, objs):
1091 '''Resolve group members.'''
1092
1093 def map_member(x):
1094 return get_index(
1095 objs, 'callback', x, config=self.configfile)
1096
1097 self.members = map(
1098 map_member,
1099 self.members)
1100
1101 super(CallbackGraphEntry, self).setup(objs)
1102
Marri Devender Rao80c70612018-04-12 09:22:55 -05001103class PathCallbackGraphEntry(Group):
1104 '''An entry in a traversal list for groups of callbacks.'''
1105
1106 def __init__(self, *a, **kw):
1107 super(PathCallbackGraphEntry, self).__init__(**kw)
1108
1109 def setup(self, objs):
1110 '''Resolve group members.'''
1111
1112 def map_member(x):
1113 return get_index(
1114 objs, 'pathcallback', x, config=self.configfile)
1115
1116 self.members = map(
1117 map_member,
1118 self.members)
1119
1120 super(PathCallbackGraphEntry, self).setup(objs)
Brad Bishop49e66172017-05-23 19:16:21 -04001121
1122class GroupOfCallbacks(ConfigEntry, Renderer):
1123 '''Handle the callback group config file directive.'''
1124
1125 def __init__(self, *a, **kw):
1126 self.members = kw.pop('members')
1127 super(GroupOfCallbacks, self).__init__(**kw)
1128
1129 def factory(self, objs):
1130 '''Create a graph instance for this group of callbacks.'''
1131
1132 args = {
1133 'configfile': self.configfile,
1134 'members': self.members,
1135 'class': 'callbackgroup',
1136 'callbackgroup': 'callback',
1137 'name': self.members
1138 }
1139
1140 entry = CallbackGraphEntry(**args)
1141 add_unique(entry, objs, config=self.configfile)
1142
1143 super(GroupOfCallbacks, self).factory(objs)
1144
1145 def setup(self, objs):
1146 '''Resolve graph entry.'''
1147
1148 self.graph = get_index(
1149 objs, 'callbackgroup', self.members, config=self.configfile)
1150
1151 super(GroupOfCallbacks, self).setup(objs)
1152
1153 def construct(self, loader, indent):
1154 return self.render(
1155 loader,
1156 'callbackgroup.mako.cpp',
1157 c=self,
1158 indent=indent)
1159
Marri Devender Rao80c70612018-04-12 09:22:55 -05001160class GroupOfPathCallbacks(ConfigEntry, Renderer):
1161 '''Handle the callback group config file directive.'''
1162
1163 def __init__(self, *a, **kw):
1164 self.members = kw.pop('members')
1165 super(GroupOfPathCallbacks, self).__init__(**kw)
1166
1167 def factory(self, objs):
1168 '''Create a graph instance for this group of callbacks.'''
1169
1170 args = {
1171 'configfile': self.configfile,
1172 'members': self.members,
1173 'class': 'pathcallbackgroup',
1174 'pathcallbackgroup': 'pathcallback',
1175 'name': self.members
1176 }
1177
1178 entry = PathCallbackGraphEntry(**args)
1179 add_unique(entry, objs, config=self.configfile)
1180 super(GroupOfPathCallbacks, self).factory(objs)
1181
1182 def setup(self, objs):
1183 '''Resolve graph entry.'''
1184
1185 self.graph = get_index(
1186 objs, 'callbackpathgroup', self.members, config=self.configfile)
1187
1188 super(GroupOfPathCallbacks, self).setup(objs)
1189
1190 def construct(self, loader, indent):
1191 return self.render(
1192 loader,
1193 'callbackpathgroup.mako.cpp',
1194 c=self,
1195 indent=indent)
Brad Bishop49e66172017-05-23 19:16:21 -04001196
Brad Bishop34a7acd2017-04-27 23:47:23 -04001197class Everything(Renderer):
1198 '''Parse/render entry point.'''
1199
1200 @staticmethod
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001201 def classmap(cls, sub=None):
1202 '''Map render item class and subclass entries to the appropriate
1203 handler methods.'''
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001204 class_map = {
Brad Bishop0e7df132017-05-23 17:58:12 -04001205 'path': {
1206 'element': Path,
1207 },
1208 'pathgroup': {
1209 'path': GroupOfPaths,
1210 },
Brad Bishope73b2c32017-05-23 18:01:54 -04001211 'propertygroup': {
1212 'property': GroupOfProperties,
1213 },
1214 'property': {
1215 'element': Property,
1216 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001217 'watch': {
1218 'property': PropertyWatch,
1219 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001220 'pathwatch': {
1221 'path': PathWatch,
1222 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001223 'instance': {
1224 'element': Instance,
1225 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001226 'pathinstance': {
1227 'element': PathInstance,
1228 },
Brad Bishopc1283ae2017-05-20 21:42:38 -04001229 'callback': {
1230 'journal': Journal,
Gunnar Millsd5faea32017-08-08 14:19:36 -05001231 'elog': Elog,
Matt Spinler3c5318d2018-02-19 14:03:05 -06001232 'elog_with_metadata': ElogWithMetadata,
Ratan Gupta90bfaea2017-10-06 20:56:31 +05301233 'event': Event,
Brad Bishop49e66172017-05-23 19:16:21 -04001234 'group': GroupOfCallbacks,
Brad Bishop0df00be2017-05-25 23:38:37 -04001235 'method': Method,
Matt Spinler1d6ca482017-11-01 10:48:02 -05001236 'resolve callout': ResolveCallout,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001237 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001238 'pathcallback': {
1239 'eventpath': EventPath,
1240 'grouppath': GroupOfPathCallbacks,
1241 },
Brad Bishop4041d722017-05-21 10:06:07 -04001242 'condition': {
1243 'count': CountCondition,
Matthew Barthefdd03c2019-09-04 15:44:35 -05001244 'median': MedianCondition,
Brad Bishop4041d722017-05-21 10:06:07 -04001245 },
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001246 }
1247
1248 if cls not in class_map:
1249 raise NotImplementedError('Unknown class: "{0}"'.format(cls))
1250 if sub not in class_map[cls]:
1251 raise NotImplementedError('Unknown {0} type: "{1}"'.format(
1252 cls, sub))
1253
1254 return class_map[cls][sub]
1255
1256 @staticmethod
1257 def load_one_yaml(path, fd, objs):
1258 '''Parse a single YAML file. Parsing occurs in three phases.
1259 In the first phase a factory method associated with each
1260 configuration file directive is invoked. These factory
1261 methods generate more factory methods. In the second
1262 phase the factory methods created in the first phase
1263 are invoked. In the last phase a callback is invoked on
1264 each object created in phase two. Typically the callback
1265 resolves references to other configuration file directives.'''
1266
1267 factory_objs = {}
1268 for x in yaml.safe_load(fd.read()) or {}:
1269
1270 # Create factory object for this config file directive.
1271 cls = x['class']
1272 sub = x.get(cls)
1273 if cls == 'group':
1274 cls = '{0}group'.format(sub)
1275
1276 factory = Everything.classmap(cls, sub)
1277 obj = factory(configfile=path, **x)
1278
1279 # For a given class of directive, validate the file
1280 # doesn't have any duplicate names (duplicates are
1281 # ok across config files).
1282 if exists(factory_objs, obj.cls, obj.name, config=path):
1283 raise NotUniqueError(path, cls, obj.name)
1284
1285 factory_objs.setdefault(cls, []).append(obj)
1286 objs.setdefault(cls, []).append(obj)
1287
1288 for cls, items in factory_objs.items():
1289 for obj in items:
1290 # Add objects for template consumption.
1291 obj.factory(objs)
1292
1293 @staticmethod
Brad Bishop34a7acd2017-04-27 23:47:23 -04001294 def load(args):
1295 '''Aggregate all the YAML in the input directory
1296 into a single aggregate.'''
1297
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001298 objs = {}
1299 yaml_files = filter(
1300 lambda x: x.endswith('.yaml'),
1301 os.listdir(args.inputdir))
Brad Bishop34a7acd2017-04-27 23:47:23 -04001302
Marri Devender Rao44fd7e82020-03-08 09:51:34 -05001303 for x in sorted(yaml_files):
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001304 path = os.path.join(args.inputdir, x)
1305 with open(path, 'r') as fd:
1306 Everything.load_one_yaml(path, fd, objs)
1307
1308 # Configuration file directives reference each other via
1309 # the name attribute; however, when rendered the reference
1310 # is just an array index.
1311 #
1312 # At this point all objects have been created but references
Gunnar Mills78199b42017-10-25 16:30:18 -05001313 # have not been resolved to array indices. Instruct objects
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001314 # to do that now.
1315 for cls, items in objs.items():
1316 for obj in items:
1317 obj.setup(objs)
1318
1319 return Everything(**objs)
Brad Bishop34a7acd2017-04-27 23:47:23 -04001320
1321 def __init__(self, *a, **kw):
Brad Bishop0e7df132017-05-23 17:58:12 -04001322 self.pathmeta = kw.pop('path', [])
1323 self.paths = kw.pop('pathname', [])
1324 self.meta = kw.pop('meta', [])
1325 self.pathgroups = kw.pop('pathgroup', [])
Brad Bishope73b2c32017-05-23 18:01:54 -04001326 self.interfaces = kw.pop('interface', [])
1327 self.properties = kw.pop('property', [])
1328 self.propertynames = kw.pop('propertyname', [])
1329 self.propertygroups = kw.pop('propertygroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001330 self.instances = kw.pop('instance', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001331 self.pathinstances = kw.pop('pathinstance', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001332 self.instancegroups = kw.pop('instancegroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001333 self.pathinstancegroups = kw.pop('pathinstancegroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001334 self.watches = kw.pop('watch', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001335 self.pathwatches = kw.pop('pathwatch', [])
Brad Bishopc1283ae2017-05-20 21:42:38 -04001336 self.callbacks = kw.pop('callback', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001337 self.pathcallbacks = kw.pop('pathcallback', [])
Brad Bishop49e66172017-05-23 19:16:21 -04001338 self.callbackgroups = kw.pop('callbackgroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001339 self.pathcallbackgroups = kw.pop('pathcallbackgroup', [])
Brad Bishop4041d722017-05-21 10:06:07 -04001340 self.conditions = kw.pop('condition', [])
Matthew Barthefe01582019-09-09 15:22:37 -05001341 self.filters = kw.pop('filtersgroup', [])
Brad Bishop0e7df132017-05-23 17:58:12 -04001342
Brad Bishop34a7acd2017-04-27 23:47:23 -04001343 super(Everything, self).__init__(**kw)
1344
1345 def generate_cpp(self, loader):
1346 '''Render the template with the provided data.'''
Gunnar Millsd5faea32017-08-08 14:19:36 -05001347 # errors.hpp is used by generated.hpp to included any error.hpp files
1348 open('errors.hpp', 'w+')
1349
Brad Bishope3a01af2017-05-15 17:09:04 -04001350 with open(args.output, 'w') as fd:
Brad Bishop34a7acd2017-04-27 23:47:23 -04001351 fd.write(
1352 self.render(
1353 loader,
Brad Bishope3a01af2017-05-15 17:09:04 -04001354 args.template,
Brad Bishop0e7df132017-05-23 17:58:12 -04001355 meta=self.meta,
Brad Bishope73b2c32017-05-23 18:01:54 -04001356 properties=self.properties,
1357 propertynames=self.propertynames,
1358 interfaces=self.interfaces,
Brad Bishop0e7df132017-05-23 17:58:12 -04001359 paths=self.paths,
1360 pathmeta=self.pathmeta,
1361 pathgroups=self.pathgroups,
Brad Bishope73b2c32017-05-23 18:01:54 -04001362 propertygroups=self.propertygroups,
Brad Bishop4b916f12017-05-23 18:06:38 -04001363 instances=self.instances,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001364 pathinstances=self.pathinstances,
Brad Bishop4b916f12017-05-23 18:06:38 -04001365 watches=self.watches,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001366 pathwatches=self.pathwatches,
Brad Bishop4b916f12017-05-23 18:06:38 -04001367 instancegroups=self.instancegroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001368 pathinstancegroups=self.pathinstancegroups,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001369 callbacks=self.callbacks,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001370 pathcallbacks=self.pathcallbacks,
Brad Bishop49e66172017-05-23 19:16:21 -04001371 callbackgroups=self.callbackgroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001372 pathcallbackgroups=self.pathcallbackgroups,
Brad Bishop4041d722017-05-21 10:06:07 -04001373 conditions=self.conditions,
Matthew Barthefe01582019-09-09 15:22:37 -05001374 filters=self.filters,
Brad Bishop34a7acd2017-04-27 23:47:23 -04001375 indent=Indent()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001376
1377if __name__ == '__main__':
Brad Bishop34a7acd2017-04-27 23:47:23 -04001378 script_dir = os.path.dirname(os.path.realpath(__file__))
1379 valid_commands = {
1380 'generate-cpp': 'generate_cpp',
1381 }
1382
1383 parser = ArgumentParser(
1384 description='Phosphor DBus Monitor (PDM) YAML '
1385 'scanner and code generator.')
1386
Matthew Barthdb440d42017-04-17 15:49:37 -05001387 parser.add_argument(
Brad Bishope3a01af2017-05-15 17:09:04 -04001388 "-o", "--out", dest="output",
1389 default='generated.cpp',
1390 help="Generated output file name and path.")
1391 parser.add_argument(
1392 '-t', '--template', dest='template',
Brad Bishop870c3fc2017-05-22 23:23:13 -04001393 default='generated.mako.hpp',
Brad Bishope3a01af2017-05-15 17:09:04 -04001394 help='The top level template to render.')
1395 parser.add_argument(
1396 '-p', '--template-path', dest='template_search',
1397 default=script_dir,
1398 help='The space delimited mako template search path.')
Brad Bishop34a7acd2017-04-27 23:47:23 -04001399 parser.add_argument(
1400 '-d', '--dir', dest='inputdir',
1401 default=os.path.join(script_dir, 'example'),
1402 help='Location of files to process.')
1403 parser.add_argument(
1404 'command', metavar='COMMAND', type=str,
1405 choices=valid_commands.keys(),
1406 help='%s.' % " | ".join(valid_commands.keys()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001407
Brad Bishop34a7acd2017-04-27 23:47:23 -04001408 args = parser.parse_args()
1409
1410 if sys.version_info < (3, 0):
1411 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001412 directories=args.template_search.split(),
Brad Bishop34a7acd2017-04-27 23:47:23 -04001413 disable_unicode=True)
1414 else:
1415 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001416 directories=args.template_search.split())
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001417 try:
1418 function = getattr(
1419 Everything.load(args),
1420 valid_commands[args.command])
1421 function(lookup)
1422 except InvalidConfigError as e:
1423 sys.stdout.write('{0}: {1}\n\n'.format(e.config, e.msg))
1424 raise