blob: 7c9ee5383d82bbca50081d3d86eac7c22da82a66 [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
44 def properties(self, interface):
45 return self.dict[interface]
46
47 def interfaces(self):
48 return self.dict.keys()
49
50 def names(self, interface):
Marri Devender Raofa23d702017-09-02 04:43:42 -050051 names = []
52 if self.dict[interface]:
53 names = [x["name"] for x in self.dict[interface]]
Deepak Kodihallief550b12017-08-03 14:00:17 -050054 return names
55
56
Brad Bishop22cfbe62016-11-30 13:25:10 -050057class Interface(list):
58 '''Provide various interface transformations.'''
59
60 def __init__(self, iface):
61 super(Interface, self).__init__(iface.split('.'))
62
63 def namespace(self):
64 '''Represent as an sdbusplus namespace.'''
65 return '::'.join(['sdbusplus'] + self[:-1] + ['server', self[-1]])
66
67 def header(self):
68 '''Represent as an sdbusplus server binding header.'''
69 return os.sep.join(self + ['server.hpp'])
70
71 def __str__(self):
72 return '.'.join(self)
Brad Bishopbf066a62016-10-19 08:09:44 -040073
Brad Bishopcfb3c892016-11-12 11:43:37 -050074
Brad Bishop9b5a12f2017-01-21 14:42:11 -050075class Indent(object):
76 '''Help templates be depth agnostic.'''
77
78 def __init__(self, depth=0):
79 self.depth = depth
80
81 def __add__(self, depth):
82 return Indent(self.depth + depth)
83
84 def __call__(self, depth):
85 '''Render an indent at the current depth plus depth.'''
86 return 4*' '*(depth + self.depth)
87
88
89class Template(NamedElement):
90 '''Associate a template name with its namespace.'''
91
92 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -050093 self.namespace = kw.pop('namespace', [])
Brad Bishop9b5a12f2017-01-21 14:42:11 -050094 super(Template, self).__init__(**kw)
95
96 def qualified(self):
97 return '::'.join(self.namespace + [self.name])
98
99
Brad Bishopdb9b3252017-01-30 08:58:40 -0500100class FixBool(object):
101 '''Un-capitalize booleans.'''
102
103 def __call__(self, arg):
104 return '{0}'.format(arg.lower())
105
106
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500107class Quote(object):
108 '''Decorate an argument by quoting it.'''
109
110 def __call__(self, arg):
111 return '"{0}"'.format(arg)
112
113
114class Cast(object):
115 '''Decorate an argument by casting it.'''
116
117 def __init__(self, cast, target):
118 '''cast is the cast type (static, const, etc...).
119 target is the cast target type.'''
120 self.cast = cast
121 self.target = target
122
123 def __call__(self, arg):
124 return '{0}_cast<{1}>({2})'.format(self.cast, self.target, arg)
125
126
127class Literal(object):
128 '''Decorate an argument with a literal operator.'''
129
Brad Bishop134d2cb2017-02-23 12:37:56 -0500130 integer_types = [
131 'int8',
132 'int16',
133 'int32',
134 'int64',
135 'uint8',
136 'uint16',
137 'uint32',
138 'uint64'
139 ]
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500140
141 def __init__(self, type):
142 self.type = type
143
144 def __call__(self, arg):
Brad Bishop134d2cb2017-02-23 12:37:56 -0500145 if 'uint' in self.type:
146 arg = '{0}ull'.format(arg)
147 elif 'int' in self.type:
148 arg = '{0}ll'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500149
Brad Bishop134d2cb2017-02-23 12:37:56 -0500150 if self.type in self.integer_types:
151 return Cast('static', '{0}_t'.format(self.type))(arg)
152
153 if self.type == 'string':
154 return '{0}s'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500155
156 return arg
157
158
Brad Bishop75800cf2017-01-21 15:24:18 -0500159class Argument(NamedElement, Renderer):
160 '''Define argument type inteface.'''
161
162 def __init__(self, **kw):
163 self.type = kw.pop('type', None)
164 super(Argument, self).__init__(**kw)
165
166 def argument(self, loader, indent):
167 raise NotImplementedError
168
169
170class TrivialArgument(Argument):
171 '''Non-array type arguments.'''
Brad Bishop14a9fe52016-11-12 12:51:26 -0500172
Brad Bishop22cfbe62016-11-30 13:25:10 -0500173 def __init__(self, **kw):
174 self.value = kw.pop('value')
Brad Bishop75800cf2017-01-21 15:24:18 -0500175 self.decorators = kw.pop('decorators', [])
176 if kw.get('type', None) == 'string':
177 self.decorators.insert(0, Quote())
Brad Bishopdb9b3252017-01-30 08:58:40 -0500178 if kw.get('type', None) == 'boolean':
179 self.decorators.insert(0, FixBool())
Brad Bishop75800cf2017-01-21 15:24:18 -0500180
Brad Bishop75800cf2017-01-21 15:24:18 -0500181 super(TrivialArgument, self).__init__(**kw)
182
183 def argument(self, loader, indent):
184 a = str(self.value)
185 for d in self.decorators:
186 a = d(a)
187
188 return a
Brad Bishop14a9fe52016-11-12 12:51:26 -0500189
Brad Bishop14a9fe52016-11-12 12:51:26 -0500190
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500191class InitializerList(Argument):
192 '''Initializer list arguments.'''
193
194 def __init__(self, **kw):
195 self.values = kw.pop('values')
196 super(InitializerList, self).__init__(**kw)
197
198 def argument(self, loader, indent):
199 return self.render(
200 loader,
201 'argument.mako.cpp',
202 arg=self,
203 indent=indent)
204
205
Brad Bishop75800cf2017-01-21 15:24:18 -0500206class DbusSignature(Argument):
207 '''DBus signature arguments.'''
208
209 def __init__(self, **kw):
210 self.sig = {x: y for x, y in kw.iteritems()}
211 kw.clear()
212 super(DbusSignature, self).__init__(**kw)
213
214 def argument(self, loader, indent):
215 return self.render(
216 loader,
217 'signature.mako.cpp',
218 signature=self,
219 indent=indent)
220
221
Brad Bishopc93bcc92017-01-21 16:23:39 -0500222class MethodCall(Argument):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500223 '''Render syntatically correct c++ method calls.'''
224
225 def __init__(self, **kw):
226 self.namespace = kw.pop('namespace', [])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500227 self.templates = kw.pop('templates', [])
228 self.args = kw.pop('args', [])
Brad Bishop22cfbe62016-11-30 13:25:10 -0500229 super(MethodCall, self).__init__(**kw)
230
Brad Bishopcab2bdd2017-01-21 15:00:54 -0500231 def call(self, loader, indent):
232 return self.render(
233 loader,
234 'method.mako.cpp',
235 method=self,
236 indent=indent)
237
238 def argument(self, loader, indent):
239 return self.call(loader, indent)
240
Brad Bishop14a9fe52016-11-12 12:51:26 -0500241
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500242class Vector(MethodCall):
243 '''Convenience type for vectors.'''
244
245 def __init__(self, **kw):
246 kw['name'] = 'vector'
247 kw['namespace'] = ['std']
248 kw['args'] = [InitializerList(values=kw.pop('args'))]
249 super(Vector, self).__init__(**kw)
250
251
Brad Bishopc1f47982017-02-09 01:27:38 -0500252class Filter(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500253 '''Convenience type for filters'''
Brad Bishopbf066a62016-10-19 08:09:44 -0400254
Brad Bishop22cfbe62016-11-30 13:25:10 -0500255 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500256 kw['name'] = 'make_filter'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500257 super(Filter, self).__init__(**kw)
Brad Bishopbf066a62016-10-19 08:09:44 -0400258
Brad Bishop0a6a4792016-11-12 12:10:07 -0500259
Brad Bishopc1f47982017-02-09 01:27:38 -0500260class Action(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500261 '''Convenience type for actions'''
Brad Bishop561a5652016-10-26 21:13:32 -0500262
Brad Bishop22cfbe62016-11-30 13:25:10 -0500263 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500264 kw['name'] = 'make_action'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500265 super(Action, self).__init__(**kw)
Brad Bishop92665b22016-10-26 20:51:16 -0500266
Brad Bishopcfb3c892016-11-12 11:43:37 -0500267
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500268class PathCondition(MethodCall):
269 '''Convenience type for path conditions'''
270
271 def __init__(self, **kw):
272 kw['name'] = 'make_path_condition'
273 super(PathCondition, self).__init__(**kw)
274
275
Matthew Barth979eb592018-10-05 15:29:26 -0500276class GetProperty(MethodCall):
277 '''Convenience type for getting inventory properties'''
278
279 def __init__(self, **kw):
280 kw['name'] = 'make_get_property'
281 super(GetProperty, self).__init__(**kw)
282
283
Brad Bishopc1f47982017-02-09 01:27:38 -0500284class CreateObjects(MethodCall):
285 '''Assemble a createObjects functor.'''
Brad Bishopdb92c282017-01-21 23:44:28 -0500286
287 def __init__(self, **kw):
288 objs = []
289
290 for path, interfaces in kw.pop('objs').iteritems():
291 key_o = TrivialArgument(
292 value=path,
293 type='string',
294 decorators=[Literal('string')])
295 value_i = []
296
297 for interface, properties, in interfaces.iteritems():
298 key_i = TrivialArgument(value=interface, type='string')
299 value_p = []
Marri Devender Raofa23d702017-09-02 04:43:42 -0500300 if properties:
301 for prop, value in properties.iteritems():
302 key_p = TrivialArgument(value=prop, type='string')
303 value_v = TrivialArgument(
304 decorators=[Literal(value.get('type', None))],
305 **value)
306 value_p.append(InitializerList(values=[key_p, value_v]))
Brad Bishopdb92c282017-01-21 23:44:28 -0500307
308 value_p = InitializerList(values=value_p)
309 value_i.append(InitializerList(values=[key_i, value_p]))
310
311 value_i = InitializerList(values=value_i)
312 objs.append(InitializerList(values=[key_o, value_i]))
313
314 kw['args'] = [InitializerList(values=objs)]
Brad Bishopc1f47982017-02-09 01:27:38 -0500315 kw['namespace'] = ['functor']
Brad Bishopdb92c282017-01-21 23:44:28 -0500316 super(CreateObjects, self).__init__(**kw)
317
318
Brad Bishopc1f47982017-02-09 01:27:38 -0500319class DestroyObjects(MethodCall):
320 '''Assemble a destroyObject functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500321
322 def __init__(self, **kw):
Brad Bishop7b7e7122017-01-21 21:21:46 -0500323 values = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500324 conditions = [
325 Event.functor_map[
326 x['name']](**x) for x in kw.pop('conditions', [])]
327 conditions = [PathCondition(args=[x]) for x in conditions]
Brad Bishop7b7e7122017-01-21 21:21:46 -0500328 args = [InitializerList(
329 values=[TrivialArgument(**x) for x in values])]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500330 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500331 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500332 kw['namespace'] = ['functor']
Brad Bishop7b7e7122017-01-21 21:21:46 -0500333 super(DestroyObjects, self).__init__(**kw)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500334
335
Brad Bishopc1f47982017-02-09 01:27:38 -0500336class SetProperty(MethodCall):
337 '''Assemble a setProperty functor.'''
Brad Bishope2e402f2016-11-30 18:00:17 -0500338
339 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500340 args = []
341
342 value = kw.pop('value')
343 prop = kw.pop('property')
344 iface = kw.pop('interface')
345 iface = Interface(iface)
346 namespace = iface.namespace().split('::')[:-1]
347 name = iface[-1]
348 t = Template(namespace=namespace, name=iface[-1])
349
Brad Bishope2e402f2016-11-30 18:00:17 -0500350 member = '&%s' % '::'.join(
Brad Bishopc93bcc92017-01-21 16:23:39 -0500351 namespace + [name, NamedElement(name=prop).camelCase])
352 member_type = cppTypeName(value['type'])
353 member_cast = '{0} ({1}::*)({0})'.format(member_type, t.qualified())
Brad Bishope2e402f2016-11-30 18:00:17 -0500354
Brad Bishop02ca0212017-01-28 23:25:58 -0500355 paths = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
356 args.append(InitializerList(
357 values=[TrivialArgument(**x) for x in paths]))
358
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500359 conditions = [
360 Event.functor_map[
361 x['name']](**x) for x in kw.pop('conditions', [])]
362 conditions = [PathCondition(args=[x]) for x in conditions]
363
364 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500365 args.append(TrivialArgument(value=str(iface), type='string'))
366 args.append(TrivialArgument(
367 value=member, decorators=[Cast('static', member_cast)]))
368 args.append(TrivialArgument(**value))
Brad Bishope2e402f2016-11-30 18:00:17 -0500369
Brad Bishopc93bcc92017-01-21 16:23:39 -0500370 kw['templates'] = [Template(name=name, namespace=namespace)]
371 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500372 kw['namespace'] = ['functor']
Brad Bishope2e402f2016-11-30 18:00:17 -0500373 super(SetProperty, self).__init__(**kw)
374
375
Brad Bishopc1f47982017-02-09 01:27:38 -0500376class PropertyChanged(MethodCall):
377 '''Assemble a propertyChanged functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500378
379 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500380 args = []
381 args.append(TrivialArgument(value=kw.pop('interface'), type='string'))
382 args.append(TrivialArgument(value=kw.pop('property'), type='string'))
383 args.append(TrivialArgument(
384 decorators=[
385 Literal(kw['value'].get('type', None))], **kw.pop('value')))
386 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500387 kw['namespace'] = ['functor']
Brad Bishop22cfbe62016-11-30 13:25:10 -0500388 super(PropertyChanged, self).__init__(**kw)
389
390
Brad Bishopc1f47982017-02-09 01:27:38 -0500391class PropertyIs(MethodCall):
392 '''Assemble a propertyIs functor.'''
Brad Bishop040e18b2017-01-21 22:04:00 -0500393
394 def __init__(self, **kw):
395 args = []
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500396 path = kw.pop('path', None)
397 if not path:
398 path = TrivialArgument(value='nullptr')
399 else:
400 path = TrivialArgument(value=path, type='string')
401
402 args.append(path)
Matthew Barth979eb592018-10-05 15:29:26 -0500403 iface = TrivialArgument(value=kw.pop('interface'), type='string')
404 args.append(iface)
405 prop = TrivialArgument(value=kw.pop('property'), type='string')
406 args.append(prop)
Brad Bishop040e18b2017-01-21 22:04:00 -0500407 args.append(TrivialArgument(
408 decorators=[
409 Literal(kw['value'].get('type', None))], **kw.pop('value')))
410
411 service = kw.pop('service', None)
412 if service:
413 args.append(TrivialArgument(value=service, type='string'))
414
Matthew Barth979eb592018-10-05 15:29:26 -0500415 dbusMember = kw.pop('dbusMember', None)
416 if dbusMember:
417 # Inventory manager's service name is required
418 if not service or service != busname:
419 args.append(TrivialArgument(value=busname, type='string'))
420
421 gpArgs = []
422 gpArgs.append(path)
423 gpArgs.append(iface)
424 # Prepend '&' and append 'getPropertyByName' function on dbusMember
425 gpArgs.append(TrivialArgument(
426 value='&'+dbusMember+'::getPropertyByName'))
427 gpArgs.append(prop)
428 fArg = MethodCall(
429 name='getProperty',
430 namespace=['functor'],
431 templates=[Template(
432 name=dbusMember,
433 namespace=[])],
434 args=gpArgs)
435
436 # Append getProperty functor
437 args.append(GetProperty(
438 templates=[Template(
439 name=dbusMember+'::PropertiesVariant',
440 namespace=[])],
441 args=[fArg]))
442
Brad Bishop040e18b2017-01-21 22:04:00 -0500443 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500444 kw['namespace'] = ['functor']
Brad Bishop040e18b2017-01-21 22:04:00 -0500445 super(PropertyIs, self).__init__(**kw)
446
447
Brad Bishopc93bcc92017-01-21 16:23:39 -0500448class Event(MethodCall):
449 '''Assemble an inventory manager event.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500450
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500451 functor_map = {
Brad Bishop7b7e7122017-01-21 21:21:46 -0500452 'destroyObjects': DestroyObjects,
Brad Bishopdb92c282017-01-21 23:44:28 -0500453 'createObjects': CreateObjects,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500454 'propertyChangedTo': PropertyChanged,
Brad Bishop040e18b2017-01-21 22:04:00 -0500455 'propertyIs': PropertyIs,
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500456 'setProperty': SetProperty,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500457 }
458
Brad Bishop22cfbe62016-11-30 13:25:10 -0500459 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500460 self.summary = kw.pop('name')
461
462 filters = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500463 self.functor_map[x['name']](**x) for x in kw.pop('filters', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500464 filters = [Filter(args=[x]) for x in filters]
Brad Bishop064c94a2017-01-21 21:33:30 -0500465 filters = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500466 templates=[Template(name='Filter', namespace=[])],
Brad Bishop064c94a2017-01-21 21:33:30 -0500467 args=filters)
Brad Bishopc93bcc92017-01-21 16:23:39 -0500468
469 event = MethodCall(
470 name='make_shared',
471 namespace=['std'],
472 templates=[Template(
473 name=kw.pop('event'),
474 namespace=kw.pop('event_namespace', []))],
Brad Bishop064c94a2017-01-21 21:33:30 -0500475 args=kw.pop('event_args', []) + [filters])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500476
477 events = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500478 templates=[Template(name='EventBasePtr', namespace=[])],
Brad Bishopc93bcc92017-01-21 16:23:39 -0500479 args=[event])
480
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500481 action_type = Template(name='Action', namespace=[])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500482 action_args = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500483 self.functor_map[x['name']](**x) for x in kw.pop('actions', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500484 action_args = [Action(args=[x]) for x in action_args]
Brad Bishopc93bcc92017-01-21 16:23:39 -0500485 actions = Vector(
486 templates=[action_type],
487 args=action_args)
488
489 kw['name'] = 'make_tuple'
490 kw['namespace'] = ['std']
491 kw['args'] = [events, actions]
Brad Bishop22cfbe62016-11-30 13:25:10 -0500492 super(Event, self).__init__(**kw)
Brad Bishopcfb3c892016-11-12 11:43:37 -0500493
Brad Bishopcfb3c892016-11-12 11:43:37 -0500494
Brad Bishop22cfbe62016-11-30 13:25:10 -0500495class MatchEvent(Event):
496 '''Associate one or more dbus signal match signatures with
497 a filter.'''
498
Brad Bishop22cfbe62016-11-30 13:25:10 -0500499 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500500 kw['event'] = 'DbusSignal'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500501 kw['event_namespace'] = []
Brad Bishopc93bcc92017-01-21 16:23:39 -0500502 kw['event_args'] = [
503 DbusSignature(**x) for x in kw.pop('signatures', [])]
504
Brad Bishop22cfbe62016-11-30 13:25:10 -0500505 super(MatchEvent, self).__init__(**kw)
506
507
Brad Bishop828df832017-01-21 22:20:43 -0500508class StartupEvent(Event):
509 '''Assemble a startup event.'''
510
511 def __init__(self, **kw):
512 kw['event'] = 'StartupEvent'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500513 kw['event_namespace'] = []
Brad Bishop828df832017-01-21 22:20:43 -0500514 super(StartupEvent, self).__init__(**kw)
515
516
Brad Bishop22cfbe62016-11-30 13:25:10 -0500517class Everything(Renderer):
518 '''Parse/render entry point.'''
519
520 class_map = {
521 'match': MatchEvent,
Brad Bishop828df832017-01-21 22:20:43 -0500522 'startup': StartupEvent,
Brad Bishop22cfbe62016-11-30 13:25:10 -0500523 }
524
525 @staticmethod
526 def load(args):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500527 # Aggregate all the event YAML in the events.d directory
528 # into a single list of events.
529
Brad Bishop22cfbe62016-11-30 13:25:10 -0500530 events = []
Brad Bishopa6fcd562017-02-03 11:00:27 -0500531 events_dir = os.path.join(args.inputdir, 'events.d')
532
533 if os.path.exists(events_dir):
534 yaml_files = filter(
535 lambda x: x.endswith('.yaml'),
536 os.listdir(events_dir))
537
538 for x in yaml_files:
539 with open(os.path.join(events_dir, x), 'r') as fd:
540 for e in yaml.safe_load(fd.read()).get('events', {}):
541 events.append(e)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500542
Deepak Kodihallief550b12017-08-03 14:00:17 -0500543 interfaces, interface_composite = Everything.get_interfaces(
544 args.ifacesdir)
545 extra_interfaces, extra_interface_composite = \
546 Everything.get_interfaces(
547 os.path.join(args.inputdir, 'extra_interfaces.d'))
548 interface_composite.update(extra_interface_composite)
549 interface_composite = InterfaceComposite(interface_composite)
Matthew Barth979eb592018-10-05 15:29:26 -0500550 # Update busname if configured differenly than the default
551 busname = args.busname
Brad Bishop834989f2017-02-06 12:08:20 -0500552
Brad Bishop22cfbe62016-11-30 13:25:10 -0500553 return Everything(
554 *events,
Deepak Kodihallief550b12017-08-03 14:00:17 -0500555 interfaces=interfaces + extra_interfaces,
556 interface_composite=interface_composite)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500557
558 @staticmethod
Brad Bishop834989f2017-02-06 12:08:20 -0500559 def get_interfaces(targetdir):
560 '''Scan the interfaces directory for interfaces that PIM can create.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500561
Brad Bishop834989f2017-02-06 12:08:20 -0500562 yaml_files = []
Brad Bishop22cfbe62016-11-30 13:25:10 -0500563 interfaces = []
Deepak Kodihallief550b12017-08-03 14:00:17 -0500564 interface_composite = {}
Brad Bishopa6fcd562017-02-03 11:00:27 -0500565
Brad Bishop834989f2017-02-06 12:08:20 -0500566 if targetdir and os.path.exists(targetdir):
567 for directory, _, files in os.walk(targetdir):
568 if not files:
569 continue
570
571 yaml_files += map(
572 lambda f: os.path.relpath(
573 os.path.join(directory, f),
574 targetdir),
575 filter(lambda f: f.endswith('.interface.yaml'), files))
576
577 for y in yaml_files:
Marri Devender Rao06e3d502017-06-09 11:33:38 -0500578 # parse only phosphor dbus related interface files
579 if not y.startswith('xyz'):
580 continue
Brad Bishop834989f2017-02-06 12:08:20 -0500581 with open(os.path.join(targetdir, y)) as fd:
582 i = y.replace('.interface.yaml', '').replace(os.sep, '.')
583
584 # PIM can't create interfaces with methods.
Brad Bishop834989f2017-02-06 12:08:20 -0500585 parsed = yaml.safe_load(fd.read())
586 if parsed.get('methods', None):
587 continue
Deepak Kodihalli0b6ca102017-08-09 04:39:43 -0500588 # Cereal can't understand the type sdbusplus::object_path. This
589 # type is a wrapper around std::string. Ignore interfaces having
590 # a property of this type for now. The only interface that has a
591 # property of this type now is xyz.openbmc_project.Association,
592 # which is an unused interface. No inventory objects implement
593 # this interface.
594 # TODO via openbmc/openbmc#2123 : figure out how to make Cereal
595 # understand sdbusplus::object_path.
Marri Devender Raofa23d702017-09-02 04:43:42 -0500596 properties = parsed.get('properties', None)
597 if properties:
598 if any('path' in p['type'] for p in properties):
599 continue
Deepak Kodihallief550b12017-08-03 14:00:17 -0500600 interface_composite[i] = properties
Brad Bishop834989f2017-02-06 12:08:20 -0500601 interfaces.append(i)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500602
Deepak Kodihallief550b12017-08-03 14:00:17 -0500603 return interfaces, interface_composite
Brad Bishop22cfbe62016-11-30 13:25:10 -0500604
605 def __init__(self, *a, **kw):
606 self.interfaces = \
607 [Interface(x) for x in kw.pop('interfaces', [])]
Deepak Kodihallief550b12017-08-03 14:00:17 -0500608 self.interface_composite = \
609 kw.pop('interface_composite', {})
Brad Bishop22cfbe62016-11-30 13:25:10 -0500610 self.events = [
611 self.class_map[x['type']](**x) for x in a]
612 super(Everything, self).__init__(**kw)
613
Brad Bishop22cfbe62016-11-30 13:25:10 -0500614 def generate_cpp(self, loader):
615 '''Render the template with the provided events and interfaces.'''
616 with open(os.path.join(
617 args.outputdir,
618 'generated.cpp'), 'w') as fd:
619 fd.write(
620 self.render(
621 loader,
622 'generated.mako.cpp',
623 events=self.events,
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500624 interfaces=self.interfaces,
625 indent=Indent()))
Brad Bishopbf066a62016-10-19 08:09:44 -0400626
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500627 def generate_serialization(self, loader):
628 with open(os.path.join(
629 args.outputdir,
630 'gen_serialization.hpp'), 'w') as fd:
631 fd.write(
632 self.render(
633 loader,
634 'gen_serialization.mako.hpp',
635 interfaces=self.interfaces,
636 interface_composite=self.interface_composite))
637
Brad Bishop95dd98f2016-11-12 12:39:15 -0500638
639if __name__ == '__main__':
640 script_dir = os.path.dirname(os.path.realpath(__file__))
Brad Bishop14a9fe52016-11-12 12:51:26 -0500641 valid_commands = {
642 'generate-cpp': 'generate_cpp',
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500643 'generate-serialization': 'generate_serialization',
Brad Bishop22cfbe62016-11-30 13:25:10 -0500644 }
Brad Bishop95dd98f2016-11-12 12:39:15 -0500645
646 parser = argparse.ArgumentParser(
647 description='Phosphor Inventory Manager (PIM) YAML '
648 'scanner and code generator.')
649 parser.add_argument(
650 '-o', '--output-dir', dest='outputdir',
651 default='.', help='Output directory.')
652 parser.add_argument(
Brad Bishop834989f2017-02-06 12:08:20 -0500653 '-i', '--interfaces-dir', dest='ifacesdir',
654 help='Location of interfaces to be supported.')
655 parser.add_argument(
Brad Bishop95dd98f2016-11-12 12:39:15 -0500656 '-d', '--dir', dest='inputdir',
657 default=os.path.join(script_dir, 'example'),
658 help='Location of files to process.')
Brad Bishopf4666f52016-11-12 12:44:42 -0500659 parser.add_argument(
Matthew Barth979eb592018-10-05 15:29:26 -0500660 '-b', '--bus-name', dest='busname',
661 default='xyz.openbmc_project.Inventory.Manager',
662 help='Inventory manager busname.')
663 parser.add_argument(
Brad Bishopf4666f52016-11-12 12:44:42 -0500664 'command', metavar='COMMAND', type=str,
665 choices=valid_commands.keys(),
Brad Bishopc029f6a2017-01-18 19:43:26 -0500666 help='%s.' % " | ".join(valid_commands.keys()))
Brad Bishop95dd98f2016-11-12 12:39:15 -0500667
668 args = parser.parse_args()
Brad Bishop22cfbe62016-11-30 13:25:10 -0500669
670 if sys.version_info < (3, 0):
671 lookup = mako.lookup.TemplateLookup(
672 directories=[script_dir],
673 disable_unicode=True)
674 else:
675 lookup = mako.lookup.TemplateLookup(
676 directories=[script_dir])
677
678 function = getattr(
679 Everything.load(args),
680 valid_commands[args.command])
681 function(lookup)
Brad Bishop95dd98f2016-11-12 12:39:15 -0500682
683
Brad Bishopbf066a62016-10-19 08:09:44 -0400684# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4