blob: 925dd218f133da3aa9c9d0f360a81ad56b22fe48 [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)
Lei YU98d64622022-05-24 19:11:23 +0800679 self.ignore_start_callback = kw.pop('ignore_start_callback', False)
680 self.ignore_start_callback = 'true' if self.ignore_start_callback else 'false'
Brad Bishop4b916f12017-05-23 18:06:38 -0400681 super(PropertyWatch, self).__init__(**kw)
682
Matthew Barthefe01582019-09-09 15:22:37 -0500683 def factory(self, objs):
684 '''Create any filters for this property watch.'''
685
686 if self.filters:
687 # Get the datatype(i.e. "int64_t") of the properties in this watch
688 # (Made available after all `super` classes init'd)
689 datatype = objs['propertygroup'][get_index(
690 objs,
691 'propertygroup',
692 self.properties,
693 config=self.configfile)].datatype
694 # Get the type(i.e. "int64") of the properties in this watch
695 # (Made available after all `super` classes init'd)
696 type = objs['propertygroup'][get_index(
697 objs,
698 'propertygroup',
699 self.properties,
700 config=self.configfile)].type
701 # Construct the data needed to make the filters for
702 # this watch available.
703 # *Note: 'class', 'subclass', 'name' are required for
704 # storing the filter data(i.e. 'type', 'datatype', & 'filters')
705 args = {
706 'type': type,
707 'datatype': datatype,
708 'filters': self.filters,
709 'class': 'filtersgroup',
710 'filtersgroup': 'filters',
711 'name': self.name,
712 }
713 # Init GroupOfFilters class with this watch's filters' arguments
714 group = GroupOfFilters(configfile=self.configfile, **args)
715 # Store this group of filters so it can be indexed later
716 add_unique(group, objs, config=self.configfile)
717 group.factory(objs)
718
719 super(PropertyWatch, self).factory(objs)
720
Brad Bishopfccdc392017-05-22 21:11:09 -0400721 def setup(self, objs):
Matthew Barthefe01582019-09-09 15:22:37 -0500722 '''Resolve optional filters and callback.'''
723
724 if self.filters:
725 # Watch has filters, provide array index to access them
726 self.filters = get_index(
727 objs,
728 'filtersgroup',
729 self.name,
730 config=self.configfile)
Brad Bishopfccdc392017-05-22 21:11:09 -0400731
732 if self.callback:
733 self.callback = get_index(
734 objs,
735 'callback',
736 self.callback,
737 config=self.configfile)
738
739 super(PropertyWatch, self).setup(objs)
740
Marri Devender Rao80c70612018-04-12 09:22:55 -0500741class PathWatch(HasPathIndex):
742 '''Handle the path watch config file directive.'''
743
744 def __init__(self, *a, **kw):
745 self.pathcallback = kw.pop('pathcallback', None)
746 super(PathWatch, self).__init__(**kw)
747
748 def setup(self, objs):
749 '''Resolve optional callback.'''
750 if self.pathcallback:
751 self.pathcallback = get_index(
752 objs,
753 'pathcallback',
754 self.pathcallback,
755 config=self.configfile)
756 super(PathWatch, self).setup(objs)
757
Brad Bishopc1283ae2017-05-20 21:42:38 -0400758class Callback(HasPropertyIndex):
759 '''Interface and common logic for callbacks.'''
760
761 def __init__(self, *a, **kw):
762 super(Callback, self).__init__(**kw)
763
Marri Devender Rao80c70612018-04-12 09:22:55 -0500764class PathCallback(HasPathIndex):
765 '''Interface and common logic for callbacks.'''
766
767 def __init__(self, *a, **kw):
768 super(PathCallback, self).__init__(**kw)
Brad Bishopc1283ae2017-05-20 21:42:38 -0400769
Brad Bishop4041d722017-05-21 10:06:07 -0400770class ConditionCallback(ConfigEntry, Renderer):
771 '''Handle the journal callback config file directive.'''
772
773 def __init__(self, *a, **kw):
774 self.condition = kw.pop('condition')
775 self.instance = kw.pop('instance')
Brad Bishop3539db62017-05-30 14:21:12 -0400776 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400777 super(ConditionCallback, self).__init__(**kw)
778
779 def factory(self, objs):
780 '''Create a graph instance for this callback.'''
781
782 args = {
783 'configfile': self.configfile,
784 'members': [self.instance],
785 'class': 'callbackgroup',
786 'callbackgroup': 'callback',
787 'name': [self.instance]
788 }
789
790 entry = CallbackGraphEntry(**args)
791 add_unique(entry, objs, config=self.configfile)
792
793 super(ConditionCallback, self).factory(objs)
794
795 def setup(self, objs):
796 '''Resolve condition and graph entry.'''
797
798 self.graph = get_index(
799 objs,
800 'callbackgroup',
801 [self.instance],
802 config=self.configfile)
803
804 self.condition = get_index(
805 objs,
806 'condition',
807 self.name,
808 config=self.configfile)
809
810 super(ConditionCallback, self).setup(objs)
811
812 def construct(self, loader, indent):
813 return self.render(
814 loader,
815 'conditional.mako.cpp',
816 c=self,
817 indent=indent)
818
819
820class Condition(HasPropertyIndex):
821 '''Interface and common logic for conditions.'''
822
823 def __init__(self, *a, **kw):
824 self.callback = kw.pop('callback')
Brad Bishop3539db62017-05-30 14:21:12 -0400825 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400826 super(Condition, self).__init__(**kw)
827
828 def factory(self, objs):
829 '''Create a callback instance for this conditional.'''
830
831 args = {
832 'configfile': self.configfile,
833 'condition': self.name,
834 'class': 'callback',
835 'callback': 'conditional',
836 'instance': self.callback,
837 'name': self.name,
Brad Bishop3539db62017-05-30 14:21:12 -0400838 'defer': self.defer
Brad Bishop4041d722017-05-21 10:06:07 -0400839 }
840
841 callback = ConditionCallback(**args)
842 add_unique(callback, objs, config=self.configfile)
843 callback.factory(objs)
844
845 super(Condition, self).factory(objs)
846
847
848class CountCondition(Condition, Renderer):
849 '''Handle the count condition config file directive.'''
850
851 def __init__(self, *a, **kw):
852 self.countop = kw.pop('countop')
853 self.countbound = kw.pop('countbound')
854 self.op = kw.pop('op')
855 self.bound = kw.pop('bound')
Matt Spinlerc458dee2018-02-19 13:09:10 -0600856 self.oneshot = TrivialArgument(
857 type='boolean',
858 value=kw.pop('oneshot', False))
Brad Bishop4041d722017-05-21 10:06:07 -0400859 super(CountCondition, self).__init__(**kw)
860
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400861 def setup(self, objs):
862 '''Resolve type.'''
863
864 super(CountCondition, self).setup(objs)
865 self.bound = TrivialArgument(
866 type=self.type,
867 value=self.bound)
868
Brad Bishop4041d722017-05-21 10:06:07 -0400869 def construct(self, loader, indent):
870 return self.render(
871 loader,
872 'count.mako.cpp',
873 c=self,
874 indent=indent)
875
876
Matthew Barthefdd03c2019-09-04 15:44:35 -0500877class MedianCondition(Condition, Renderer):
878 '''Handle the median condition config file directive.'''
879
880 def __init__(self, *a, **kw):
881 self.op = kw.pop('op')
882 self.bound = kw.pop('bound')
883 self.oneshot = TrivialArgument(
884 type='boolean',
885 value=kw.pop('oneshot', False))
886 super(MedianCondition, self).__init__(**kw)
887
888 def setup(self, objs):
889 '''Resolve type.'''
890
891 super(MedianCondition, self).setup(objs)
892 self.bound = TrivialArgument(
893 type=self.type,
894 value=self.bound)
895
896 def construct(self, loader, indent):
897 return self.render(
898 loader,
899 'median.mako.cpp',
900 c=self,
901 indent=indent)
902
903
Brad Bishopc1283ae2017-05-20 21:42:38 -0400904class Journal(Callback, Renderer):
905 '''Handle the journal callback config file directive.'''
906
907 def __init__(self, *a, **kw):
908 self.severity = kw.pop('severity')
909 self.message = kw.pop('message')
910 super(Journal, self).__init__(**kw)
911
912 def construct(self, loader, indent):
913 return self.render(
914 loader,
915 'journal.mako.cpp',
916 c=self,
917 indent=indent)
918
919
Gunnar Millsd5faea32017-08-08 14:19:36 -0500920class Elog(Callback, Renderer):
921 '''Handle the elog callback config file directive.'''
922
923 def __init__(self, *a, **kw):
924 self.error = kw.pop('error')
Gunnar Mills30474cf2017-08-11 09:38:54 -0500925 self.metadata = [Metadata(**x) for x in kw.pop('metadata', {})]
Gunnar Millsd5faea32017-08-08 14:19:36 -0500926 super(Elog, self).__init__(**kw)
927
928 def construct(self, loader, indent):
Gunnar Millsd5faea32017-08-08 14:19:36 -0500929 with open('errors.hpp', 'a') as fd:
930 fd.write(
931 self.render(
932 loader,
933 'errors.mako.hpp',
934 c=self))
935 return self.render(
936 loader,
937 'elog.mako.cpp',
938 c=self,
939 indent=indent)
940
Ratan Gupta90bfaea2017-10-06 20:56:31 +0530941class Event(Callback, Renderer):
942 '''Handle the event callback config file directive.'''
943
944 def __init__(self, *a, **kw):
945 self.eventName = kw.pop('eventName')
946 self.eventMessage = kw.pop('eventMessage')
947 super(Event, self).__init__(**kw)
948
949 def construct(self, loader, indent):
950 return self.render(
951 loader,
952 'event.mako.cpp',
953 c=self,
954 indent=indent)
Gunnar Millsd5faea32017-08-08 14:19:36 -0500955
Marri Devender Rao80c70612018-04-12 09:22:55 -0500956class EventPath(PathCallback, Renderer):
957 '''Handle the event path callback config file directive.'''
958
959 def __init__(self, *a, **kw):
960 self.eventType = kw.pop('eventType')
961 super(EventPath, self).__init__(**kw)
962
963 def construct(self, loader, indent):
964 return self.render(
965 loader,
966 'eventpath.mako.cpp',
967 c=self,
968 indent=indent)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600969
970class ElogWithMetadata(Callback, Renderer):
971 '''Handle the elog_with_metadata callback config file directive.'''
972
973 def __init__(self, *a, **kw):
974 self.error = kw.pop('error')
975 self.metadata = kw.pop('metadata')
976 super(ElogWithMetadata, self).__init__(**kw)
977
978 def construct(self, loader, indent):
979 with open('errors.hpp', 'a') as fd:
980 fd.write(
981 self.render(
982 loader,
983 'errors.mako.hpp',
984 c=self))
985 return self.render(
986 loader,
987 'elog_with_metadata.mako.cpp',
988 c=self,
989 indent=indent)
990
991
Matt Spinler1d6ca482017-11-01 10:48:02 -0500992class ResolveCallout(Callback, Renderer):
993 '''Handle the 'resolve callout' callback config file directive.'''
994
995 def __init__(self, *a, **kw):
996 self.callout = kw.pop('callout')
997 super(ResolveCallout, self).__init__(**kw)
998
999 def construct(self, loader, indent):
1000 return self.render(
1001 loader,
1002 'resolve_errors.mako.cpp',
1003 c=self,
1004 indent=indent)
1005
1006
Brad Bishop0df00be2017-05-25 23:38:37 -04001007class Method(ConfigEntry, Renderer):
1008 '''Handle the method callback config file directive.'''
1009
1010 def __init__(self, *a, **kw):
1011 self.service = kw.pop('service')
1012 self.path = kw.pop('path')
1013 self.interface = kw.pop('interface')
1014 self.method = kw.pop('method')
1015 self.args = [TrivialArgument(**x) for x in kw.pop('args', {})]
1016 super(Method, self).__init__(**kw)
1017
1018 def factory(self, objs):
1019 args = {
1020 'class': 'interface',
1021 'interface': 'element',
1022 'name': self.service
1023 }
1024 add_unique(ConfigEntry(
1025 configfile=self.configfile, **args), objs)
1026
1027 args = {
1028 'class': 'pathname',
1029 'pathname': 'element',
1030 'name': self.path
1031 }
1032 add_unique(ConfigEntry(
1033 configfile=self.configfile, **args), objs)
1034
1035 args = {
1036 'class': 'interface',
1037 'interface': 'element',
1038 'name': self.interface
1039 }
1040 add_unique(ConfigEntry(
1041 configfile=self.configfile, **args), objs)
1042
1043 args = {
1044 'class': 'propertyname',
1045 'propertyname': 'element',
1046 'name': self.method
1047 }
1048 add_unique(ConfigEntry(
1049 configfile=self.configfile, **args), objs)
1050
1051 super(Method, self).factory(objs)
1052
1053 def setup(self, objs):
1054 '''Resolve elements.'''
1055
1056 self.service = get_index(
1057 objs,
1058 'interface',
1059 self.service)
1060
1061 self.path = get_index(
1062 objs,
1063 'pathname',
1064 self.path)
1065
1066 self.interface = get_index(
1067 objs,
1068 'interface',
1069 self.interface)
1070
1071 self.method = get_index(
1072 objs,
1073 'propertyname',
1074 self.method)
1075
1076 super(Method, self).setup(objs)
1077
1078 def construct(self, loader, indent):
1079 return self.render(
1080 loader,
1081 'method.mako.cpp',
1082 c=self,
1083 indent=indent)
1084
1085
Brad Bishop49e66172017-05-23 19:16:21 -04001086class CallbackGraphEntry(Group):
1087 '''An entry in a traversal list for groups of callbacks.'''
1088
1089 def __init__(self, *a, **kw):
1090 super(CallbackGraphEntry, self).__init__(**kw)
1091
1092 def setup(self, objs):
1093 '''Resolve group members.'''
1094
1095 def map_member(x):
1096 return get_index(
1097 objs, 'callback', x, config=self.configfile)
1098
1099 self.members = map(
1100 map_member,
1101 self.members)
1102
1103 super(CallbackGraphEntry, self).setup(objs)
1104
Marri Devender Rao80c70612018-04-12 09:22:55 -05001105class PathCallbackGraphEntry(Group):
1106 '''An entry in a traversal list for groups of callbacks.'''
1107
1108 def __init__(self, *a, **kw):
1109 super(PathCallbackGraphEntry, self).__init__(**kw)
1110
1111 def setup(self, objs):
1112 '''Resolve group members.'''
1113
1114 def map_member(x):
1115 return get_index(
1116 objs, 'pathcallback', x, config=self.configfile)
1117
1118 self.members = map(
1119 map_member,
1120 self.members)
1121
1122 super(PathCallbackGraphEntry, self).setup(objs)
Brad Bishop49e66172017-05-23 19:16:21 -04001123
1124class GroupOfCallbacks(ConfigEntry, Renderer):
1125 '''Handle the callback group config file directive.'''
1126
1127 def __init__(self, *a, **kw):
1128 self.members = kw.pop('members')
1129 super(GroupOfCallbacks, self).__init__(**kw)
1130
1131 def factory(self, objs):
1132 '''Create a graph instance for this group of callbacks.'''
1133
1134 args = {
1135 'configfile': self.configfile,
1136 'members': self.members,
1137 'class': 'callbackgroup',
1138 'callbackgroup': 'callback',
1139 'name': self.members
1140 }
1141
1142 entry = CallbackGraphEntry(**args)
1143 add_unique(entry, objs, config=self.configfile)
1144
1145 super(GroupOfCallbacks, self).factory(objs)
1146
1147 def setup(self, objs):
1148 '''Resolve graph entry.'''
1149
1150 self.graph = get_index(
1151 objs, 'callbackgroup', self.members, config=self.configfile)
1152
1153 super(GroupOfCallbacks, self).setup(objs)
1154
1155 def construct(self, loader, indent):
1156 return self.render(
1157 loader,
1158 'callbackgroup.mako.cpp',
1159 c=self,
1160 indent=indent)
1161
Marri Devender Rao80c70612018-04-12 09:22:55 -05001162class GroupOfPathCallbacks(ConfigEntry, Renderer):
1163 '''Handle the callback group config file directive.'''
1164
1165 def __init__(self, *a, **kw):
1166 self.members = kw.pop('members')
1167 super(GroupOfPathCallbacks, self).__init__(**kw)
1168
1169 def factory(self, objs):
1170 '''Create a graph instance for this group of callbacks.'''
1171
1172 args = {
1173 'configfile': self.configfile,
1174 'members': self.members,
1175 'class': 'pathcallbackgroup',
1176 'pathcallbackgroup': 'pathcallback',
1177 'name': self.members
1178 }
1179
1180 entry = PathCallbackGraphEntry(**args)
1181 add_unique(entry, objs, config=self.configfile)
1182 super(GroupOfPathCallbacks, self).factory(objs)
1183
1184 def setup(self, objs):
1185 '''Resolve graph entry.'''
1186
1187 self.graph = get_index(
1188 objs, 'callbackpathgroup', self.members, config=self.configfile)
1189
1190 super(GroupOfPathCallbacks, self).setup(objs)
1191
1192 def construct(self, loader, indent):
1193 return self.render(
1194 loader,
1195 'callbackpathgroup.mako.cpp',
1196 c=self,
1197 indent=indent)
Brad Bishop49e66172017-05-23 19:16:21 -04001198
Brad Bishop34a7acd2017-04-27 23:47:23 -04001199class Everything(Renderer):
1200 '''Parse/render entry point.'''
1201
1202 @staticmethod
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001203 def classmap(cls, sub=None):
1204 '''Map render item class and subclass entries to the appropriate
1205 handler methods.'''
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001206 class_map = {
Brad Bishop0e7df132017-05-23 17:58:12 -04001207 'path': {
1208 'element': Path,
1209 },
1210 'pathgroup': {
1211 'path': GroupOfPaths,
1212 },
Brad Bishope73b2c32017-05-23 18:01:54 -04001213 'propertygroup': {
1214 'property': GroupOfProperties,
1215 },
1216 'property': {
1217 'element': Property,
1218 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001219 'watch': {
1220 'property': PropertyWatch,
1221 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001222 'pathwatch': {
1223 'path': PathWatch,
1224 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001225 'instance': {
1226 'element': Instance,
1227 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001228 'pathinstance': {
1229 'element': PathInstance,
1230 },
Brad Bishopc1283ae2017-05-20 21:42:38 -04001231 'callback': {
1232 'journal': Journal,
Gunnar Millsd5faea32017-08-08 14:19:36 -05001233 'elog': Elog,
Matt Spinler3c5318d2018-02-19 14:03:05 -06001234 'elog_with_metadata': ElogWithMetadata,
Ratan Gupta90bfaea2017-10-06 20:56:31 +05301235 'event': Event,
Brad Bishop49e66172017-05-23 19:16:21 -04001236 'group': GroupOfCallbacks,
Brad Bishop0df00be2017-05-25 23:38:37 -04001237 'method': Method,
Matt Spinler1d6ca482017-11-01 10:48:02 -05001238 'resolve callout': ResolveCallout,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001239 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001240 'pathcallback': {
1241 'eventpath': EventPath,
1242 'grouppath': GroupOfPathCallbacks,
1243 },
Brad Bishop4041d722017-05-21 10:06:07 -04001244 'condition': {
1245 'count': CountCondition,
Matthew Barthefdd03c2019-09-04 15:44:35 -05001246 'median': MedianCondition,
Brad Bishop4041d722017-05-21 10:06:07 -04001247 },
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001248 }
1249
1250 if cls not in class_map:
1251 raise NotImplementedError('Unknown class: "{0}"'.format(cls))
1252 if sub not in class_map[cls]:
1253 raise NotImplementedError('Unknown {0} type: "{1}"'.format(
1254 cls, sub))
1255
1256 return class_map[cls][sub]
1257
1258 @staticmethod
1259 def load_one_yaml(path, fd, objs):
1260 '''Parse a single YAML file. Parsing occurs in three phases.
1261 In the first phase a factory method associated with each
1262 configuration file directive is invoked. These factory
1263 methods generate more factory methods. In the second
1264 phase the factory methods created in the first phase
1265 are invoked. In the last phase a callback is invoked on
1266 each object created in phase two. Typically the callback
1267 resolves references to other configuration file directives.'''
1268
1269 factory_objs = {}
1270 for x in yaml.safe_load(fd.read()) or {}:
1271
1272 # Create factory object for this config file directive.
1273 cls = x['class']
1274 sub = x.get(cls)
1275 if cls == 'group':
1276 cls = '{0}group'.format(sub)
1277
1278 factory = Everything.classmap(cls, sub)
1279 obj = factory(configfile=path, **x)
1280
1281 # For a given class of directive, validate the file
1282 # doesn't have any duplicate names (duplicates are
1283 # ok across config files).
1284 if exists(factory_objs, obj.cls, obj.name, config=path):
1285 raise NotUniqueError(path, cls, obj.name)
1286
1287 factory_objs.setdefault(cls, []).append(obj)
1288 objs.setdefault(cls, []).append(obj)
1289
1290 for cls, items in factory_objs.items():
1291 for obj in items:
1292 # Add objects for template consumption.
1293 obj.factory(objs)
1294
1295 @staticmethod
Brad Bishop34a7acd2017-04-27 23:47:23 -04001296 def load(args):
1297 '''Aggregate all the YAML in the input directory
1298 into a single aggregate.'''
1299
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001300 objs = {}
1301 yaml_files = filter(
1302 lambda x: x.endswith('.yaml'),
1303 os.listdir(args.inputdir))
Brad Bishop34a7acd2017-04-27 23:47:23 -04001304
Marri Devender Rao44fd7e82020-03-08 09:51:34 -05001305 for x in sorted(yaml_files):
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001306 path = os.path.join(args.inputdir, x)
1307 with open(path, 'r') as fd:
1308 Everything.load_one_yaml(path, fd, objs)
1309
1310 # Configuration file directives reference each other via
1311 # the name attribute; however, when rendered the reference
1312 # is just an array index.
1313 #
1314 # At this point all objects have been created but references
Gunnar Mills78199b42017-10-25 16:30:18 -05001315 # have not been resolved to array indices. Instruct objects
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001316 # to do that now.
1317 for cls, items in objs.items():
1318 for obj in items:
1319 obj.setup(objs)
1320
1321 return Everything(**objs)
Brad Bishop34a7acd2017-04-27 23:47:23 -04001322
1323 def __init__(self, *a, **kw):
Brad Bishop0e7df132017-05-23 17:58:12 -04001324 self.pathmeta = kw.pop('path', [])
1325 self.paths = kw.pop('pathname', [])
1326 self.meta = kw.pop('meta', [])
1327 self.pathgroups = kw.pop('pathgroup', [])
Brad Bishope73b2c32017-05-23 18:01:54 -04001328 self.interfaces = kw.pop('interface', [])
1329 self.properties = kw.pop('property', [])
1330 self.propertynames = kw.pop('propertyname', [])
1331 self.propertygroups = kw.pop('propertygroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001332 self.instances = kw.pop('instance', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001333 self.pathinstances = kw.pop('pathinstance', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001334 self.instancegroups = kw.pop('instancegroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001335 self.pathinstancegroups = kw.pop('pathinstancegroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001336 self.watches = kw.pop('watch', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001337 self.pathwatches = kw.pop('pathwatch', [])
Brad Bishopc1283ae2017-05-20 21:42:38 -04001338 self.callbacks = kw.pop('callback', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001339 self.pathcallbacks = kw.pop('pathcallback', [])
Brad Bishop49e66172017-05-23 19:16:21 -04001340 self.callbackgroups = kw.pop('callbackgroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001341 self.pathcallbackgroups = kw.pop('pathcallbackgroup', [])
Brad Bishop4041d722017-05-21 10:06:07 -04001342 self.conditions = kw.pop('condition', [])
Matthew Barthefe01582019-09-09 15:22:37 -05001343 self.filters = kw.pop('filtersgroup', [])
Brad Bishop0e7df132017-05-23 17:58:12 -04001344
Brad Bishop34a7acd2017-04-27 23:47:23 -04001345 super(Everything, self).__init__(**kw)
1346
1347 def generate_cpp(self, loader):
1348 '''Render the template with the provided data.'''
Gunnar Millsd5faea32017-08-08 14:19:36 -05001349 # errors.hpp is used by generated.hpp to included any error.hpp files
1350 open('errors.hpp', 'w+')
1351
Brad Bishope3a01af2017-05-15 17:09:04 -04001352 with open(args.output, 'w') as fd:
Brad Bishop34a7acd2017-04-27 23:47:23 -04001353 fd.write(
1354 self.render(
1355 loader,
Brad Bishope3a01af2017-05-15 17:09:04 -04001356 args.template,
Brad Bishop0e7df132017-05-23 17:58:12 -04001357 meta=self.meta,
Brad Bishope73b2c32017-05-23 18:01:54 -04001358 properties=self.properties,
1359 propertynames=self.propertynames,
1360 interfaces=self.interfaces,
Brad Bishop0e7df132017-05-23 17:58:12 -04001361 paths=self.paths,
1362 pathmeta=self.pathmeta,
1363 pathgroups=self.pathgroups,
Brad Bishope73b2c32017-05-23 18:01:54 -04001364 propertygroups=self.propertygroups,
Brad Bishop4b916f12017-05-23 18:06:38 -04001365 instances=self.instances,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001366 pathinstances=self.pathinstances,
Brad Bishop4b916f12017-05-23 18:06:38 -04001367 watches=self.watches,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001368 pathwatches=self.pathwatches,
Brad Bishop4b916f12017-05-23 18:06:38 -04001369 instancegroups=self.instancegroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001370 pathinstancegroups=self.pathinstancegroups,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001371 callbacks=self.callbacks,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001372 pathcallbacks=self.pathcallbacks,
Brad Bishop49e66172017-05-23 19:16:21 -04001373 callbackgroups=self.callbackgroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001374 pathcallbackgroups=self.pathcallbackgroups,
Brad Bishop4041d722017-05-21 10:06:07 -04001375 conditions=self.conditions,
Matthew Barthefe01582019-09-09 15:22:37 -05001376 filters=self.filters,
Brad Bishop34a7acd2017-04-27 23:47:23 -04001377 indent=Indent()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001378
1379if __name__ == '__main__':
Brad Bishop34a7acd2017-04-27 23:47:23 -04001380 script_dir = os.path.dirname(os.path.realpath(__file__))
1381 valid_commands = {
1382 'generate-cpp': 'generate_cpp',
1383 }
1384
1385 parser = ArgumentParser(
1386 description='Phosphor DBus Monitor (PDM) YAML '
1387 'scanner and code generator.')
1388
Matthew Barthdb440d42017-04-17 15:49:37 -05001389 parser.add_argument(
Brad Bishope3a01af2017-05-15 17:09:04 -04001390 "-o", "--out", dest="output",
1391 default='generated.cpp',
1392 help="Generated output file name and path.")
1393 parser.add_argument(
1394 '-t', '--template', dest='template',
Brad Bishop870c3fc2017-05-22 23:23:13 -04001395 default='generated.mako.hpp',
Brad Bishope3a01af2017-05-15 17:09:04 -04001396 help='The top level template to render.')
1397 parser.add_argument(
1398 '-p', '--template-path', dest='template_search',
1399 default=script_dir,
1400 help='The space delimited mako template search path.')
Brad Bishop34a7acd2017-04-27 23:47:23 -04001401 parser.add_argument(
1402 '-d', '--dir', dest='inputdir',
1403 default=os.path.join(script_dir, 'example'),
1404 help='Location of files to process.')
1405 parser.add_argument(
1406 'command', metavar='COMMAND', type=str,
1407 choices=valid_commands.keys(),
1408 help='%s.' % " | ".join(valid_commands.keys()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001409
Brad Bishop34a7acd2017-04-27 23:47:23 -04001410 args = parser.parse_args()
1411
1412 if sys.version_info < (3, 0):
1413 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001414 directories=args.template_search.split(),
Brad Bishop34a7acd2017-04-27 23:47:23 -04001415 disable_unicode=True)
1416 else:
1417 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001418 directories=args.template_search.split())
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001419 try:
1420 function = getattr(
1421 Everything.load(args),
1422 valid_commands[args.command])
1423 function(lookup)
1424 except InvalidConfigError as e:
1425 sys.stdout.write('{0}: {1}\n\n'.format(e.config, e.msg))
1426 raise