blob: ef1b7900892d5e20e35e24d8f3554663b82a620a [file] [log] [blame]
Matthew Barthdb440d42017-04-17 15:49:37 -05001#!/usr/bin/env python
2
Brad Bishop34a7acd2017-04-27 23:47:23 -04003'''Phosphor DBus Monitor YAML parser and code generator.
4
5The parser workflow is broken down as follows:
6 1 - Import YAML files as native python type(s) instance(s).
7 2 - Create an instance of the Everything class from the
8 native python type instance(s) with the Everything.load
9 method.
10 3 - The Everything class constructor orchestrates conversion of the
11 native python type(s) instances(s) to render helper types.
12 Each render helper type constructor imports its attributes
13 from the native python type(s) instances(s).
14 4 - Present the converted YAML to the command processing method
15 requested by the script user.
16'''
17
Matthew Barthdb440d42017-04-17 15:49:37 -050018import os
19import sys
20import yaml
Brad Bishop34a7acd2017-04-27 23:47:23 -040021import mako.lookup
Matthew Barthdb440d42017-04-17 15:49:37 -050022from argparse import ArgumentParser
Brad Bishop34a7acd2017-04-27 23:47:23 -040023from sdbusplus.renderer import Renderer
Brad Bishop05b0c1e2017-05-23 00:24:01 -040024from sdbusplus.namedelement import NamedElement
Brad Bishope73b2c32017-05-23 18:01:54 -040025import sdbusplus.property
Brad Bishop05b0c1e2017-05-23 00:24:01 -040026
27
28class InvalidConfigError(BaseException):
29 '''General purpose config file parsing error.'''
30
31 def __init__(self, path, msg):
32 '''Display configuration file with the syntax
33 error and the error message.'''
34
35 self.config = path
36 self.msg = msg
37
38
39class NotUniqueError(InvalidConfigError):
40 '''Within a config file names must be unique.
41 Display the config file with the duplicate and
42 the duplicate itself.'''
43
44 def __init__(self, path, cls, *names):
45 fmt = 'Duplicate {0}: "{1}"'
46 super(NotUniqueError, self).__init__(
47 path, fmt.format(cls, ' '.join(names)))
48
49
50def get_index(objs, cls, name, config=None):
51 '''Items are usually rendered as C++ arrays and as
52 such are stored in python lists. Given an item name
53 its class, and an optional config file filter, find
54 the item index.'''
55
56 for i, x in enumerate(objs.get(cls, [])):
57 if config and x.configfile != config:
58 continue
59 if x.name != name:
60 continue
61
62 return i
63 raise InvalidConfigError(config, 'Could not find name: "{0}"'.format(name))
64
65
66def exists(objs, cls, name, config=None):
67 '''Check to see if an item already exists in a list given
68 the item name.'''
69
70 try:
71 get_index(objs, cls, name, config)
72 except:
73 return False
74
75 return True
76
77
78def add_unique(obj, *a, **kw):
79 '''Add an item to one or more lists unless already present,
80 with an option to constrain the search to a specific config file.'''
81
82 for container in a:
83 if not exists(container, obj.cls, obj.name, config=kw.get('config')):
84 container.setdefault(obj.cls, []).append(obj)
Matthew Barthdb440d42017-04-17 15:49:37 -050085
86
Brad Bishop01079892017-05-26 10:56:45 -040087class Cast(object):
88 '''Decorate an argument by casting it.'''
89
90 def __init__(self, cast, target):
91 '''cast is the cast type (static, const, etc...).
92 target is the cast target type.'''
93 self.cast = cast
94 self.target = target
95
96 def __call__(self, arg):
97 return '{0}_cast<{1}>({2})'.format(self.cast, self.target, arg)
98
99
100class Literal(object):
101 '''Decorate an argument with a literal operator.'''
102
103 integer_types = [
Brad Bishop01079892017-05-26 10:56:45 -0400104 'int16',
105 'int32',
106 'int64',
Brad Bishop01079892017-05-26 10:56:45 -0400107 'uint16',
108 'uint32',
109 'uint64'
110 ]
111
112 def __init__(self, type):
113 self.type = type
114
115 def __call__(self, arg):
116 if 'uint' in self.type:
117 arg = '{0}ull'.format(arg)
118 elif 'int' in self.type:
119 arg = '{0}ll'.format(arg)
120
121 if self.type in self.integer_types:
122 return Cast('static', '{0}_t'.format(self.type))(arg)
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400123 elif self.type == 'byte':
124 return Cast('static', 'uint8_t'.format(self.type))(arg)
Brad Bishop01079892017-05-26 10:56:45 -0400125
126 if self.type == 'string':
127 return '{0}s'.format(arg)
128
129 return arg
130
131
132class FixBool(object):
133 '''Un-capitalize booleans.'''
134
135 def __call__(self, arg):
136 return '{0}'.format(arg.lower())
137
138
139class Quote(object):
140 '''Decorate an argument by quoting it.'''
141
142 def __call__(self, arg):
143 return '"{0}"'.format(arg)
144
145
146class Argument(NamedElement, Renderer):
Gunnar Mills06fdaff2018-04-08 16:28:18 -0500147 '''Define argument type interface.'''
Brad Bishop01079892017-05-26 10:56:45 -0400148
149 def __init__(self, **kw):
150 self.type = kw.pop('type', None)
151 super(Argument, self).__init__(**kw)
152
153 def argument(self, loader, indent):
154 raise NotImplementedError
155
156
157class TrivialArgument(Argument):
158 '''Non-array type arguments.'''
159
160 def __init__(self, **kw):
161 self.value = kw.pop('value')
162 self.decorators = kw.pop('decorators', [])
163 if kw.get('type', None):
164 self.decorators.insert(0, Literal(kw['type']))
165 if kw.get('type', None) == 'string':
166 self.decorators.insert(0, Quote())
167 if kw.get('type', None) == 'boolean':
168 self.decorators.insert(0, FixBool())
169
170 super(TrivialArgument, self).__init__(**kw)
171
172 def argument(self, loader, indent):
173 a = str(self.value)
174 for d in self.decorators:
175 a = d(a)
176
177 return a
178
Matt Spinler80e9b652017-11-02 14:21:04 -0500179
Gunnar Mills30474cf2017-08-11 09:38:54 -0500180class Metadata(Argument):
181 '''Metadata type arguments.'''
182
183 def __init__(self, **kw):
184 self.value = kw.pop('value')
185 self.decorators = kw.pop('decorators', [])
186 if kw.get('type', None) == 'string':
187 self.decorators.insert(0, Quote())
188
189 super(Metadata, self).__init__(**kw)
190
191 def argument(self, loader, indent):
192 a = str(self.value)
193 for d in self.decorators:
194 a = d(a)
195
196 return a
Brad Bishop01079892017-05-26 10:56:45 -0400197
Matt Spinler80e9b652017-11-02 14:21:04 -0500198
Matthew Barthae786ef2019-09-04 15:46:13 -0500199class OpArgument(Argument):
200 '''Operation type arguments.'''
201
202 def __init__(self, **kw):
203 self.op = kw.pop('op')
204 self.bound = kw.pop('bound')
205 self.decorators = kw.pop('decorators', [])
206 if kw.get('type', None):
207 self.decorators.insert(0, Literal(kw['type']))
208 if kw.get('type', None) == 'string':
209 self.decorators.insert(0, Quote())
210 if kw.get('type', None) == 'boolean':
211 self.decorators.insert(0, FixBool())
212
213 super(OpArgument, self).__init__(**kw)
214
215 def argument(self, loader, indent):
216 a = str(self.bound)
217 for d in self.decorators:
218 a = d(a)
219
220 return a
221
222
Brad Bishop34a7acd2017-04-27 23:47:23 -0400223class Indent(object):
224 '''Help templates be depth agnostic.'''
Matthew Barthdb440d42017-04-17 15:49:37 -0500225
Brad Bishop34a7acd2017-04-27 23:47:23 -0400226 def __init__(self, depth=0):
227 self.depth = depth
Matthew Barthdb440d42017-04-17 15:49:37 -0500228
Brad Bishop34a7acd2017-04-27 23:47:23 -0400229 def __add__(self, depth):
230 return Indent(self.depth + depth)
231
232 def __call__(self, depth):
233 '''Render an indent at the current depth plus depth.'''
234 return 4*' '*(depth + self.depth)
235
236
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400237class ConfigEntry(NamedElement):
238 '''Base interface for rendered items.'''
239
240 def __init__(self, *a, **kw):
241 '''Pop the configfile/class/subclass keywords.'''
242
243 self.configfile = kw.pop('configfile')
244 self.cls = kw.pop('class')
245 self.subclass = kw.pop(self.cls)
246 super(ConfigEntry, self).__init__(**kw)
247
248 def factory(self, objs):
249 ''' Optional factory interface for subclasses to add
250 additional items to be rendered.'''
251
252 pass
253
254 def setup(self, objs):
255 ''' Optional setup interface for subclasses, invoked
256 after all factory methods have been run.'''
257
258 pass
259
260
Brad Bishop0e7df132017-05-23 17:58:12 -0400261class Path(ConfigEntry):
262 '''Path/metadata association.'''
263
264 def __init__(self, *a, **kw):
265 super(Path, self).__init__(**kw)
266
Brad Bishopbabf3b72017-05-31 19:44:53 -0400267 if self.name['meta'].upper() != self.name['meta']:
268 raise InvalidConfigError(
269 self.configfile,
270 'Metadata tag "{0}" must be upper case.'.format(
271 self.name['meta']))
272
Brad Bishop0e7df132017-05-23 17:58:12 -0400273 def factory(self, objs):
274 '''Create path and metadata elements.'''
275
276 args = {
277 'class': 'pathname',
278 'pathname': 'element',
279 'name': self.name['path']
280 }
281 add_unique(ConfigEntry(
282 configfile=self.configfile, **args), objs)
283
284 args = {
285 'class': 'meta',
286 'meta': 'element',
287 'name': self.name['meta']
288 }
289 add_unique(ConfigEntry(
290 configfile=self.configfile, **args), objs)
291
292 super(Path, self).factory(objs)
293
294 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500295 '''Resolve path and metadata names to indices.'''
Brad Bishop0e7df132017-05-23 17:58:12 -0400296
297 self.path = get_index(
298 objs, 'pathname', self.name['path'])
299 self.meta = get_index(
300 objs, 'meta', self.name['meta'])
301
302 super(Path, self).setup(objs)
303
304
Brad Bishope73b2c32017-05-23 18:01:54 -0400305class Property(ConfigEntry):
306 '''Property/interface/metadata association.'''
307
308 def __init__(self, *a, **kw):
309 super(Property, self).__init__(**kw)
310
Brad Bishopbabf3b72017-05-31 19:44:53 -0400311 if self.name['meta'].upper() != self.name['meta']:
312 raise InvalidConfigError(
313 self.configfile,
314 'Metadata tag "{0}" must be upper case.'.format(
315 self.name['meta']))
316
Brad Bishope73b2c32017-05-23 18:01:54 -0400317 def factory(self, objs):
318 '''Create interface, property name and metadata elements.'''
319
320 args = {
321 'class': 'interface',
322 'interface': 'element',
323 'name': self.name['interface']
324 }
325 add_unique(ConfigEntry(
326 configfile=self.configfile, **args), objs)
327
328 args = {
329 'class': 'propertyname',
330 'propertyname': 'element',
331 'name': self.name['property']
332 }
333 add_unique(ConfigEntry(
334 configfile=self.configfile, **args), objs)
335
336 args = {
337 'class': 'meta',
338 'meta': 'element',
339 'name': self.name['meta']
340 }
341 add_unique(ConfigEntry(
342 configfile=self.configfile, **args), objs)
343
344 super(Property, self).factory(objs)
345
346 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500347 '''Resolve interface, property and metadata to indices.'''
Brad Bishope73b2c32017-05-23 18:01:54 -0400348
349 self.interface = get_index(
350 objs, 'interface', self.name['interface'])
351 self.prop = get_index(
352 objs, 'propertyname', self.name['property'])
353 self.meta = get_index(
354 objs, 'meta', self.name['meta'])
355
356 super(Property, self).setup(objs)
357
358
Brad Bishop4b916f12017-05-23 18:06:38 -0400359class Instance(ConfigEntry):
360 '''Property/Path association.'''
361
362 def __init__(self, *a, **kw):
363 super(Instance, self).__init__(**kw)
364
365 def setup(self, objs):
Gunnar Mills78199b42017-10-25 16:30:18 -0500366 '''Resolve elements to indices.'''
Brad Bishop4b916f12017-05-23 18:06:38 -0400367
368 self.interface = get_index(
369 objs, 'interface', self.name['property']['interface'])
370 self.prop = get_index(
371 objs, 'propertyname', self.name['property']['property'])
372 self.propmeta = get_index(
373 objs, 'meta', self.name['property']['meta'])
374 self.path = get_index(
375 objs, 'pathname', self.name['path']['path'])
376 self.pathmeta = get_index(
377 objs, 'meta', self.name['path']['meta'])
378
379 super(Instance, self).setup(objs)
380
Marri Devender Rao80c70612018-04-12 09:22:55 -0500381class PathInstance(ConfigEntry):
382 '''Path association.'''
383
384 def __init__(self, *a, **kw):
385 super(PathInstance, self).__init__(**kw)
386
387 def setup(self, objs):
388 '''Resolve elements to indices.'''
389 self.path = self.name['path']['path']
390 self.pathmeta = self.name['path']['meta']
391 super(PathInstance, self).setup(objs)
Brad Bishop4b916f12017-05-23 18:06:38 -0400392
Brad Bishop05b0c1e2017-05-23 00:24:01 -0400393class Group(ConfigEntry):
394 '''Pop the members keyword for groups.'''
395
396 def __init__(self, *a, **kw):
397 self.members = kw.pop('members')
398 super(Group, self).__init__(**kw)
399
400
401class ImplicitGroup(Group):
402 '''Provide a factory method for groups whose members are
403 not explicitly declared in the config files.'''
404
405 def __init__(self, *a, **kw):
406 super(ImplicitGroup, self).__init__(**kw)
407
408 def factory(self, objs):
409 '''Create group members.'''
410
411 factory = Everything.classmap(self.subclass, 'element')
412 for m in self.members:
413 args = {
414 'class': self.subclass,
415 self.subclass: 'element',
416 'name': m
417 }
418
419 obj = factory(configfile=self.configfile, **args)
420 add_unique(obj, objs)
421 obj.factory(objs)
422
423 super(ImplicitGroup, self).factory(objs)
424
425
Brad Bishop0e7df132017-05-23 17:58:12 -0400426class GroupOfPaths(ImplicitGroup):
427 '''Path group config file directive.'''
428
429 def __init__(self, *a, **kw):
430 super(GroupOfPaths, self).__init__(**kw)
431
432 def setup(self, objs):
433 '''Resolve group members.'''
434
435 def map_member(x):
436 path = get_index(
437 objs, 'pathname', x['path'])
438 meta = get_index(
439 objs, 'meta', x['meta'])
440 return (path, meta)
441
442 self.members = map(
443 map_member,
444 self.members)
445
446 super(GroupOfPaths, self).setup(objs)
447
448
Brad Bishope73b2c32017-05-23 18:01:54 -0400449class GroupOfProperties(ImplicitGroup):
450 '''Property group config file directive.'''
451
452 def __init__(self, *a, **kw):
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400453 self.type = kw.pop('type')
Brad Bishope73b2c32017-05-23 18:01:54 -0400454 self.datatype = sdbusplus.property.Property(
455 name=kw.get('name'),
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400456 type=self.type).cppTypeName
Brad Bishope73b2c32017-05-23 18:01:54 -0400457
458 super(GroupOfProperties, self).__init__(**kw)
459
460 def setup(self, objs):
461 '''Resolve group members.'''
462
463 def map_member(x):
464 iface = get_index(
465 objs, 'interface', x['interface'])
466 prop = get_index(
467 objs, 'propertyname', x['property'])
468 meta = get_index(
469 objs, 'meta', x['meta'])
470
471 return (iface, prop, meta)
472
473 self.members = map(
474 map_member,
475 self.members)
476
477 super(GroupOfProperties, self).setup(objs)
478
479
Brad Bishop4b916f12017-05-23 18:06:38 -0400480class GroupOfInstances(ImplicitGroup):
481 '''A group of property instances.'''
482
483 def __init__(self, *a, **kw):
484 super(GroupOfInstances, self).__init__(**kw)
485
486 def setup(self, objs):
487 '''Resolve group members.'''
488
489 def map_member(x):
490 path = get_index(objs, 'pathname', x['path']['path'])
491 pathmeta = get_index(objs, 'meta', x['path']['meta'])
492 interface = get_index(
493 objs, 'interface', x['property']['interface'])
494 prop = get_index(objs, 'propertyname', x['property']['property'])
495 propmeta = get_index(objs, 'meta', x['property']['meta'])
496 instance = get_index(objs, 'instance', x)
497
498 return (path, pathmeta, interface, prop, propmeta, instance)
499
500 self.members = map(
501 map_member,
502 self.members)
503
504 super(GroupOfInstances, self).setup(objs)
505
Marri Devender Rao80c70612018-04-12 09:22:55 -0500506class GroupOfPathInstances(ImplicitGroup):
507 '''A group of path instances.'''
508
509 def __init__(self, *a, **kw):
510 super(GroupOfPathInstances, self).__init__(**kw)
511
512 def setup(self, objs):
513 '''Resolve group members.'''
514
515 def map_member(x):
516 path = get_index(objs, 'pathname', x['path']['path'])
517 pathmeta = get_index(objs, 'meta', x['path']['meta'])
518 pathinstance = get_index(objs, 'pathinstance', x)
519 return (path, pathmeta, pathinstance)
520
521 self.members = map(
522 map_member,
523 self.members)
524
525 super(GroupOfPathInstances, self).setup(objs)
526
Brad Bishop4b916f12017-05-23 18:06:38 -0400527
528class HasPropertyIndex(ConfigEntry):
529 '''Handle config file directives that require an index to be
530 constructed.'''
531
532 def __init__(self, *a, **kw):
533 self.paths = kw.pop('paths')
534 self.properties = kw.pop('properties')
535 super(HasPropertyIndex, self).__init__(**kw)
536
537 def factory(self, objs):
538 '''Create a group of instances for this index.'''
539
540 members = []
541 path_group = get_index(
542 objs, 'pathgroup', self.paths, config=self.configfile)
543 property_group = get_index(
544 objs, 'propertygroup', self.properties, config=self.configfile)
545
546 for path in objs['pathgroup'][path_group].members:
547 for prop in objs['propertygroup'][property_group].members:
548 member = {
549 'path': path,
550 'property': prop,
551 }
552 members.append(member)
553
554 args = {
555 'members': members,
556 'class': 'instancegroup',
557 'instancegroup': 'instance',
558 'name': '{0} {1}'.format(self.paths, self.properties)
559 }
560
561 group = GroupOfInstances(configfile=self.configfile, **args)
562 add_unique(group, objs, config=self.configfile)
563 group.factory(objs)
564
565 super(HasPropertyIndex, self).factory(objs)
566
567 def setup(self, objs):
568 '''Resolve path, property, and instance groups.'''
569
570 self.instances = get_index(
571 objs,
572 'instancegroup',
573 '{0} {1}'.format(self.paths, self.properties),
574 config=self.configfile)
575 self.paths = get_index(
576 objs,
577 'pathgroup',
578 self.paths,
579 config=self.configfile)
580 self.properties = get_index(
581 objs,
582 'propertygroup',
583 self.properties,
584 config=self.configfile)
585 self.datatype = objs['propertygroup'][self.properties].datatype
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400586 self.type = objs['propertygroup'][self.properties].type
Brad Bishop4b916f12017-05-23 18:06:38 -0400587
588 super(HasPropertyIndex, self).setup(objs)
589
Marri Devender Rao80c70612018-04-12 09:22:55 -0500590class HasPathIndex(ConfigEntry):
591 '''Handle config file directives that require an index to be
592 constructed.'''
593
594 def __init__(self, *a, **kw):
595 self.paths = kw.pop('paths')
596 super(HasPathIndex, self).__init__(**kw)
597
598 def factory(self, objs):
599 '''Create a group of instances for this index.'''
600
601 members = []
602 path_group = get_index(
603 objs, 'pathgroup', self.paths, config=self.configfile)
604
605 for path in objs['pathgroup'][path_group].members:
606 member = {
607 'path': path,
608 }
609 members.append(member)
610
611 args = {
612 'members': members,
613 'class': 'pathinstancegroup',
614 'pathinstancegroup': 'pathinstance',
615 'name': '{0}'.format(self.paths)
616 }
617
618 group = GroupOfPathInstances(configfile=self.configfile, **args)
619 add_unique(group, objs, config=self.configfile)
620 group.factory(objs)
621
622 super(HasPathIndex, self).factory(objs)
623
624 def setup(self, objs):
625 '''Resolve path and instance groups.'''
626
627 self.pathinstances = get_index(
628 objs,
629 'pathinstancegroup',
630 '{0}'.format(self.paths),
631 config=self.configfile)
632 self.paths = get_index(
633 objs,
634 'pathgroup',
635 self.paths,
636 config=self.configfile)
637 super(HasPathIndex, self).setup(objs)
Brad Bishop4b916f12017-05-23 18:06:38 -0400638
Matthew Barthefe01582019-09-09 15:22:37 -0500639class GroupOfFilters(ConfigEntry):
640 '''Handle config file directives that require an index for filters.'''
641
642 def __init__(self, *a, **kw):
643 # Pop filters data for adding to the available filters array
644 self.type = kw.pop('type')
645 self.datatype = kw.pop('datatype', None)
646 self.filters = kw.pop('filters', None)
647
648 super(GroupOfFilters, self).__init__(**kw)
649
650 def factory(self, objs):
651 '''Modify filters to add the property value type and
652 make them of operation argument type.'''
653 if self.filters:
654 # 'type' used within OpArgument to generate filter
655 # argument values so add to each filter
656 for f in self.filters:
657 f['type'] = self.type
658 self.filters = [OpArgument(**x) for x in self.filters]
659
660 super(GroupOfFilters, self).factory(objs)
661
Brad Bishop4b916f12017-05-23 18:06:38 -0400662class PropertyWatch(HasPropertyIndex):
663 '''Handle the property watch config file directive.'''
664
665 def __init__(self, *a, **kw):
Matthew Barthefe01582019-09-09 15:22:37 -0500666 # Pop optional filters for the properties being watched
667 self.filters = kw.pop('filters', None)
Brad Bishopfccdc392017-05-22 21:11:09 -0400668 self.callback = kw.pop('callback', None)
Brad Bishop4b916f12017-05-23 18:06:38 -0400669 super(PropertyWatch, self).__init__(**kw)
670
Matthew Barthefe01582019-09-09 15:22:37 -0500671 def factory(self, objs):
672 '''Create any filters for this property watch.'''
673
674 if self.filters:
675 # Get the datatype(i.e. "int64_t") of the properties in this watch
676 # (Made available after all `super` classes init'd)
677 datatype = objs['propertygroup'][get_index(
678 objs,
679 'propertygroup',
680 self.properties,
681 config=self.configfile)].datatype
682 # Get the type(i.e. "int64") of the properties in this watch
683 # (Made available after all `super` classes init'd)
684 type = objs['propertygroup'][get_index(
685 objs,
686 'propertygroup',
687 self.properties,
688 config=self.configfile)].type
689 # Construct the data needed to make the filters for
690 # this watch available.
691 # *Note: 'class', 'subclass', 'name' are required for
692 # storing the filter data(i.e. 'type', 'datatype', & 'filters')
693 args = {
694 'type': type,
695 'datatype': datatype,
696 'filters': self.filters,
697 'class': 'filtersgroup',
698 'filtersgroup': 'filters',
699 'name': self.name,
700 }
701 # Init GroupOfFilters class with this watch's filters' arguments
702 group = GroupOfFilters(configfile=self.configfile, **args)
703 # Store this group of filters so it can be indexed later
704 add_unique(group, objs, config=self.configfile)
705 group.factory(objs)
706
707 super(PropertyWatch, self).factory(objs)
708
Brad Bishopfccdc392017-05-22 21:11:09 -0400709 def setup(self, objs):
Matthew Barthefe01582019-09-09 15:22:37 -0500710 '''Resolve optional filters and callback.'''
711
712 if self.filters:
713 # Watch has filters, provide array index to access them
714 self.filters = get_index(
715 objs,
716 'filtersgroup',
717 self.name,
718 config=self.configfile)
Brad Bishopfccdc392017-05-22 21:11:09 -0400719
720 if self.callback:
721 self.callback = get_index(
722 objs,
723 'callback',
724 self.callback,
725 config=self.configfile)
726
727 super(PropertyWatch, self).setup(objs)
728
Marri Devender Rao80c70612018-04-12 09:22:55 -0500729class PathWatch(HasPathIndex):
730 '''Handle the path watch config file directive.'''
731
732 def __init__(self, *a, **kw):
733 self.pathcallback = kw.pop('pathcallback', None)
734 super(PathWatch, self).__init__(**kw)
735
736 def setup(self, objs):
737 '''Resolve optional callback.'''
738 if self.pathcallback:
739 self.pathcallback = get_index(
740 objs,
741 'pathcallback',
742 self.pathcallback,
743 config=self.configfile)
744 super(PathWatch, self).setup(objs)
745
Brad Bishopc1283ae2017-05-20 21:42:38 -0400746class Callback(HasPropertyIndex):
747 '''Interface and common logic for callbacks.'''
748
749 def __init__(self, *a, **kw):
750 super(Callback, self).__init__(**kw)
751
Marri Devender Rao80c70612018-04-12 09:22:55 -0500752class PathCallback(HasPathIndex):
753 '''Interface and common logic for callbacks.'''
754
755 def __init__(self, *a, **kw):
756 super(PathCallback, self).__init__(**kw)
Brad Bishopc1283ae2017-05-20 21:42:38 -0400757
Brad Bishop4041d722017-05-21 10:06:07 -0400758class ConditionCallback(ConfigEntry, Renderer):
759 '''Handle the journal callback config file directive.'''
760
761 def __init__(self, *a, **kw):
762 self.condition = kw.pop('condition')
763 self.instance = kw.pop('instance')
Brad Bishop3539db62017-05-30 14:21:12 -0400764 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400765 super(ConditionCallback, self).__init__(**kw)
766
767 def factory(self, objs):
768 '''Create a graph instance for this callback.'''
769
770 args = {
771 'configfile': self.configfile,
772 'members': [self.instance],
773 'class': 'callbackgroup',
774 'callbackgroup': 'callback',
775 'name': [self.instance]
776 }
777
778 entry = CallbackGraphEntry(**args)
779 add_unique(entry, objs, config=self.configfile)
780
781 super(ConditionCallback, self).factory(objs)
782
783 def setup(self, objs):
784 '''Resolve condition and graph entry.'''
785
786 self.graph = get_index(
787 objs,
788 'callbackgroup',
789 [self.instance],
790 config=self.configfile)
791
792 self.condition = get_index(
793 objs,
794 'condition',
795 self.name,
796 config=self.configfile)
797
798 super(ConditionCallback, self).setup(objs)
799
800 def construct(self, loader, indent):
801 return self.render(
802 loader,
803 'conditional.mako.cpp',
804 c=self,
805 indent=indent)
806
807
808class Condition(HasPropertyIndex):
809 '''Interface and common logic for conditions.'''
810
811 def __init__(self, *a, **kw):
812 self.callback = kw.pop('callback')
Brad Bishop3539db62017-05-30 14:21:12 -0400813 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400814 super(Condition, self).__init__(**kw)
815
816 def factory(self, objs):
817 '''Create a callback instance for this conditional.'''
818
819 args = {
820 'configfile': self.configfile,
821 'condition': self.name,
822 'class': 'callback',
823 'callback': 'conditional',
824 'instance': self.callback,
825 'name': self.name,
Brad Bishop3539db62017-05-30 14:21:12 -0400826 'defer': self.defer
Brad Bishop4041d722017-05-21 10:06:07 -0400827 }
828
829 callback = ConditionCallback(**args)
830 add_unique(callback, objs, config=self.configfile)
831 callback.factory(objs)
832
833 super(Condition, self).factory(objs)
834
835
836class CountCondition(Condition, Renderer):
837 '''Handle the count condition config file directive.'''
838
839 def __init__(self, *a, **kw):
840 self.countop = kw.pop('countop')
841 self.countbound = kw.pop('countbound')
842 self.op = kw.pop('op')
843 self.bound = kw.pop('bound')
Matt Spinlerc458dee2018-02-19 13:09:10 -0600844 self.oneshot = TrivialArgument(
845 type='boolean',
846 value=kw.pop('oneshot', False))
Brad Bishop4041d722017-05-21 10:06:07 -0400847 super(CountCondition, self).__init__(**kw)
848
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400849 def setup(self, objs):
850 '''Resolve type.'''
851
852 super(CountCondition, self).setup(objs)
853 self.bound = TrivialArgument(
854 type=self.type,
855 value=self.bound)
856
Brad Bishop4041d722017-05-21 10:06:07 -0400857 def construct(self, loader, indent):
858 return self.render(
859 loader,
860 'count.mako.cpp',
861 c=self,
862 indent=indent)
863
864
Matthew Barthefdd03c2019-09-04 15:44:35 -0500865class MedianCondition(Condition, Renderer):
866 '''Handle the median condition config file directive.'''
867
868 def __init__(self, *a, **kw):
869 self.op = kw.pop('op')
870 self.bound = kw.pop('bound')
871 self.oneshot = TrivialArgument(
872 type='boolean',
873 value=kw.pop('oneshot', False))
874 super(MedianCondition, self).__init__(**kw)
875
876 def setup(self, objs):
877 '''Resolve type.'''
878
879 super(MedianCondition, self).setup(objs)
880 self.bound = TrivialArgument(
881 type=self.type,
882 value=self.bound)
883
884 def construct(self, loader, indent):
885 return self.render(
886 loader,
887 'median.mako.cpp',
888 c=self,
889 indent=indent)
890
891
Brad Bishopc1283ae2017-05-20 21:42:38 -0400892class Journal(Callback, Renderer):
893 '''Handle the journal callback config file directive.'''
894
895 def __init__(self, *a, **kw):
896 self.severity = kw.pop('severity')
897 self.message = kw.pop('message')
898 super(Journal, self).__init__(**kw)
899
900 def construct(self, loader, indent):
901 return self.render(
902 loader,
903 'journal.mako.cpp',
904 c=self,
905 indent=indent)
906
907
Gunnar Millsd5faea32017-08-08 14:19:36 -0500908class Elog(Callback, Renderer):
909 '''Handle the elog callback config file directive.'''
910
911 def __init__(self, *a, **kw):
912 self.error = kw.pop('error')
Gunnar Mills30474cf2017-08-11 09:38:54 -0500913 self.metadata = [Metadata(**x) for x in kw.pop('metadata', {})]
Gunnar Millsd5faea32017-08-08 14:19:36 -0500914 super(Elog, self).__init__(**kw)
915
916 def construct(self, loader, indent):
Gunnar Millsd5faea32017-08-08 14:19:36 -0500917 with open('errors.hpp', 'a') as fd:
918 fd.write(
919 self.render(
920 loader,
921 'errors.mako.hpp',
922 c=self))
923 return self.render(
924 loader,
925 'elog.mako.cpp',
926 c=self,
927 indent=indent)
928
Ratan Gupta90bfaea2017-10-06 20:56:31 +0530929class Event(Callback, Renderer):
930 '''Handle the event callback config file directive.'''
931
932 def __init__(self, *a, **kw):
933 self.eventName = kw.pop('eventName')
934 self.eventMessage = kw.pop('eventMessage')
935 super(Event, self).__init__(**kw)
936
937 def construct(self, loader, indent):
938 return self.render(
939 loader,
940 'event.mako.cpp',
941 c=self,
942 indent=indent)
Gunnar Millsd5faea32017-08-08 14:19:36 -0500943
Marri Devender Rao80c70612018-04-12 09:22:55 -0500944class EventPath(PathCallback, Renderer):
945 '''Handle the event path callback config file directive.'''
946
947 def __init__(self, *a, **kw):
948 self.eventType = kw.pop('eventType')
949 super(EventPath, self).__init__(**kw)
950
951 def construct(self, loader, indent):
952 return self.render(
953 loader,
954 'eventpath.mako.cpp',
955 c=self,
956 indent=indent)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600957
958class ElogWithMetadata(Callback, Renderer):
959 '''Handle the elog_with_metadata callback config file directive.'''
960
961 def __init__(self, *a, **kw):
962 self.error = kw.pop('error')
963 self.metadata = kw.pop('metadata')
964 super(ElogWithMetadata, self).__init__(**kw)
965
966 def construct(self, loader, indent):
967 with open('errors.hpp', 'a') as fd:
968 fd.write(
969 self.render(
970 loader,
971 'errors.mako.hpp',
972 c=self))
973 return self.render(
974 loader,
975 'elog_with_metadata.mako.cpp',
976 c=self,
977 indent=indent)
978
979
Matt Spinler1d6ca482017-11-01 10:48:02 -0500980class ResolveCallout(Callback, Renderer):
981 '''Handle the 'resolve callout' callback config file directive.'''
982
983 def __init__(self, *a, **kw):
984 self.callout = kw.pop('callout')
985 super(ResolveCallout, self).__init__(**kw)
986
987 def construct(self, loader, indent):
988 return self.render(
989 loader,
990 'resolve_errors.mako.cpp',
991 c=self,
992 indent=indent)
993
994
Brad Bishop0df00be2017-05-25 23:38:37 -0400995class Method(ConfigEntry, Renderer):
996 '''Handle the method callback config file directive.'''
997
998 def __init__(self, *a, **kw):
999 self.service = kw.pop('service')
1000 self.path = kw.pop('path')
1001 self.interface = kw.pop('interface')
1002 self.method = kw.pop('method')
1003 self.args = [TrivialArgument(**x) for x in kw.pop('args', {})]
1004 super(Method, self).__init__(**kw)
1005
1006 def factory(self, objs):
1007 args = {
1008 'class': 'interface',
1009 'interface': 'element',
1010 'name': self.service
1011 }
1012 add_unique(ConfigEntry(
1013 configfile=self.configfile, **args), objs)
1014
1015 args = {
1016 'class': 'pathname',
1017 'pathname': 'element',
1018 'name': self.path
1019 }
1020 add_unique(ConfigEntry(
1021 configfile=self.configfile, **args), objs)
1022
1023 args = {
1024 'class': 'interface',
1025 'interface': 'element',
1026 'name': self.interface
1027 }
1028 add_unique(ConfigEntry(
1029 configfile=self.configfile, **args), objs)
1030
1031 args = {
1032 'class': 'propertyname',
1033 'propertyname': 'element',
1034 'name': self.method
1035 }
1036 add_unique(ConfigEntry(
1037 configfile=self.configfile, **args), objs)
1038
1039 super(Method, self).factory(objs)
1040
1041 def setup(self, objs):
1042 '''Resolve elements.'''
1043
1044 self.service = get_index(
1045 objs,
1046 'interface',
1047 self.service)
1048
1049 self.path = get_index(
1050 objs,
1051 'pathname',
1052 self.path)
1053
1054 self.interface = get_index(
1055 objs,
1056 'interface',
1057 self.interface)
1058
1059 self.method = get_index(
1060 objs,
1061 'propertyname',
1062 self.method)
1063
1064 super(Method, self).setup(objs)
1065
1066 def construct(self, loader, indent):
1067 return self.render(
1068 loader,
1069 'method.mako.cpp',
1070 c=self,
1071 indent=indent)
1072
1073
Brad Bishop49e66172017-05-23 19:16:21 -04001074class CallbackGraphEntry(Group):
1075 '''An entry in a traversal list for groups of callbacks.'''
1076
1077 def __init__(self, *a, **kw):
1078 super(CallbackGraphEntry, self).__init__(**kw)
1079
1080 def setup(self, objs):
1081 '''Resolve group members.'''
1082
1083 def map_member(x):
1084 return get_index(
1085 objs, 'callback', x, config=self.configfile)
1086
1087 self.members = map(
1088 map_member,
1089 self.members)
1090
1091 super(CallbackGraphEntry, self).setup(objs)
1092
Marri Devender Rao80c70612018-04-12 09:22:55 -05001093class PathCallbackGraphEntry(Group):
1094 '''An entry in a traversal list for groups of callbacks.'''
1095
1096 def __init__(self, *a, **kw):
1097 super(PathCallbackGraphEntry, self).__init__(**kw)
1098
1099 def setup(self, objs):
1100 '''Resolve group members.'''
1101
1102 def map_member(x):
1103 return get_index(
1104 objs, 'pathcallback', x, config=self.configfile)
1105
1106 self.members = map(
1107 map_member,
1108 self.members)
1109
1110 super(PathCallbackGraphEntry, self).setup(objs)
Brad Bishop49e66172017-05-23 19:16:21 -04001111
1112class GroupOfCallbacks(ConfigEntry, Renderer):
1113 '''Handle the callback group config file directive.'''
1114
1115 def __init__(self, *a, **kw):
1116 self.members = kw.pop('members')
1117 super(GroupOfCallbacks, self).__init__(**kw)
1118
1119 def factory(self, objs):
1120 '''Create a graph instance for this group of callbacks.'''
1121
1122 args = {
1123 'configfile': self.configfile,
1124 'members': self.members,
1125 'class': 'callbackgroup',
1126 'callbackgroup': 'callback',
1127 'name': self.members
1128 }
1129
1130 entry = CallbackGraphEntry(**args)
1131 add_unique(entry, objs, config=self.configfile)
1132
1133 super(GroupOfCallbacks, self).factory(objs)
1134
1135 def setup(self, objs):
1136 '''Resolve graph entry.'''
1137
1138 self.graph = get_index(
1139 objs, 'callbackgroup', self.members, config=self.configfile)
1140
1141 super(GroupOfCallbacks, self).setup(objs)
1142
1143 def construct(self, loader, indent):
1144 return self.render(
1145 loader,
1146 'callbackgroup.mako.cpp',
1147 c=self,
1148 indent=indent)
1149
Marri Devender Rao80c70612018-04-12 09:22:55 -05001150class GroupOfPathCallbacks(ConfigEntry, Renderer):
1151 '''Handle the callback group config file directive.'''
1152
1153 def __init__(self, *a, **kw):
1154 self.members = kw.pop('members')
1155 super(GroupOfPathCallbacks, self).__init__(**kw)
1156
1157 def factory(self, objs):
1158 '''Create a graph instance for this group of callbacks.'''
1159
1160 args = {
1161 'configfile': self.configfile,
1162 'members': self.members,
1163 'class': 'pathcallbackgroup',
1164 'pathcallbackgroup': 'pathcallback',
1165 'name': self.members
1166 }
1167
1168 entry = PathCallbackGraphEntry(**args)
1169 add_unique(entry, objs, config=self.configfile)
1170 super(GroupOfPathCallbacks, self).factory(objs)
1171
1172 def setup(self, objs):
1173 '''Resolve graph entry.'''
1174
1175 self.graph = get_index(
1176 objs, 'callbackpathgroup', self.members, config=self.configfile)
1177
1178 super(GroupOfPathCallbacks, self).setup(objs)
1179
1180 def construct(self, loader, indent):
1181 return self.render(
1182 loader,
1183 'callbackpathgroup.mako.cpp',
1184 c=self,
1185 indent=indent)
Brad Bishop49e66172017-05-23 19:16:21 -04001186
Brad Bishop34a7acd2017-04-27 23:47:23 -04001187class Everything(Renderer):
1188 '''Parse/render entry point.'''
1189
1190 @staticmethod
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001191 def classmap(cls, sub=None):
1192 '''Map render item class and subclass entries to the appropriate
1193 handler methods.'''
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001194 class_map = {
Brad Bishop0e7df132017-05-23 17:58:12 -04001195 'path': {
1196 'element': Path,
1197 },
1198 'pathgroup': {
1199 'path': GroupOfPaths,
1200 },
Brad Bishope73b2c32017-05-23 18:01:54 -04001201 'propertygroup': {
1202 'property': GroupOfProperties,
1203 },
1204 'property': {
1205 'element': Property,
1206 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001207 'watch': {
1208 'property': PropertyWatch,
1209 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001210 'pathwatch': {
1211 'path': PathWatch,
1212 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001213 'instance': {
1214 'element': Instance,
1215 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001216 'pathinstance': {
1217 'element': PathInstance,
1218 },
Brad Bishopc1283ae2017-05-20 21:42:38 -04001219 'callback': {
1220 'journal': Journal,
Gunnar Millsd5faea32017-08-08 14:19:36 -05001221 'elog': Elog,
Matt Spinler3c5318d2018-02-19 14:03:05 -06001222 'elog_with_metadata': ElogWithMetadata,
Ratan Gupta90bfaea2017-10-06 20:56:31 +05301223 'event': Event,
Brad Bishop49e66172017-05-23 19:16:21 -04001224 'group': GroupOfCallbacks,
Brad Bishop0df00be2017-05-25 23:38:37 -04001225 'method': Method,
Matt Spinler1d6ca482017-11-01 10:48:02 -05001226 'resolve callout': ResolveCallout,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001227 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001228 'pathcallback': {
1229 'eventpath': EventPath,
1230 'grouppath': GroupOfPathCallbacks,
1231 },
Brad Bishop4041d722017-05-21 10:06:07 -04001232 'condition': {
1233 'count': CountCondition,
Matthew Barthefdd03c2019-09-04 15:44:35 -05001234 'median': MedianCondition,
Brad Bishop4041d722017-05-21 10:06:07 -04001235 },
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001236 }
1237
1238 if cls not in class_map:
1239 raise NotImplementedError('Unknown class: "{0}"'.format(cls))
1240 if sub not in class_map[cls]:
1241 raise NotImplementedError('Unknown {0} type: "{1}"'.format(
1242 cls, sub))
1243
1244 return class_map[cls][sub]
1245
1246 @staticmethod
1247 def load_one_yaml(path, fd, objs):
1248 '''Parse a single YAML file. Parsing occurs in three phases.
1249 In the first phase a factory method associated with each
1250 configuration file directive is invoked. These factory
1251 methods generate more factory methods. In the second
1252 phase the factory methods created in the first phase
1253 are invoked. In the last phase a callback is invoked on
1254 each object created in phase two. Typically the callback
1255 resolves references to other configuration file directives.'''
1256
1257 factory_objs = {}
1258 for x in yaml.safe_load(fd.read()) or {}:
1259
1260 # Create factory object for this config file directive.
1261 cls = x['class']
1262 sub = x.get(cls)
1263 if cls == 'group':
1264 cls = '{0}group'.format(sub)
1265
1266 factory = Everything.classmap(cls, sub)
1267 obj = factory(configfile=path, **x)
1268
1269 # For a given class of directive, validate the file
1270 # doesn't have any duplicate names (duplicates are
1271 # ok across config files).
1272 if exists(factory_objs, obj.cls, obj.name, config=path):
1273 raise NotUniqueError(path, cls, obj.name)
1274
1275 factory_objs.setdefault(cls, []).append(obj)
1276 objs.setdefault(cls, []).append(obj)
1277
1278 for cls, items in factory_objs.items():
1279 for obj in items:
1280 # Add objects for template consumption.
1281 obj.factory(objs)
1282
1283 @staticmethod
Brad Bishop34a7acd2017-04-27 23:47:23 -04001284 def load(args):
1285 '''Aggregate all the YAML in the input directory
1286 into a single aggregate.'''
1287
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001288 objs = {}
1289 yaml_files = filter(
1290 lambda x: x.endswith('.yaml'),
1291 os.listdir(args.inputdir))
Brad Bishop34a7acd2017-04-27 23:47:23 -04001292
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001293 yaml_files.sort()
Brad Bishop34a7acd2017-04-27 23:47:23 -04001294
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001295 for x in yaml_files:
1296 path = os.path.join(args.inputdir, x)
1297 with open(path, 'r') as fd:
1298 Everything.load_one_yaml(path, fd, objs)
1299
1300 # Configuration file directives reference each other via
1301 # the name attribute; however, when rendered the reference
1302 # is just an array index.
1303 #
1304 # At this point all objects have been created but references
Gunnar Mills78199b42017-10-25 16:30:18 -05001305 # have not been resolved to array indices. Instruct objects
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001306 # to do that now.
1307 for cls, items in objs.items():
1308 for obj in items:
1309 obj.setup(objs)
1310
1311 return Everything(**objs)
Brad Bishop34a7acd2017-04-27 23:47:23 -04001312
1313 def __init__(self, *a, **kw):
Brad Bishop0e7df132017-05-23 17:58:12 -04001314 self.pathmeta = kw.pop('path', [])
1315 self.paths = kw.pop('pathname', [])
1316 self.meta = kw.pop('meta', [])
1317 self.pathgroups = kw.pop('pathgroup', [])
Brad Bishope73b2c32017-05-23 18:01:54 -04001318 self.interfaces = kw.pop('interface', [])
1319 self.properties = kw.pop('property', [])
1320 self.propertynames = kw.pop('propertyname', [])
1321 self.propertygroups = kw.pop('propertygroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001322 self.instances = kw.pop('instance', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001323 self.pathinstances = kw.pop('pathinstance', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001324 self.instancegroups = kw.pop('instancegroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001325 self.pathinstancegroups = kw.pop('pathinstancegroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001326 self.watches = kw.pop('watch', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001327 self.pathwatches = kw.pop('pathwatch', [])
Brad Bishopc1283ae2017-05-20 21:42:38 -04001328 self.callbacks = kw.pop('callback', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001329 self.pathcallbacks = kw.pop('pathcallback', [])
Brad Bishop49e66172017-05-23 19:16:21 -04001330 self.callbackgroups = kw.pop('callbackgroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001331 self.pathcallbackgroups = kw.pop('pathcallbackgroup', [])
Brad Bishop4041d722017-05-21 10:06:07 -04001332 self.conditions = kw.pop('condition', [])
Matthew Barthefe01582019-09-09 15:22:37 -05001333 self.filters = kw.pop('filtersgroup', [])
Brad Bishop0e7df132017-05-23 17:58:12 -04001334
Brad Bishop34a7acd2017-04-27 23:47:23 -04001335 super(Everything, self).__init__(**kw)
1336
1337 def generate_cpp(self, loader):
1338 '''Render the template with the provided data.'''
Gunnar Millsd5faea32017-08-08 14:19:36 -05001339 # errors.hpp is used by generated.hpp to included any error.hpp files
1340 open('errors.hpp', 'w+')
1341
Brad Bishope3a01af2017-05-15 17:09:04 -04001342 with open(args.output, 'w') as fd:
Brad Bishop34a7acd2017-04-27 23:47:23 -04001343 fd.write(
1344 self.render(
1345 loader,
Brad Bishope3a01af2017-05-15 17:09:04 -04001346 args.template,
Brad Bishop0e7df132017-05-23 17:58:12 -04001347 meta=self.meta,
Brad Bishope73b2c32017-05-23 18:01:54 -04001348 properties=self.properties,
1349 propertynames=self.propertynames,
1350 interfaces=self.interfaces,
Brad Bishop0e7df132017-05-23 17:58:12 -04001351 paths=self.paths,
1352 pathmeta=self.pathmeta,
1353 pathgroups=self.pathgroups,
Brad Bishope73b2c32017-05-23 18:01:54 -04001354 propertygroups=self.propertygroups,
Brad Bishop4b916f12017-05-23 18:06:38 -04001355 instances=self.instances,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001356 pathinstances=self.pathinstances,
Brad Bishop4b916f12017-05-23 18:06:38 -04001357 watches=self.watches,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001358 pathwatches=self.pathwatches,
Brad Bishop4b916f12017-05-23 18:06:38 -04001359 instancegroups=self.instancegroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001360 pathinstancegroups=self.pathinstancegroups,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001361 callbacks=self.callbacks,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001362 pathcallbacks=self.pathcallbacks,
Brad Bishop49e66172017-05-23 19:16:21 -04001363 callbackgroups=self.callbackgroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001364 pathcallbackgroups=self.pathcallbackgroups,
Brad Bishop4041d722017-05-21 10:06:07 -04001365 conditions=self.conditions,
Matthew Barthefe01582019-09-09 15:22:37 -05001366 filters=self.filters,
Brad Bishop34a7acd2017-04-27 23:47:23 -04001367 indent=Indent()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001368
1369if __name__ == '__main__':
Brad Bishop34a7acd2017-04-27 23:47:23 -04001370 script_dir = os.path.dirname(os.path.realpath(__file__))
1371 valid_commands = {
1372 'generate-cpp': 'generate_cpp',
1373 }
1374
1375 parser = ArgumentParser(
1376 description='Phosphor DBus Monitor (PDM) YAML '
1377 'scanner and code generator.')
1378
Matthew Barthdb440d42017-04-17 15:49:37 -05001379 parser.add_argument(
Brad Bishope3a01af2017-05-15 17:09:04 -04001380 "-o", "--out", dest="output",
1381 default='generated.cpp',
1382 help="Generated output file name and path.")
1383 parser.add_argument(
1384 '-t', '--template', dest='template',
Brad Bishop870c3fc2017-05-22 23:23:13 -04001385 default='generated.mako.hpp',
Brad Bishope3a01af2017-05-15 17:09:04 -04001386 help='The top level template to render.')
1387 parser.add_argument(
1388 '-p', '--template-path', dest='template_search',
1389 default=script_dir,
1390 help='The space delimited mako template search path.')
Brad Bishop34a7acd2017-04-27 23:47:23 -04001391 parser.add_argument(
1392 '-d', '--dir', dest='inputdir',
1393 default=os.path.join(script_dir, 'example'),
1394 help='Location of files to process.')
1395 parser.add_argument(
1396 'command', metavar='COMMAND', type=str,
1397 choices=valid_commands.keys(),
1398 help='%s.' % " | ".join(valid_commands.keys()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001399
Brad Bishop34a7acd2017-04-27 23:47:23 -04001400 args = parser.parse_args()
1401
1402 if sys.version_info < (3, 0):
1403 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001404 directories=args.template_search.split(),
Brad Bishop34a7acd2017-04-27 23:47:23 -04001405 disable_unicode=True)
1406 else:
1407 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001408 directories=args.template_search.split())
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001409 try:
1410 function = getattr(
1411 Everything.load(args),
1412 valid_commands[args.command])
1413 function(lookup)
1414 except InvalidConfigError as e:
1415 sys.stdout.write('{0}: {1}\n\n'.format(e.config, e.msg))
1416 raise