blob: c7ed93350de3706371312adb7f3dd371c3ae3565 [file] [log] [blame]
Brad Bishopbf066a62016-10-19 08:09:44 -04001#!/usr/bin/env python
2
Brad Bishop22cfbe62016-11-30 13:25:10 -05003'''Phosphor Inventory Manager 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
Brad Bishopbf066a62016-10-19 08:09:44 -040018import sys
19import os
Brad Bishopbf066a62016-10-19 08:09:44 -040020import argparse
Brad Bishopcfb3c892016-11-12 11:43:37 -050021import subprocess
Brad Bishop22cfbe62016-11-30 13:25:10 -050022import yaml
23import mako.lookup
24import sdbusplus.property
25from sdbusplus.namedelement import NamedElement
26from sdbusplus.renderer import Renderer
Brad Bishopbf066a62016-10-19 08:09:44 -040027
28
Matthew Barth979eb592018-10-05 15:29:26 -050029# Global busname for use within classes where necessary
30busname = "xyz.openbmc_project.Inventory.Manager"
31
32
Brad Bishop9b5a12f2017-01-21 14:42:11 -050033def cppTypeName(yaml_type):
34 ''' Convert yaml types to cpp types.'''
35 return sdbusplus.property.Property(type=yaml_type).cppTypeName
36
37
Deepak Kodihallief550b12017-08-03 14:00:17 -050038class InterfaceComposite(object):
39 '''Compose interface properties.'''
40
41 def __init__(self, dict):
42 self.dict = dict
43
Deepak Kodihallief550b12017-08-03 14:00:17 -050044 def interfaces(self):
45 return self.dict.keys()
46
47 def names(self, interface):
Marri Devender Raofa23d702017-09-02 04:43:42 -050048 names = []
49 if self.dict[interface]:
Brad Bishop38646592019-04-12 18:05:45 +000050 names = [NamedElement(name=x["name"]) for x in self.dict[interface]]
Deepak Kodihallief550b12017-08-03 14:00:17 -050051 return names
52
53
Brad Bishop22cfbe62016-11-30 13:25:10 -050054class Interface(list):
55 '''Provide various interface transformations.'''
56
57 def __init__(self, iface):
58 super(Interface, self).__init__(iface.split('.'))
59
60 def namespace(self):
61 '''Represent as an sdbusplus namespace.'''
62 return '::'.join(['sdbusplus'] + self[:-1] + ['server', self[-1]])
63
64 def header(self):
65 '''Represent as an sdbusplus server binding header.'''
66 return os.sep.join(self + ['server.hpp'])
67
68 def __str__(self):
69 return '.'.join(self)
Brad Bishopbf066a62016-10-19 08:09:44 -040070
Brad Bishopcfb3c892016-11-12 11:43:37 -050071
Brad Bishop9b5a12f2017-01-21 14:42:11 -050072class Indent(object):
73 '''Help templates be depth agnostic.'''
74
75 def __init__(self, depth=0):
76 self.depth = depth
77
78 def __add__(self, depth):
79 return Indent(self.depth + depth)
80
81 def __call__(self, depth):
82 '''Render an indent at the current depth plus depth.'''
83 return 4*' '*(depth + self.depth)
84
85
86class Template(NamedElement):
87 '''Associate a template name with its namespace.'''
88
89 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -050090 self.namespace = kw.pop('namespace', [])
Brad Bishop9b5a12f2017-01-21 14:42:11 -050091 super(Template, self).__init__(**kw)
92
93 def qualified(self):
94 return '::'.join(self.namespace + [self.name])
95
96
Brad Bishopdb9b3252017-01-30 08:58:40 -050097class FixBool(object):
98 '''Un-capitalize booleans.'''
99
100 def __call__(self, arg):
101 return '{0}'.format(arg.lower())
102
103
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500104class Quote(object):
105 '''Decorate an argument by quoting it.'''
106
107 def __call__(self, arg):
108 return '"{0}"'.format(arg)
109
110
111class Cast(object):
112 '''Decorate an argument by casting it.'''
113
114 def __init__(self, cast, target):
115 '''cast is the cast type (static, const, etc...).
116 target is the cast target type.'''
117 self.cast = cast
118 self.target = target
119
120 def __call__(self, arg):
121 return '{0}_cast<{1}>({2})'.format(self.cast, self.target, arg)
122
123
124class Literal(object):
125 '''Decorate an argument with a literal operator.'''
126
Brad Bishop134d2cb2017-02-23 12:37:56 -0500127 integer_types = [
128 'int8',
129 'int16',
130 'int32',
131 'int64',
132 'uint8',
133 'uint16',
134 'uint32',
135 'uint64'
136 ]
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500137
138 def __init__(self, type):
139 self.type = type
140
141 def __call__(self, arg):
Brad Bishop134d2cb2017-02-23 12:37:56 -0500142 if 'uint' in self.type:
143 arg = '{0}ull'.format(arg)
144 elif 'int' in self.type:
145 arg = '{0}ll'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500146
Brad Bishop134d2cb2017-02-23 12:37:56 -0500147 if self.type in self.integer_types:
148 return Cast('static', '{0}_t'.format(self.type))(arg)
149
150 if self.type == 'string':
151 return '{0}s'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500152
153 return arg
154
155
Brad Bishop75800cf2017-01-21 15:24:18 -0500156class Argument(NamedElement, Renderer):
157 '''Define argument type inteface.'''
158
159 def __init__(self, **kw):
160 self.type = kw.pop('type', None)
161 super(Argument, self).__init__(**kw)
162
163 def argument(self, loader, indent):
164 raise NotImplementedError
165
166
167class TrivialArgument(Argument):
168 '''Non-array type arguments.'''
Brad Bishop14a9fe52016-11-12 12:51:26 -0500169
Brad Bishop22cfbe62016-11-30 13:25:10 -0500170 def __init__(self, **kw):
171 self.value = kw.pop('value')
Brad Bishop75800cf2017-01-21 15:24:18 -0500172 self.decorators = kw.pop('decorators', [])
173 if kw.get('type', None) == 'string':
174 self.decorators.insert(0, Quote())
Brad Bishopdb9b3252017-01-30 08:58:40 -0500175 if kw.get('type', None) == 'boolean':
176 self.decorators.insert(0, FixBool())
Brad Bishop75800cf2017-01-21 15:24:18 -0500177
Brad Bishop75800cf2017-01-21 15:24:18 -0500178 super(TrivialArgument, self).__init__(**kw)
179
180 def argument(self, loader, indent):
181 a = str(self.value)
182 for d in self.decorators:
183 a = d(a)
184
185 return a
Brad Bishop14a9fe52016-11-12 12:51:26 -0500186
Brad Bishop14a9fe52016-11-12 12:51:26 -0500187
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500188class InitializerList(Argument):
189 '''Initializer list arguments.'''
190
191 def __init__(self, **kw):
192 self.values = kw.pop('values')
193 super(InitializerList, self).__init__(**kw)
194
195 def argument(self, loader, indent):
196 return self.render(
197 loader,
198 'argument.mako.cpp',
199 arg=self,
200 indent=indent)
201
202
Brad Bishop75800cf2017-01-21 15:24:18 -0500203class DbusSignature(Argument):
204 '''DBus signature arguments.'''
205
206 def __init__(self, **kw):
207 self.sig = {x: y for x, y in kw.iteritems()}
208 kw.clear()
209 super(DbusSignature, self).__init__(**kw)
210
211 def argument(self, loader, indent):
212 return self.render(
213 loader,
214 'signature.mako.cpp',
215 signature=self,
216 indent=indent)
217
218
Brad Bishopc93bcc92017-01-21 16:23:39 -0500219class MethodCall(Argument):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500220 '''Render syntatically correct c++ method calls.'''
221
222 def __init__(self, **kw):
223 self.namespace = kw.pop('namespace', [])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500224 self.templates = kw.pop('templates', [])
225 self.args = kw.pop('args', [])
Brad Bishop22cfbe62016-11-30 13:25:10 -0500226 super(MethodCall, self).__init__(**kw)
227
Brad Bishopcab2bdd2017-01-21 15:00:54 -0500228 def call(self, loader, indent):
229 return self.render(
230 loader,
231 'method.mako.cpp',
232 method=self,
233 indent=indent)
234
235 def argument(self, loader, indent):
236 return self.call(loader, indent)
237
Brad Bishop14a9fe52016-11-12 12:51:26 -0500238
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500239class Vector(MethodCall):
240 '''Convenience type for vectors.'''
241
242 def __init__(self, **kw):
243 kw['name'] = 'vector'
244 kw['namespace'] = ['std']
245 kw['args'] = [InitializerList(values=kw.pop('args'))]
246 super(Vector, self).__init__(**kw)
247
248
Brad Bishopc1f47982017-02-09 01:27:38 -0500249class Filter(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500250 '''Convenience type for filters'''
Brad Bishopbf066a62016-10-19 08:09:44 -0400251
Brad Bishop22cfbe62016-11-30 13:25:10 -0500252 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500253 kw['name'] = 'make_filter'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500254 super(Filter, self).__init__(**kw)
Brad Bishopbf066a62016-10-19 08:09:44 -0400255
Brad Bishop0a6a4792016-11-12 12:10:07 -0500256
Brad Bishopc1f47982017-02-09 01:27:38 -0500257class Action(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500258 '''Convenience type for actions'''
Brad Bishop561a5652016-10-26 21:13:32 -0500259
Brad Bishop22cfbe62016-11-30 13:25:10 -0500260 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500261 kw['name'] = 'make_action'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500262 super(Action, self).__init__(**kw)
Brad Bishop92665b22016-10-26 20:51:16 -0500263
Brad Bishopcfb3c892016-11-12 11:43:37 -0500264
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500265class PathCondition(MethodCall):
266 '''Convenience type for path conditions'''
267
268 def __init__(self, **kw):
269 kw['name'] = 'make_path_condition'
270 super(PathCondition, self).__init__(**kw)
271
272
Matthew Barth979eb592018-10-05 15:29:26 -0500273class GetProperty(MethodCall):
274 '''Convenience type for getting inventory properties'''
275
276 def __init__(self, **kw):
277 kw['name'] = 'make_get_property'
278 super(GetProperty, self).__init__(**kw)
279
280
Brad Bishopc1f47982017-02-09 01:27:38 -0500281class CreateObjects(MethodCall):
282 '''Assemble a createObjects functor.'''
Brad Bishopdb92c282017-01-21 23:44:28 -0500283
284 def __init__(self, **kw):
285 objs = []
286
287 for path, interfaces in kw.pop('objs').iteritems():
288 key_o = TrivialArgument(
289 value=path,
290 type='string',
291 decorators=[Literal('string')])
292 value_i = []
293
294 for interface, properties, in interfaces.iteritems():
295 key_i = TrivialArgument(value=interface, type='string')
296 value_p = []
Marri Devender Raofa23d702017-09-02 04:43:42 -0500297 if properties:
298 for prop, value in properties.iteritems():
299 key_p = TrivialArgument(value=prop, type='string')
300 value_v = TrivialArgument(
301 decorators=[Literal(value.get('type', None))],
302 **value)
303 value_p.append(InitializerList(values=[key_p, value_v]))
Brad Bishopdb92c282017-01-21 23:44:28 -0500304
305 value_p = InitializerList(values=value_p)
306 value_i.append(InitializerList(values=[key_i, value_p]))
307
308 value_i = InitializerList(values=value_i)
309 objs.append(InitializerList(values=[key_o, value_i]))
310
311 kw['args'] = [InitializerList(values=objs)]
Brad Bishopc1f47982017-02-09 01:27:38 -0500312 kw['namespace'] = ['functor']
Brad Bishopdb92c282017-01-21 23:44:28 -0500313 super(CreateObjects, self).__init__(**kw)
314
315
Brad Bishopc1f47982017-02-09 01:27:38 -0500316class DestroyObjects(MethodCall):
317 '''Assemble a destroyObject functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500318
319 def __init__(self, **kw):
Brad Bishop7b7e7122017-01-21 21:21:46 -0500320 values = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500321 conditions = [
322 Event.functor_map[
323 x['name']](**x) for x in kw.pop('conditions', [])]
324 conditions = [PathCondition(args=[x]) for x in conditions]
Brad Bishop7b7e7122017-01-21 21:21:46 -0500325 args = [InitializerList(
326 values=[TrivialArgument(**x) for x in values])]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500327 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500328 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500329 kw['namespace'] = ['functor']
Brad Bishop7b7e7122017-01-21 21:21:46 -0500330 super(DestroyObjects, self).__init__(**kw)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500331
332
Brad Bishopc1f47982017-02-09 01:27:38 -0500333class SetProperty(MethodCall):
334 '''Assemble a setProperty functor.'''
Brad Bishope2e402f2016-11-30 18:00:17 -0500335
336 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500337 args = []
338
339 value = kw.pop('value')
340 prop = kw.pop('property')
341 iface = kw.pop('interface')
342 iface = Interface(iface)
343 namespace = iface.namespace().split('::')[:-1]
344 name = iface[-1]
345 t = Template(namespace=namespace, name=iface[-1])
346
Brad Bishope2e402f2016-11-30 18:00:17 -0500347 member = '&%s' % '::'.join(
Brad Bishopc93bcc92017-01-21 16:23:39 -0500348 namespace + [name, NamedElement(name=prop).camelCase])
349 member_type = cppTypeName(value['type'])
350 member_cast = '{0} ({1}::*)({0})'.format(member_type, t.qualified())
Brad Bishope2e402f2016-11-30 18:00:17 -0500351
Brad Bishop02ca0212017-01-28 23:25:58 -0500352 paths = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
353 args.append(InitializerList(
354 values=[TrivialArgument(**x) for x in paths]))
355
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500356 conditions = [
357 Event.functor_map[
358 x['name']](**x) for x in kw.pop('conditions', [])]
359 conditions = [PathCondition(args=[x]) for x in conditions]
360
361 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500362 args.append(TrivialArgument(value=str(iface), type='string'))
363 args.append(TrivialArgument(
364 value=member, decorators=[Cast('static', member_cast)]))
365 args.append(TrivialArgument(**value))
Brad Bishope2e402f2016-11-30 18:00:17 -0500366
Brad Bishopc93bcc92017-01-21 16:23:39 -0500367 kw['templates'] = [Template(name=name, namespace=namespace)]
368 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500369 kw['namespace'] = ['functor']
Brad Bishope2e402f2016-11-30 18:00:17 -0500370 super(SetProperty, self).__init__(**kw)
371
372
Brad Bishopc1f47982017-02-09 01:27:38 -0500373class PropertyChanged(MethodCall):
374 '''Assemble a propertyChanged functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500375
376 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500377 args = []
378 args.append(TrivialArgument(value=kw.pop('interface'), type='string'))
379 args.append(TrivialArgument(value=kw.pop('property'), type='string'))
380 args.append(TrivialArgument(
381 decorators=[
382 Literal(kw['value'].get('type', None))], **kw.pop('value')))
383 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500384 kw['namespace'] = ['functor']
Brad Bishop22cfbe62016-11-30 13:25:10 -0500385 super(PropertyChanged, self).__init__(**kw)
386
387
Brad Bishopc1f47982017-02-09 01:27:38 -0500388class PropertyIs(MethodCall):
389 '''Assemble a propertyIs functor.'''
Brad Bishop040e18b2017-01-21 22:04:00 -0500390
391 def __init__(self, **kw):
392 args = []
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500393 path = kw.pop('path', None)
394 if not path:
395 path = TrivialArgument(value='nullptr')
396 else:
397 path = TrivialArgument(value=path, type='string')
398
399 args.append(path)
Matthew Barth979eb592018-10-05 15:29:26 -0500400 iface = TrivialArgument(value=kw.pop('interface'), type='string')
401 args.append(iface)
402 prop = TrivialArgument(value=kw.pop('property'), type='string')
403 args.append(prop)
Brad Bishop040e18b2017-01-21 22:04:00 -0500404 args.append(TrivialArgument(
405 decorators=[
406 Literal(kw['value'].get('type', None))], **kw.pop('value')))
407
408 service = kw.pop('service', None)
409 if service:
410 args.append(TrivialArgument(value=service, type='string'))
411
Matthew Barth979eb592018-10-05 15:29:26 -0500412 dbusMember = kw.pop('dbusMember', None)
413 if dbusMember:
414 # Inventory manager's service name is required
415 if not service or service != busname:
416 args.append(TrivialArgument(value=busname, type='string'))
417
418 gpArgs = []
419 gpArgs.append(path)
420 gpArgs.append(iface)
421 # Prepend '&' and append 'getPropertyByName' function on dbusMember
422 gpArgs.append(TrivialArgument(
423 value='&'+dbusMember+'::getPropertyByName'))
424 gpArgs.append(prop)
425 fArg = MethodCall(
426 name='getProperty',
427 namespace=['functor'],
428 templates=[Template(
429 name=dbusMember,
430 namespace=[])],
431 args=gpArgs)
432
433 # Append getProperty functor
434 args.append(GetProperty(
435 templates=[Template(
436 name=dbusMember+'::PropertiesVariant',
437 namespace=[])],
438 args=[fArg]))
439
Brad Bishop040e18b2017-01-21 22:04:00 -0500440 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500441 kw['namespace'] = ['functor']
Brad Bishop040e18b2017-01-21 22:04:00 -0500442 super(PropertyIs, self).__init__(**kw)
443
444
Brad Bishopc93bcc92017-01-21 16:23:39 -0500445class Event(MethodCall):
446 '''Assemble an inventory manager event.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500447
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500448 functor_map = {
Brad Bishop7b7e7122017-01-21 21:21:46 -0500449 'destroyObjects': DestroyObjects,
Brad Bishopdb92c282017-01-21 23:44:28 -0500450 'createObjects': CreateObjects,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500451 'propertyChangedTo': PropertyChanged,
Brad Bishop040e18b2017-01-21 22:04:00 -0500452 'propertyIs': PropertyIs,
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500453 'setProperty': SetProperty,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500454 }
455
Brad Bishop22cfbe62016-11-30 13:25:10 -0500456 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500457 self.summary = kw.pop('name')
458
459 filters = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500460 self.functor_map[x['name']](**x) for x in kw.pop('filters', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500461 filters = [Filter(args=[x]) for x in filters]
Brad Bishop064c94a2017-01-21 21:33:30 -0500462 filters = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500463 templates=[Template(name='Filter', namespace=[])],
Brad Bishop064c94a2017-01-21 21:33:30 -0500464 args=filters)
Brad Bishopc93bcc92017-01-21 16:23:39 -0500465
466 event = MethodCall(
467 name='make_shared',
468 namespace=['std'],
469 templates=[Template(
470 name=kw.pop('event'),
471 namespace=kw.pop('event_namespace', []))],
Brad Bishop064c94a2017-01-21 21:33:30 -0500472 args=kw.pop('event_args', []) + [filters])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500473
474 events = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500475 templates=[Template(name='EventBasePtr', namespace=[])],
Brad Bishopc93bcc92017-01-21 16:23:39 -0500476 args=[event])
477
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500478 action_type = Template(name='Action', namespace=[])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500479 action_args = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500480 self.functor_map[x['name']](**x) for x in kw.pop('actions', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500481 action_args = [Action(args=[x]) for x in action_args]
Brad Bishopc93bcc92017-01-21 16:23:39 -0500482 actions = Vector(
483 templates=[action_type],
484 args=action_args)
485
486 kw['name'] = 'make_tuple'
487 kw['namespace'] = ['std']
488 kw['args'] = [events, actions]
Brad Bishop22cfbe62016-11-30 13:25:10 -0500489 super(Event, self).__init__(**kw)
Brad Bishopcfb3c892016-11-12 11:43:37 -0500490
Brad Bishopcfb3c892016-11-12 11:43:37 -0500491
Brad Bishop22cfbe62016-11-30 13:25:10 -0500492class MatchEvent(Event):
493 '''Associate one or more dbus signal match signatures with
494 a filter.'''
495
Brad Bishop22cfbe62016-11-30 13:25:10 -0500496 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500497 kw['event'] = 'DbusSignal'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500498 kw['event_namespace'] = []
Brad Bishopc93bcc92017-01-21 16:23:39 -0500499 kw['event_args'] = [
500 DbusSignature(**x) for x in kw.pop('signatures', [])]
501
Brad Bishop22cfbe62016-11-30 13:25:10 -0500502 super(MatchEvent, self).__init__(**kw)
503
504
Brad Bishop828df832017-01-21 22:20:43 -0500505class StartupEvent(Event):
506 '''Assemble a startup event.'''
507
508 def __init__(self, **kw):
509 kw['event'] = 'StartupEvent'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500510 kw['event_namespace'] = []
Brad Bishop828df832017-01-21 22:20:43 -0500511 super(StartupEvent, self).__init__(**kw)
512
513
Brad Bishop22cfbe62016-11-30 13:25:10 -0500514class Everything(Renderer):
515 '''Parse/render entry point.'''
516
517 class_map = {
518 'match': MatchEvent,
Brad Bishop828df832017-01-21 22:20:43 -0500519 'startup': StartupEvent,
Brad Bishop22cfbe62016-11-30 13:25:10 -0500520 }
521
522 @staticmethod
523 def load(args):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500524 # Aggregate all the event YAML in the events.d directory
525 # into a single list of events.
526
Brad Bishop22cfbe62016-11-30 13:25:10 -0500527 events = []
Brad Bishopa6fcd562017-02-03 11:00:27 -0500528 events_dir = os.path.join(args.inputdir, 'events.d')
529
530 if os.path.exists(events_dir):
531 yaml_files = filter(
532 lambda x: x.endswith('.yaml'),
533 os.listdir(events_dir))
534
535 for x in yaml_files:
536 with open(os.path.join(events_dir, x), 'r') as fd:
537 for e in yaml.safe_load(fd.read()).get('events', {}):
538 events.append(e)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500539
Deepak Kodihallief550b12017-08-03 14:00:17 -0500540 interfaces, interface_composite = Everything.get_interfaces(
541 args.ifacesdir)
542 extra_interfaces, extra_interface_composite = \
543 Everything.get_interfaces(
544 os.path.join(args.inputdir, 'extra_interfaces.d'))
545 interface_composite.update(extra_interface_composite)
546 interface_composite = InterfaceComposite(interface_composite)
Matthew Barth979eb592018-10-05 15:29:26 -0500547 # Update busname if configured differenly than the default
548 busname = args.busname
Brad Bishop834989f2017-02-06 12:08:20 -0500549
Brad Bishop22cfbe62016-11-30 13:25:10 -0500550 return Everything(
551 *events,
Deepak Kodihallief550b12017-08-03 14:00:17 -0500552 interfaces=interfaces + extra_interfaces,
553 interface_composite=interface_composite)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500554
555 @staticmethod
Brad Bishop834989f2017-02-06 12:08:20 -0500556 def get_interfaces(targetdir):
557 '''Scan the interfaces directory for interfaces that PIM can create.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500558
Brad Bishop834989f2017-02-06 12:08:20 -0500559 yaml_files = []
Brad Bishop22cfbe62016-11-30 13:25:10 -0500560 interfaces = []
Deepak Kodihallief550b12017-08-03 14:00:17 -0500561 interface_composite = {}
Brad Bishopa6fcd562017-02-03 11:00:27 -0500562
Brad Bishop834989f2017-02-06 12:08:20 -0500563 if targetdir and os.path.exists(targetdir):
564 for directory, _, files in os.walk(targetdir):
565 if not files:
566 continue
567
568 yaml_files += map(
569 lambda f: os.path.relpath(
570 os.path.join(directory, f),
571 targetdir),
572 filter(lambda f: f.endswith('.interface.yaml'), files))
573
574 for y in yaml_files:
Marri Devender Rao06e3d502017-06-09 11:33:38 -0500575 # parse only phosphor dbus related interface files
576 if not y.startswith('xyz'):
577 continue
Brad Bishop834989f2017-02-06 12:08:20 -0500578 with open(os.path.join(targetdir, y)) as fd:
579 i = y.replace('.interface.yaml', '').replace(os.sep, '.')
580
581 # PIM can't create interfaces with methods.
Brad Bishop834989f2017-02-06 12:08:20 -0500582 parsed = yaml.safe_load(fd.read())
583 if parsed.get('methods', None):
584 continue
Deepak Kodihalli0b6ca102017-08-09 04:39:43 -0500585 # Cereal can't understand the type sdbusplus::object_path. This
586 # type is a wrapper around std::string. Ignore interfaces having
587 # a property of this type for now. The only interface that has a
588 # property of this type now is xyz.openbmc_project.Association,
589 # which is an unused interface. No inventory objects implement
590 # this interface.
591 # TODO via openbmc/openbmc#2123 : figure out how to make Cereal
592 # understand sdbusplus::object_path.
Marri Devender Raofa23d702017-09-02 04:43:42 -0500593 properties = parsed.get('properties', None)
594 if properties:
595 if any('path' in p['type'] for p in properties):
596 continue
Deepak Kodihallief550b12017-08-03 14:00:17 -0500597 interface_composite[i] = properties
Brad Bishop834989f2017-02-06 12:08:20 -0500598 interfaces.append(i)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500599
Deepak Kodihallief550b12017-08-03 14:00:17 -0500600 return interfaces, interface_composite
Brad Bishop22cfbe62016-11-30 13:25:10 -0500601
602 def __init__(self, *a, **kw):
603 self.interfaces = \
604 [Interface(x) for x in kw.pop('interfaces', [])]
Deepak Kodihallief550b12017-08-03 14:00:17 -0500605 self.interface_composite = \
606 kw.pop('interface_composite', {})
Brad Bishop22cfbe62016-11-30 13:25:10 -0500607 self.events = [
608 self.class_map[x['type']](**x) for x in a]
609 super(Everything, self).__init__(**kw)
610
Brad Bishop22cfbe62016-11-30 13:25:10 -0500611 def generate_cpp(self, loader):
612 '''Render the template with the provided events and interfaces.'''
613 with open(os.path.join(
614 args.outputdir,
615 'generated.cpp'), 'w') as fd:
616 fd.write(
617 self.render(
618 loader,
619 'generated.mako.cpp',
620 events=self.events,
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500621 interfaces=self.interfaces,
622 indent=Indent()))
Brad Bishopbf066a62016-10-19 08:09:44 -0400623
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500624 def generate_serialization(self, loader):
625 with open(os.path.join(
626 args.outputdir,
627 'gen_serialization.hpp'), 'w') as fd:
628 fd.write(
629 self.render(
630 loader,
631 'gen_serialization.mako.hpp',
632 interfaces=self.interfaces,
633 interface_composite=self.interface_composite))
634
Brad Bishop95dd98f2016-11-12 12:39:15 -0500635
636if __name__ == '__main__':
637 script_dir = os.path.dirname(os.path.realpath(__file__))
Brad Bishop14a9fe52016-11-12 12:51:26 -0500638 valid_commands = {
639 'generate-cpp': 'generate_cpp',
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500640 'generate-serialization': 'generate_serialization',
Brad Bishop22cfbe62016-11-30 13:25:10 -0500641 }
Brad Bishop95dd98f2016-11-12 12:39:15 -0500642
643 parser = argparse.ArgumentParser(
644 description='Phosphor Inventory Manager (PIM) YAML '
645 'scanner and code generator.')
646 parser.add_argument(
647 '-o', '--output-dir', dest='outputdir',
648 default='.', help='Output directory.')
649 parser.add_argument(
Brad Bishop834989f2017-02-06 12:08:20 -0500650 '-i', '--interfaces-dir', dest='ifacesdir',
651 help='Location of interfaces to be supported.')
652 parser.add_argument(
Brad Bishop95dd98f2016-11-12 12:39:15 -0500653 '-d', '--dir', dest='inputdir',
654 default=os.path.join(script_dir, 'example'),
655 help='Location of files to process.')
Brad Bishopf4666f52016-11-12 12:44:42 -0500656 parser.add_argument(
Matthew Barth979eb592018-10-05 15:29:26 -0500657 '-b', '--bus-name', dest='busname',
658 default='xyz.openbmc_project.Inventory.Manager',
659 help='Inventory manager busname.')
660 parser.add_argument(
Brad Bishopf4666f52016-11-12 12:44:42 -0500661 'command', metavar='COMMAND', type=str,
662 choices=valid_commands.keys(),
Brad Bishopc029f6a2017-01-18 19:43:26 -0500663 help='%s.' % " | ".join(valid_commands.keys()))
Brad Bishop95dd98f2016-11-12 12:39:15 -0500664
665 args = parser.parse_args()
Brad Bishop22cfbe62016-11-30 13:25:10 -0500666
667 if sys.version_info < (3, 0):
668 lookup = mako.lookup.TemplateLookup(
669 directories=[script_dir],
670 disable_unicode=True)
671 else:
672 lookup = mako.lookup.TemplateLookup(
673 directories=[script_dir])
674
675 function = getattr(
676 Everything.load(args),
677 valid_commands[args.command])
678 function(lookup)
Brad Bishop95dd98f2016-11-12 12:39:15 -0500679
680
Brad Bishopbf066a62016-10-19 08:09:44 -0400681# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4