blob: dc1c9b789209de0336d96b1a8b1e94f8a90753db [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
639class PropertyWatch(HasPropertyIndex):
640 '''Handle the property watch config file directive.'''
641
642 def __init__(self, *a, **kw):
Matthew Barthae786ef2019-09-04 15:46:13 -0500643 self.filters = [OpArgument(**x) for x in kw.pop('filters', {})]
Brad Bishopfccdc392017-05-22 21:11:09 -0400644 self.callback = kw.pop('callback', None)
Brad Bishop4b916f12017-05-23 18:06:38 -0400645 super(PropertyWatch, self).__init__(**kw)
646
Brad Bishopfccdc392017-05-22 21:11:09 -0400647 def setup(self, objs):
648 '''Resolve optional callback.'''
649
650 if self.callback:
651 self.callback = get_index(
652 objs,
653 'callback',
654 self.callback,
655 config=self.configfile)
656
657 super(PropertyWatch, self).setup(objs)
658
Marri Devender Rao80c70612018-04-12 09:22:55 -0500659class PathWatch(HasPathIndex):
660 '''Handle the path watch config file directive.'''
661
662 def __init__(self, *a, **kw):
663 self.pathcallback = kw.pop('pathcallback', None)
664 super(PathWatch, self).__init__(**kw)
665
666 def setup(self, objs):
667 '''Resolve optional callback.'''
668 if self.pathcallback:
669 self.pathcallback = get_index(
670 objs,
671 'pathcallback',
672 self.pathcallback,
673 config=self.configfile)
674 super(PathWatch, self).setup(objs)
675
Brad Bishop4b916f12017-05-23 18:06:38 -0400676
Brad Bishopc1283ae2017-05-20 21:42:38 -0400677class Callback(HasPropertyIndex):
678 '''Interface and common logic for callbacks.'''
679
680 def __init__(self, *a, **kw):
681 super(Callback, self).__init__(**kw)
682
Marri Devender Rao80c70612018-04-12 09:22:55 -0500683class PathCallback(HasPathIndex):
684 '''Interface and common logic for callbacks.'''
685
686 def __init__(self, *a, **kw):
687 super(PathCallback, self).__init__(**kw)
Brad Bishopc1283ae2017-05-20 21:42:38 -0400688
Brad Bishop4041d722017-05-21 10:06:07 -0400689class ConditionCallback(ConfigEntry, Renderer):
690 '''Handle the journal callback config file directive.'''
691
692 def __init__(self, *a, **kw):
693 self.condition = kw.pop('condition')
694 self.instance = kw.pop('instance')
Brad Bishop3539db62017-05-30 14:21:12 -0400695 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400696 super(ConditionCallback, self).__init__(**kw)
697
698 def factory(self, objs):
699 '''Create a graph instance for this callback.'''
700
701 args = {
702 'configfile': self.configfile,
703 'members': [self.instance],
704 'class': 'callbackgroup',
705 'callbackgroup': 'callback',
706 'name': [self.instance]
707 }
708
709 entry = CallbackGraphEntry(**args)
710 add_unique(entry, objs, config=self.configfile)
711
712 super(ConditionCallback, self).factory(objs)
713
714 def setup(self, objs):
715 '''Resolve condition and graph entry.'''
716
717 self.graph = get_index(
718 objs,
719 'callbackgroup',
720 [self.instance],
721 config=self.configfile)
722
723 self.condition = get_index(
724 objs,
725 'condition',
726 self.name,
727 config=self.configfile)
728
729 super(ConditionCallback, self).setup(objs)
730
731 def construct(self, loader, indent):
732 return self.render(
733 loader,
734 'conditional.mako.cpp',
735 c=self,
736 indent=indent)
737
738
739class Condition(HasPropertyIndex):
740 '''Interface and common logic for conditions.'''
741
742 def __init__(self, *a, **kw):
743 self.callback = kw.pop('callback')
Brad Bishop3539db62017-05-30 14:21:12 -0400744 self.defer = kw.pop('defer', None)
Brad Bishop4041d722017-05-21 10:06:07 -0400745 super(Condition, self).__init__(**kw)
746
747 def factory(self, objs):
748 '''Create a callback instance for this conditional.'''
749
750 args = {
751 'configfile': self.configfile,
752 'condition': self.name,
753 'class': 'callback',
754 'callback': 'conditional',
755 'instance': self.callback,
756 'name': self.name,
Brad Bishop3539db62017-05-30 14:21:12 -0400757 'defer': self.defer
Brad Bishop4041d722017-05-21 10:06:07 -0400758 }
759
760 callback = ConditionCallback(**args)
761 add_unique(callback, objs, config=self.configfile)
762 callback.factory(objs)
763
764 super(Condition, self).factory(objs)
765
766
767class CountCondition(Condition, Renderer):
768 '''Handle the count condition config file directive.'''
769
770 def __init__(self, *a, **kw):
771 self.countop = kw.pop('countop')
772 self.countbound = kw.pop('countbound')
773 self.op = kw.pop('op')
774 self.bound = kw.pop('bound')
Matt Spinlerc458dee2018-02-19 13:09:10 -0600775 self.oneshot = TrivialArgument(
776 type='boolean',
777 value=kw.pop('oneshot', False))
Brad Bishop4041d722017-05-21 10:06:07 -0400778 super(CountCondition, self).__init__(**kw)
779
Brad Bishopec2ed2f2017-05-31 21:10:43 -0400780 def setup(self, objs):
781 '''Resolve type.'''
782
783 super(CountCondition, self).setup(objs)
784 self.bound = TrivialArgument(
785 type=self.type,
786 value=self.bound)
787
Brad Bishop4041d722017-05-21 10:06:07 -0400788 def construct(self, loader, indent):
789 return self.render(
790 loader,
791 'count.mako.cpp',
792 c=self,
793 indent=indent)
794
795
Matthew Barthefdd03c2019-09-04 15:44:35 -0500796class MedianCondition(Condition, Renderer):
797 '''Handle the median condition config file directive.'''
798
799 def __init__(self, *a, **kw):
800 self.op = kw.pop('op')
801 self.bound = kw.pop('bound')
802 self.oneshot = TrivialArgument(
803 type='boolean',
804 value=kw.pop('oneshot', False))
805 super(MedianCondition, self).__init__(**kw)
806
807 def setup(self, objs):
808 '''Resolve type.'''
809
810 super(MedianCondition, self).setup(objs)
811 self.bound = TrivialArgument(
812 type=self.type,
813 value=self.bound)
814
815 def construct(self, loader, indent):
816 return self.render(
817 loader,
818 'median.mako.cpp',
819 c=self,
820 indent=indent)
821
822
Brad Bishopc1283ae2017-05-20 21:42:38 -0400823class Journal(Callback, Renderer):
824 '''Handle the journal callback config file directive.'''
825
826 def __init__(self, *a, **kw):
827 self.severity = kw.pop('severity')
828 self.message = kw.pop('message')
829 super(Journal, self).__init__(**kw)
830
831 def construct(self, loader, indent):
832 return self.render(
833 loader,
834 'journal.mako.cpp',
835 c=self,
836 indent=indent)
837
838
Gunnar Millsd5faea32017-08-08 14:19:36 -0500839class Elog(Callback, Renderer):
840 '''Handle the elog callback config file directive.'''
841
842 def __init__(self, *a, **kw):
843 self.error = kw.pop('error')
Gunnar Mills30474cf2017-08-11 09:38:54 -0500844 self.metadata = [Metadata(**x) for x in kw.pop('metadata', {})]
Gunnar Millsd5faea32017-08-08 14:19:36 -0500845 super(Elog, self).__init__(**kw)
846
847 def construct(self, loader, indent):
Gunnar Millsd5faea32017-08-08 14:19:36 -0500848 with open('errors.hpp', 'a') as fd:
849 fd.write(
850 self.render(
851 loader,
852 'errors.mako.hpp',
853 c=self))
854 return self.render(
855 loader,
856 'elog.mako.cpp',
857 c=self,
858 indent=indent)
859
Ratan Gupta90bfaea2017-10-06 20:56:31 +0530860class Event(Callback, Renderer):
861 '''Handle the event callback config file directive.'''
862
863 def __init__(self, *a, **kw):
864 self.eventName = kw.pop('eventName')
865 self.eventMessage = kw.pop('eventMessage')
866 super(Event, self).__init__(**kw)
867
868 def construct(self, loader, indent):
869 return self.render(
870 loader,
871 'event.mako.cpp',
872 c=self,
873 indent=indent)
Gunnar Millsd5faea32017-08-08 14:19:36 -0500874
Marri Devender Rao80c70612018-04-12 09:22:55 -0500875class EventPath(PathCallback, Renderer):
876 '''Handle the event path callback config file directive.'''
877
878 def __init__(self, *a, **kw):
879 self.eventType = kw.pop('eventType')
880 super(EventPath, self).__init__(**kw)
881
882 def construct(self, loader, indent):
883 return self.render(
884 loader,
885 'eventpath.mako.cpp',
886 c=self,
887 indent=indent)
Matt Spinler3c5318d2018-02-19 14:03:05 -0600888
889class ElogWithMetadata(Callback, Renderer):
890 '''Handle the elog_with_metadata callback config file directive.'''
891
892 def __init__(self, *a, **kw):
893 self.error = kw.pop('error')
894 self.metadata = kw.pop('metadata')
895 super(ElogWithMetadata, self).__init__(**kw)
896
897 def construct(self, loader, indent):
898 with open('errors.hpp', 'a') as fd:
899 fd.write(
900 self.render(
901 loader,
902 'errors.mako.hpp',
903 c=self))
904 return self.render(
905 loader,
906 'elog_with_metadata.mako.cpp',
907 c=self,
908 indent=indent)
909
910
Matt Spinler1d6ca482017-11-01 10:48:02 -0500911class ResolveCallout(Callback, Renderer):
912 '''Handle the 'resolve callout' callback config file directive.'''
913
914 def __init__(self, *a, **kw):
915 self.callout = kw.pop('callout')
916 super(ResolveCallout, self).__init__(**kw)
917
918 def construct(self, loader, indent):
919 return self.render(
920 loader,
921 'resolve_errors.mako.cpp',
922 c=self,
923 indent=indent)
924
925
Brad Bishop0df00be2017-05-25 23:38:37 -0400926class Method(ConfigEntry, Renderer):
927 '''Handle the method callback config file directive.'''
928
929 def __init__(self, *a, **kw):
930 self.service = kw.pop('service')
931 self.path = kw.pop('path')
932 self.interface = kw.pop('interface')
933 self.method = kw.pop('method')
934 self.args = [TrivialArgument(**x) for x in kw.pop('args', {})]
935 super(Method, self).__init__(**kw)
936
937 def factory(self, objs):
938 args = {
939 'class': 'interface',
940 'interface': 'element',
941 'name': self.service
942 }
943 add_unique(ConfigEntry(
944 configfile=self.configfile, **args), objs)
945
946 args = {
947 'class': 'pathname',
948 'pathname': 'element',
949 'name': self.path
950 }
951 add_unique(ConfigEntry(
952 configfile=self.configfile, **args), objs)
953
954 args = {
955 'class': 'interface',
956 'interface': 'element',
957 'name': self.interface
958 }
959 add_unique(ConfigEntry(
960 configfile=self.configfile, **args), objs)
961
962 args = {
963 'class': 'propertyname',
964 'propertyname': 'element',
965 'name': self.method
966 }
967 add_unique(ConfigEntry(
968 configfile=self.configfile, **args), objs)
969
970 super(Method, self).factory(objs)
971
972 def setup(self, objs):
973 '''Resolve elements.'''
974
975 self.service = get_index(
976 objs,
977 'interface',
978 self.service)
979
980 self.path = get_index(
981 objs,
982 'pathname',
983 self.path)
984
985 self.interface = get_index(
986 objs,
987 'interface',
988 self.interface)
989
990 self.method = get_index(
991 objs,
992 'propertyname',
993 self.method)
994
995 super(Method, self).setup(objs)
996
997 def construct(self, loader, indent):
998 return self.render(
999 loader,
1000 'method.mako.cpp',
1001 c=self,
1002 indent=indent)
1003
1004
Brad Bishop49e66172017-05-23 19:16:21 -04001005class CallbackGraphEntry(Group):
1006 '''An entry in a traversal list for groups of callbacks.'''
1007
1008 def __init__(self, *a, **kw):
1009 super(CallbackGraphEntry, self).__init__(**kw)
1010
1011 def setup(self, objs):
1012 '''Resolve group members.'''
1013
1014 def map_member(x):
1015 return get_index(
1016 objs, 'callback', x, config=self.configfile)
1017
1018 self.members = map(
1019 map_member,
1020 self.members)
1021
1022 super(CallbackGraphEntry, self).setup(objs)
1023
Marri Devender Rao80c70612018-04-12 09:22:55 -05001024class PathCallbackGraphEntry(Group):
1025 '''An entry in a traversal list for groups of callbacks.'''
1026
1027 def __init__(self, *a, **kw):
1028 super(PathCallbackGraphEntry, self).__init__(**kw)
1029
1030 def setup(self, objs):
1031 '''Resolve group members.'''
1032
1033 def map_member(x):
1034 return get_index(
1035 objs, 'pathcallback', x, config=self.configfile)
1036
1037 self.members = map(
1038 map_member,
1039 self.members)
1040
1041 super(PathCallbackGraphEntry, self).setup(objs)
Brad Bishop49e66172017-05-23 19:16:21 -04001042
1043class GroupOfCallbacks(ConfigEntry, Renderer):
1044 '''Handle the callback group config file directive.'''
1045
1046 def __init__(self, *a, **kw):
1047 self.members = kw.pop('members')
1048 super(GroupOfCallbacks, self).__init__(**kw)
1049
1050 def factory(self, objs):
1051 '''Create a graph instance for this group of callbacks.'''
1052
1053 args = {
1054 'configfile': self.configfile,
1055 'members': self.members,
1056 'class': 'callbackgroup',
1057 'callbackgroup': 'callback',
1058 'name': self.members
1059 }
1060
1061 entry = CallbackGraphEntry(**args)
1062 add_unique(entry, objs, config=self.configfile)
1063
1064 super(GroupOfCallbacks, self).factory(objs)
1065
1066 def setup(self, objs):
1067 '''Resolve graph entry.'''
1068
1069 self.graph = get_index(
1070 objs, 'callbackgroup', self.members, config=self.configfile)
1071
1072 super(GroupOfCallbacks, self).setup(objs)
1073
1074 def construct(self, loader, indent):
1075 return self.render(
1076 loader,
1077 'callbackgroup.mako.cpp',
1078 c=self,
1079 indent=indent)
1080
Marri Devender Rao80c70612018-04-12 09:22:55 -05001081class GroupOfPathCallbacks(ConfigEntry, Renderer):
1082 '''Handle the callback group config file directive.'''
1083
1084 def __init__(self, *a, **kw):
1085 self.members = kw.pop('members')
1086 super(GroupOfPathCallbacks, self).__init__(**kw)
1087
1088 def factory(self, objs):
1089 '''Create a graph instance for this group of callbacks.'''
1090
1091 args = {
1092 'configfile': self.configfile,
1093 'members': self.members,
1094 'class': 'pathcallbackgroup',
1095 'pathcallbackgroup': 'pathcallback',
1096 'name': self.members
1097 }
1098
1099 entry = PathCallbackGraphEntry(**args)
1100 add_unique(entry, objs, config=self.configfile)
1101 super(GroupOfPathCallbacks, self).factory(objs)
1102
1103 def setup(self, objs):
1104 '''Resolve graph entry.'''
1105
1106 self.graph = get_index(
1107 objs, 'callbackpathgroup', self.members, config=self.configfile)
1108
1109 super(GroupOfPathCallbacks, self).setup(objs)
1110
1111 def construct(self, loader, indent):
1112 return self.render(
1113 loader,
1114 'callbackpathgroup.mako.cpp',
1115 c=self,
1116 indent=indent)
Brad Bishop49e66172017-05-23 19:16:21 -04001117
Brad Bishop34a7acd2017-04-27 23:47:23 -04001118class Everything(Renderer):
1119 '''Parse/render entry point.'''
1120
1121 @staticmethod
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001122 def classmap(cls, sub=None):
1123 '''Map render item class and subclass entries to the appropriate
1124 handler methods.'''
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001125 class_map = {
Brad Bishop0e7df132017-05-23 17:58:12 -04001126 'path': {
1127 'element': Path,
1128 },
1129 'pathgroup': {
1130 'path': GroupOfPaths,
1131 },
Brad Bishope73b2c32017-05-23 18:01:54 -04001132 'propertygroup': {
1133 'property': GroupOfProperties,
1134 },
1135 'property': {
1136 'element': Property,
1137 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001138 'watch': {
1139 'property': PropertyWatch,
1140 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001141 'pathwatch': {
1142 'path': PathWatch,
1143 },
Brad Bishop4b916f12017-05-23 18:06:38 -04001144 'instance': {
1145 'element': Instance,
1146 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001147 'pathinstance': {
1148 'element': PathInstance,
1149 },
Brad Bishopc1283ae2017-05-20 21:42:38 -04001150 'callback': {
1151 'journal': Journal,
Gunnar Millsd5faea32017-08-08 14:19:36 -05001152 'elog': Elog,
Matt Spinler3c5318d2018-02-19 14:03:05 -06001153 'elog_with_metadata': ElogWithMetadata,
Ratan Gupta90bfaea2017-10-06 20:56:31 +05301154 'event': Event,
Brad Bishop49e66172017-05-23 19:16:21 -04001155 'group': GroupOfCallbacks,
Brad Bishop0df00be2017-05-25 23:38:37 -04001156 'method': Method,
Matt Spinler1d6ca482017-11-01 10:48:02 -05001157 'resolve callout': ResolveCallout,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001158 },
Marri Devender Rao80c70612018-04-12 09:22:55 -05001159 'pathcallback': {
1160 'eventpath': EventPath,
1161 'grouppath': GroupOfPathCallbacks,
1162 },
Brad Bishop4041d722017-05-21 10:06:07 -04001163 'condition': {
1164 'count': CountCondition,
Matthew Barthefdd03c2019-09-04 15:44:35 -05001165 'median': MedianCondition,
Brad Bishop4041d722017-05-21 10:06:07 -04001166 },
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001167 }
1168
1169 if cls not in class_map:
1170 raise NotImplementedError('Unknown class: "{0}"'.format(cls))
1171 if sub not in class_map[cls]:
1172 raise NotImplementedError('Unknown {0} type: "{1}"'.format(
1173 cls, sub))
1174
1175 return class_map[cls][sub]
1176
1177 @staticmethod
1178 def load_one_yaml(path, fd, objs):
1179 '''Parse a single YAML file. Parsing occurs in three phases.
1180 In the first phase a factory method associated with each
1181 configuration file directive is invoked. These factory
1182 methods generate more factory methods. In the second
1183 phase the factory methods created in the first phase
1184 are invoked. In the last phase a callback is invoked on
1185 each object created in phase two. Typically the callback
1186 resolves references to other configuration file directives.'''
1187
1188 factory_objs = {}
1189 for x in yaml.safe_load(fd.read()) or {}:
1190
1191 # Create factory object for this config file directive.
1192 cls = x['class']
1193 sub = x.get(cls)
1194 if cls == 'group':
1195 cls = '{0}group'.format(sub)
1196
1197 factory = Everything.classmap(cls, sub)
1198 obj = factory(configfile=path, **x)
1199
1200 # For a given class of directive, validate the file
1201 # doesn't have any duplicate names (duplicates are
1202 # ok across config files).
1203 if exists(factory_objs, obj.cls, obj.name, config=path):
1204 raise NotUniqueError(path, cls, obj.name)
1205
1206 factory_objs.setdefault(cls, []).append(obj)
1207 objs.setdefault(cls, []).append(obj)
1208
1209 for cls, items in factory_objs.items():
1210 for obj in items:
1211 # Add objects for template consumption.
1212 obj.factory(objs)
1213
1214 @staticmethod
Brad Bishop34a7acd2017-04-27 23:47:23 -04001215 def load(args):
1216 '''Aggregate all the YAML in the input directory
1217 into a single aggregate.'''
1218
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001219 objs = {}
1220 yaml_files = filter(
1221 lambda x: x.endswith('.yaml'),
1222 os.listdir(args.inputdir))
Brad Bishop34a7acd2017-04-27 23:47:23 -04001223
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001224 yaml_files.sort()
Brad Bishop34a7acd2017-04-27 23:47:23 -04001225
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001226 for x in yaml_files:
1227 path = os.path.join(args.inputdir, x)
1228 with open(path, 'r') as fd:
1229 Everything.load_one_yaml(path, fd, objs)
1230
1231 # Configuration file directives reference each other via
1232 # the name attribute; however, when rendered the reference
1233 # is just an array index.
1234 #
1235 # At this point all objects have been created but references
Gunnar Mills78199b42017-10-25 16:30:18 -05001236 # have not been resolved to array indices. Instruct objects
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001237 # to do that now.
1238 for cls, items in objs.items():
1239 for obj in items:
1240 obj.setup(objs)
1241
1242 return Everything(**objs)
Brad Bishop34a7acd2017-04-27 23:47:23 -04001243
1244 def __init__(self, *a, **kw):
Brad Bishop0e7df132017-05-23 17:58:12 -04001245 self.pathmeta = kw.pop('path', [])
1246 self.paths = kw.pop('pathname', [])
1247 self.meta = kw.pop('meta', [])
1248 self.pathgroups = kw.pop('pathgroup', [])
Brad Bishope73b2c32017-05-23 18:01:54 -04001249 self.interfaces = kw.pop('interface', [])
1250 self.properties = kw.pop('property', [])
1251 self.propertynames = kw.pop('propertyname', [])
1252 self.propertygroups = kw.pop('propertygroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001253 self.instances = kw.pop('instance', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001254 self.pathinstances = kw.pop('pathinstance', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001255 self.instancegroups = kw.pop('instancegroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001256 self.pathinstancegroups = kw.pop('pathinstancegroup', [])
Brad Bishop4b916f12017-05-23 18:06:38 -04001257 self.watches = kw.pop('watch', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001258 self.pathwatches = kw.pop('pathwatch', [])
Brad Bishopc1283ae2017-05-20 21:42:38 -04001259 self.callbacks = kw.pop('callback', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001260 self.pathcallbacks = kw.pop('pathcallback', [])
Brad Bishop49e66172017-05-23 19:16:21 -04001261 self.callbackgroups = kw.pop('callbackgroup', [])
Marri Devender Rao80c70612018-04-12 09:22:55 -05001262 self.pathcallbackgroups = kw.pop('pathcallbackgroup', [])
Brad Bishop4041d722017-05-21 10:06:07 -04001263 self.conditions = kw.pop('condition', [])
Brad Bishop0e7df132017-05-23 17:58:12 -04001264
Brad Bishop34a7acd2017-04-27 23:47:23 -04001265 super(Everything, self).__init__(**kw)
1266
1267 def generate_cpp(self, loader):
1268 '''Render the template with the provided data.'''
Gunnar Millsd5faea32017-08-08 14:19:36 -05001269 # errors.hpp is used by generated.hpp to included any error.hpp files
1270 open('errors.hpp', 'w+')
1271
Brad Bishope3a01af2017-05-15 17:09:04 -04001272 with open(args.output, 'w') as fd:
Brad Bishop34a7acd2017-04-27 23:47:23 -04001273 fd.write(
1274 self.render(
1275 loader,
Brad Bishope3a01af2017-05-15 17:09:04 -04001276 args.template,
Brad Bishop0e7df132017-05-23 17:58:12 -04001277 meta=self.meta,
Brad Bishope73b2c32017-05-23 18:01:54 -04001278 properties=self.properties,
1279 propertynames=self.propertynames,
1280 interfaces=self.interfaces,
Brad Bishop0e7df132017-05-23 17:58:12 -04001281 paths=self.paths,
1282 pathmeta=self.pathmeta,
1283 pathgroups=self.pathgroups,
Brad Bishope73b2c32017-05-23 18:01:54 -04001284 propertygroups=self.propertygroups,
Brad Bishop4b916f12017-05-23 18:06:38 -04001285 instances=self.instances,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001286 pathinstances=self.pathinstances,
Brad Bishop4b916f12017-05-23 18:06:38 -04001287 watches=self.watches,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001288 pathwatches=self.pathwatches,
Brad Bishop4b916f12017-05-23 18:06:38 -04001289 instancegroups=self.instancegroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001290 pathinstancegroups=self.pathinstancegroups,
Brad Bishopc1283ae2017-05-20 21:42:38 -04001291 callbacks=self.callbacks,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001292 pathcallbacks=self.pathcallbacks,
Brad Bishop49e66172017-05-23 19:16:21 -04001293 callbackgroups=self.callbackgroups,
Marri Devender Rao80c70612018-04-12 09:22:55 -05001294 pathcallbackgroups=self.pathcallbackgroups,
Brad Bishop4041d722017-05-21 10:06:07 -04001295 conditions=self.conditions,
Brad Bishop34a7acd2017-04-27 23:47:23 -04001296 indent=Indent()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001297
1298if __name__ == '__main__':
Brad Bishop34a7acd2017-04-27 23:47:23 -04001299 script_dir = os.path.dirname(os.path.realpath(__file__))
1300 valid_commands = {
1301 'generate-cpp': 'generate_cpp',
1302 }
1303
1304 parser = ArgumentParser(
1305 description='Phosphor DBus Monitor (PDM) YAML '
1306 'scanner and code generator.')
1307
Matthew Barthdb440d42017-04-17 15:49:37 -05001308 parser.add_argument(
Brad Bishope3a01af2017-05-15 17:09:04 -04001309 "-o", "--out", dest="output",
1310 default='generated.cpp',
1311 help="Generated output file name and path.")
1312 parser.add_argument(
1313 '-t', '--template', dest='template',
Brad Bishop870c3fc2017-05-22 23:23:13 -04001314 default='generated.mako.hpp',
Brad Bishope3a01af2017-05-15 17:09:04 -04001315 help='The top level template to render.')
1316 parser.add_argument(
1317 '-p', '--template-path', dest='template_search',
1318 default=script_dir,
1319 help='The space delimited mako template search path.')
Brad Bishop34a7acd2017-04-27 23:47:23 -04001320 parser.add_argument(
1321 '-d', '--dir', dest='inputdir',
1322 default=os.path.join(script_dir, 'example'),
1323 help='Location of files to process.')
1324 parser.add_argument(
1325 'command', metavar='COMMAND', type=str,
1326 choices=valid_commands.keys(),
1327 help='%s.' % " | ".join(valid_commands.keys()))
Matthew Barthdb440d42017-04-17 15:49:37 -05001328
Brad Bishop34a7acd2017-04-27 23:47:23 -04001329 args = parser.parse_args()
1330
1331 if sys.version_info < (3, 0):
1332 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001333 directories=args.template_search.split(),
Brad Bishop34a7acd2017-04-27 23:47:23 -04001334 disable_unicode=True)
1335 else:
1336 lookup = mako.lookup.TemplateLookup(
Brad Bishope3a01af2017-05-15 17:09:04 -04001337 directories=args.template_search.split())
Brad Bishop05b0c1e2017-05-23 00:24:01 -04001338 try:
1339 function = getattr(
1340 Everything.load(args),
1341 valid_commands[args.command])
1342 function(lookup)
1343 except InvalidConfigError as e:
1344 sys.stdout.write('{0}: {1}\n\n'.format(e.config, e.msg))
1345 raise