blob: fef22ad72f5b8ff6a76b0e34add9c65288a7962d [file] [log] [blame]
Patrick Williams55878982020-04-03 15:24:57 -05001#!/usr/bin/env python3
Brad Bishopbf066a62016-10-19 08:09:44 -04002
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):
Patrick Williams55878982020-04-03 15:24:57 -050045 return list(self.dict.keys())
Deepak Kodihallief550b12017-08-03 14:00:17 -050046
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):
Patrick Williams55878982020-04-03 15:24:57 -0500207 self.sig = {x: y for x, y in kw.items()}
Brad Bishop75800cf2017-01-21 15:24:18 -0500208 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
Patrick Williams55878982020-04-03 15:24:57 -0500287 for path, interfaces in kw.pop('objs').items():
Brad Bishopdb92c282017-01-21 23:44:28 -0500288 key_o = TrivialArgument(
289 value=path,
290 type='string',
291 decorators=[Literal('string')])
292 value_i = []
293
Patrick Williams55878982020-04-03 15:24:57 -0500294 for interface, properties, in interfaces.items():
Brad Bishopdb92c282017-01-21 23:44:28 -0500295 key_i = TrivialArgument(value=interface, type='string')
296 value_p = []
Marri Devender Raofa23d702017-09-02 04:43:42 -0500297 if properties:
Patrick Williams55878982020-04-03 15:24:57 -0500298 for prop, value in properties.items():
Marri Devender Raofa23d702017-09-02 04:43:42 -0500299 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):
Patrick Williams55878982020-04-03 15:24:57 -0500531 yaml_files = [x for x in os.listdir(events_dir) if
532 x.endswith('.yaml')]
Brad Bishopa6fcd562017-02-03 11:00:27 -0500533
534 for x in yaml_files:
535 with open(os.path.join(events_dir, x), 'r') as fd:
536 for e in yaml.safe_load(fd.read()).get('events', {}):
537 events.append(e)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500538
Deepak Kodihallief550b12017-08-03 14:00:17 -0500539 interfaces, interface_composite = Everything.get_interfaces(
540 args.ifacesdir)
541 extra_interfaces, extra_interface_composite = \
542 Everything.get_interfaces(
543 os.path.join(args.inputdir, 'extra_interfaces.d'))
544 interface_composite.update(extra_interface_composite)
545 interface_composite = InterfaceComposite(interface_composite)
Matthew Barth979eb592018-10-05 15:29:26 -0500546 # Update busname if configured differenly than the default
547 busname = args.busname
Brad Bishop834989f2017-02-06 12:08:20 -0500548
Brad Bishop22cfbe62016-11-30 13:25:10 -0500549 return Everything(
550 *events,
Deepak Kodihallief550b12017-08-03 14:00:17 -0500551 interfaces=interfaces + extra_interfaces,
552 interface_composite=interface_composite)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500553
554 @staticmethod
Brad Bishop834989f2017-02-06 12:08:20 -0500555 def get_interfaces(targetdir):
556 '''Scan the interfaces directory for interfaces that PIM can create.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500557
Brad Bishop834989f2017-02-06 12:08:20 -0500558 yaml_files = []
Brad Bishop22cfbe62016-11-30 13:25:10 -0500559 interfaces = []
Deepak Kodihallief550b12017-08-03 14:00:17 -0500560 interface_composite = {}
Brad Bishopa6fcd562017-02-03 11:00:27 -0500561
Brad Bishop834989f2017-02-06 12:08:20 -0500562 if targetdir and os.path.exists(targetdir):
563 for directory, _, files in os.walk(targetdir):
564 if not files:
565 continue
566
Patrick Williams55878982020-04-03 15:24:57 -0500567 yaml_files += [os.path.relpath(
Brad Bishop834989f2017-02-06 12:08:20 -0500568 os.path.join(directory, f),
Patrick Williams55878982020-04-03 15:24:57 -0500569 targetdir) for f in [f for f in files if
570 f.endswith('.interface.yaml')]]
Brad Bishop834989f2017-02-06 12:08:20 -0500571
572 for y in yaml_files:
Marri Devender Rao06e3d502017-06-09 11:33:38 -0500573 # parse only phosphor dbus related interface files
574 if not y.startswith('xyz'):
575 continue
Brad Bishop834989f2017-02-06 12:08:20 -0500576 with open(os.path.join(targetdir, y)) as fd:
577 i = y.replace('.interface.yaml', '').replace(os.sep, '.')
578
579 # PIM can't create interfaces with methods.
Brad Bishop834989f2017-02-06 12:08:20 -0500580 parsed = yaml.safe_load(fd.read())
581 if parsed.get('methods', None):
582 continue
Deepak Kodihalli0b6ca102017-08-09 04:39:43 -0500583 # Cereal can't understand the type sdbusplus::object_path. This
584 # type is a wrapper around std::string. Ignore interfaces having
585 # a property of this type for now. The only interface that has a
586 # property of this type now is xyz.openbmc_project.Association,
587 # which is an unused interface. No inventory objects implement
588 # this interface.
589 # TODO via openbmc/openbmc#2123 : figure out how to make Cereal
590 # understand sdbusplus::object_path.
Marri Devender Raofa23d702017-09-02 04:43:42 -0500591 properties = parsed.get('properties', None)
592 if properties:
593 if any('path' in p['type'] for p in properties):
594 continue
Deepak Kodihallief550b12017-08-03 14:00:17 -0500595 interface_composite[i] = properties
Brad Bishop834989f2017-02-06 12:08:20 -0500596 interfaces.append(i)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500597
Deepak Kodihallief550b12017-08-03 14:00:17 -0500598 return interfaces, interface_composite
Brad Bishop22cfbe62016-11-30 13:25:10 -0500599
600 def __init__(self, *a, **kw):
601 self.interfaces = \
602 [Interface(x) for x in kw.pop('interfaces', [])]
Deepak Kodihallief550b12017-08-03 14:00:17 -0500603 self.interface_composite = \
604 kw.pop('interface_composite', {})
Brad Bishop22cfbe62016-11-30 13:25:10 -0500605 self.events = [
606 self.class_map[x['type']](**x) for x in a]
607 super(Everything, self).__init__(**kw)
608
Brad Bishop22cfbe62016-11-30 13:25:10 -0500609 def generate_cpp(self, loader):
610 '''Render the template with the provided events and interfaces.'''
611 with open(os.path.join(
612 args.outputdir,
613 'generated.cpp'), 'w') as fd:
614 fd.write(
615 self.render(
616 loader,
617 'generated.mako.cpp',
618 events=self.events,
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500619 interfaces=self.interfaces,
620 indent=Indent()))
Brad Bishopbf066a62016-10-19 08:09:44 -0400621
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500622 def generate_serialization(self, loader):
623 with open(os.path.join(
624 args.outputdir,
625 'gen_serialization.hpp'), 'w') as fd:
626 fd.write(
627 self.render(
628 loader,
629 'gen_serialization.mako.hpp',
630 interfaces=self.interfaces,
631 interface_composite=self.interface_composite))
632
Brad Bishop95dd98f2016-11-12 12:39:15 -0500633
634if __name__ == '__main__':
635 script_dir = os.path.dirname(os.path.realpath(__file__))
Brad Bishop14a9fe52016-11-12 12:51:26 -0500636 valid_commands = {
637 'generate-cpp': 'generate_cpp',
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500638 'generate-serialization': 'generate_serialization',
Brad Bishop22cfbe62016-11-30 13:25:10 -0500639 }
Brad Bishop95dd98f2016-11-12 12:39:15 -0500640
641 parser = argparse.ArgumentParser(
642 description='Phosphor Inventory Manager (PIM) YAML '
643 'scanner and code generator.')
644 parser.add_argument(
645 '-o', '--output-dir', dest='outputdir',
646 default='.', help='Output directory.')
647 parser.add_argument(
Brad Bishop834989f2017-02-06 12:08:20 -0500648 '-i', '--interfaces-dir', dest='ifacesdir',
649 help='Location of interfaces to be supported.')
650 parser.add_argument(
Brad Bishop95dd98f2016-11-12 12:39:15 -0500651 '-d', '--dir', dest='inputdir',
652 default=os.path.join(script_dir, 'example'),
653 help='Location of files to process.')
Brad Bishopf4666f52016-11-12 12:44:42 -0500654 parser.add_argument(
Matthew Barth979eb592018-10-05 15:29:26 -0500655 '-b', '--bus-name', dest='busname',
656 default='xyz.openbmc_project.Inventory.Manager',
657 help='Inventory manager busname.')
658 parser.add_argument(
Brad Bishopf4666f52016-11-12 12:44:42 -0500659 'command', metavar='COMMAND', type=str,
Patrick Williams55878982020-04-03 15:24:57 -0500660 choices=list(valid_commands.keys()),
661 help='%s.' % " | ".join(list(valid_commands.keys())))
Brad Bishop95dd98f2016-11-12 12:39:15 -0500662
663 args = parser.parse_args()
Brad Bishop22cfbe62016-11-30 13:25:10 -0500664
665 if sys.version_info < (3, 0):
666 lookup = mako.lookup.TemplateLookup(
667 directories=[script_dir],
668 disable_unicode=True)
669 else:
670 lookup = mako.lookup.TemplateLookup(
671 directories=[script_dir])
672
673 function = getattr(
674 Everything.load(args),
675 valid_commands[args.command])
676 function(lookup)
Brad Bishop95dd98f2016-11-12 12:39:15 -0500677
678
Brad Bishopbf066a62016-10-19 08:09:44 -0400679# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4