blob: de5419dc4d5fa782dbc47f991c678d55fa9a0589 [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
Brad Bishop9b5a12f2017-01-21 14:42:11 -050029def cppTypeName(yaml_type):
30 ''' Convert yaml types to cpp types.'''
31 return sdbusplus.property.Property(type=yaml_type).cppTypeName
32
33
Deepak Kodihallief550b12017-08-03 14:00:17 -050034class InterfaceComposite(object):
35 '''Compose interface properties.'''
36
37 def __init__(self, dict):
38 self.dict = dict
39
40 def properties(self, interface):
41 return self.dict[interface]
42
43 def interfaces(self):
44 return self.dict.keys()
45
46 def names(self, interface):
Marri Devender Raofa23d702017-09-02 04:43:42 -050047 names = []
48 if self.dict[interface]:
49 names = [x["name"] for x in self.dict[interface]]
Deepak Kodihallief550b12017-08-03 14:00:17 -050050 return names
51
52
Brad Bishop22cfbe62016-11-30 13:25:10 -050053class Interface(list):
54 '''Provide various interface transformations.'''
55
56 def __init__(self, iface):
57 super(Interface, self).__init__(iface.split('.'))
58
59 def namespace(self):
60 '''Represent as an sdbusplus namespace.'''
61 return '::'.join(['sdbusplus'] + self[:-1] + ['server', self[-1]])
62
63 def header(self):
64 '''Represent as an sdbusplus server binding header.'''
65 return os.sep.join(self + ['server.hpp'])
66
67 def __str__(self):
68 return '.'.join(self)
Brad Bishopbf066a62016-10-19 08:09:44 -040069
Brad Bishopcfb3c892016-11-12 11:43:37 -050070
Brad Bishop9b5a12f2017-01-21 14:42:11 -050071class Indent(object):
72 '''Help templates be depth agnostic.'''
73
74 def __init__(self, depth=0):
75 self.depth = depth
76
77 def __add__(self, depth):
78 return Indent(self.depth + depth)
79
80 def __call__(self, depth):
81 '''Render an indent at the current depth plus depth.'''
82 return 4*' '*(depth + self.depth)
83
84
85class Template(NamedElement):
86 '''Associate a template name with its namespace.'''
87
88 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -050089 self.namespace = kw.pop('namespace', [])
Brad Bishop9b5a12f2017-01-21 14:42:11 -050090 super(Template, self).__init__(**kw)
91
92 def qualified(self):
93 return '::'.join(self.namespace + [self.name])
94
95
Brad Bishopdb9b3252017-01-30 08:58:40 -050096class FixBool(object):
97 '''Un-capitalize booleans.'''
98
99 def __call__(self, arg):
100 return '{0}'.format(arg.lower())
101
102
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500103class Quote(object):
104 '''Decorate an argument by quoting it.'''
105
106 def __call__(self, arg):
107 return '"{0}"'.format(arg)
108
109
110class Cast(object):
111 '''Decorate an argument by casting it.'''
112
113 def __init__(self, cast, target):
114 '''cast is the cast type (static, const, etc...).
115 target is the cast target type.'''
116 self.cast = cast
117 self.target = target
118
119 def __call__(self, arg):
120 return '{0}_cast<{1}>({2})'.format(self.cast, self.target, arg)
121
122
123class Literal(object):
124 '''Decorate an argument with a literal operator.'''
125
Brad Bishop134d2cb2017-02-23 12:37:56 -0500126 integer_types = [
127 'int8',
128 'int16',
129 'int32',
130 'int64',
131 'uint8',
132 'uint16',
133 'uint32',
134 'uint64'
135 ]
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500136
137 def __init__(self, type):
138 self.type = type
139
140 def __call__(self, arg):
Brad Bishop134d2cb2017-02-23 12:37:56 -0500141 if 'uint' in self.type:
142 arg = '{0}ull'.format(arg)
143 elif 'int' in self.type:
144 arg = '{0}ll'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500145
Brad Bishop134d2cb2017-02-23 12:37:56 -0500146 if self.type in self.integer_types:
147 return Cast('static', '{0}_t'.format(self.type))(arg)
148
149 if self.type == 'string':
150 return '{0}s'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500151
152 return arg
153
154
Brad Bishop75800cf2017-01-21 15:24:18 -0500155class Argument(NamedElement, Renderer):
156 '''Define argument type inteface.'''
157
158 def __init__(self, **kw):
159 self.type = kw.pop('type', None)
160 super(Argument, self).__init__(**kw)
161
162 def argument(self, loader, indent):
163 raise NotImplementedError
164
165
166class TrivialArgument(Argument):
167 '''Non-array type arguments.'''
Brad Bishop14a9fe52016-11-12 12:51:26 -0500168
Brad Bishop22cfbe62016-11-30 13:25:10 -0500169 def __init__(self, **kw):
170 self.value = kw.pop('value')
Brad Bishop75800cf2017-01-21 15:24:18 -0500171 self.decorators = kw.pop('decorators', [])
172 if kw.get('type', None) == 'string':
173 self.decorators.insert(0, Quote())
Brad Bishopdb9b3252017-01-30 08:58:40 -0500174 if kw.get('type', None) == 'boolean':
175 self.decorators.insert(0, FixBool())
Brad Bishop75800cf2017-01-21 15:24:18 -0500176
Brad Bishop75800cf2017-01-21 15:24:18 -0500177 super(TrivialArgument, self).__init__(**kw)
178
179 def argument(self, loader, indent):
180 a = str(self.value)
181 for d in self.decorators:
182 a = d(a)
183
184 return a
Brad Bishop14a9fe52016-11-12 12:51:26 -0500185
Brad Bishop14a9fe52016-11-12 12:51:26 -0500186
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500187class InitializerList(Argument):
188 '''Initializer list arguments.'''
189
190 def __init__(self, **kw):
191 self.values = kw.pop('values')
192 super(InitializerList, self).__init__(**kw)
193
194 def argument(self, loader, indent):
195 return self.render(
196 loader,
197 'argument.mako.cpp',
198 arg=self,
199 indent=indent)
200
201
Brad Bishop75800cf2017-01-21 15:24:18 -0500202class DbusSignature(Argument):
203 '''DBus signature arguments.'''
204
205 def __init__(self, **kw):
206 self.sig = {x: y for x, y in kw.iteritems()}
207 kw.clear()
208 super(DbusSignature, self).__init__(**kw)
209
210 def argument(self, loader, indent):
211 return self.render(
212 loader,
213 'signature.mako.cpp',
214 signature=self,
215 indent=indent)
216
217
Brad Bishopc93bcc92017-01-21 16:23:39 -0500218class MethodCall(Argument):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500219 '''Render syntatically correct c++ method calls.'''
220
221 def __init__(self, **kw):
222 self.namespace = kw.pop('namespace', [])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500223 self.templates = kw.pop('templates', [])
224 self.args = kw.pop('args', [])
Brad Bishop22cfbe62016-11-30 13:25:10 -0500225 super(MethodCall, self).__init__(**kw)
226
Brad Bishopcab2bdd2017-01-21 15:00:54 -0500227 def call(self, loader, indent):
228 return self.render(
229 loader,
230 'method.mako.cpp',
231 method=self,
232 indent=indent)
233
234 def argument(self, loader, indent):
235 return self.call(loader, indent)
236
Brad Bishop14a9fe52016-11-12 12:51:26 -0500237
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500238class Vector(MethodCall):
239 '''Convenience type for vectors.'''
240
241 def __init__(self, **kw):
242 kw['name'] = 'vector'
243 kw['namespace'] = ['std']
244 kw['args'] = [InitializerList(values=kw.pop('args'))]
245 super(Vector, self).__init__(**kw)
246
247
Brad Bishopc1f47982017-02-09 01:27:38 -0500248class Filter(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500249 '''Convenience type for filters'''
Brad Bishopbf066a62016-10-19 08:09:44 -0400250
Brad Bishop22cfbe62016-11-30 13:25:10 -0500251 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500252 kw['name'] = 'make_filter'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500253 super(Filter, self).__init__(**kw)
Brad Bishopbf066a62016-10-19 08:09:44 -0400254
Brad Bishop0a6a4792016-11-12 12:10:07 -0500255
Brad Bishopc1f47982017-02-09 01:27:38 -0500256class Action(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500257 '''Convenience type for actions'''
Brad Bishop561a5652016-10-26 21:13:32 -0500258
Brad Bishop22cfbe62016-11-30 13:25:10 -0500259 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500260 kw['name'] = 'make_action'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500261 super(Action, self).__init__(**kw)
Brad Bishop92665b22016-10-26 20:51:16 -0500262
Brad Bishopcfb3c892016-11-12 11:43:37 -0500263
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500264class PathCondition(MethodCall):
265 '''Convenience type for path conditions'''
266
267 def __init__(self, **kw):
268 kw['name'] = 'make_path_condition'
269 super(PathCondition, self).__init__(**kw)
270
271
Brad Bishopc1f47982017-02-09 01:27:38 -0500272class CreateObjects(MethodCall):
273 '''Assemble a createObjects functor.'''
Brad Bishopdb92c282017-01-21 23:44:28 -0500274
275 def __init__(self, **kw):
276 objs = []
277
278 for path, interfaces in kw.pop('objs').iteritems():
279 key_o = TrivialArgument(
280 value=path,
281 type='string',
282 decorators=[Literal('string')])
283 value_i = []
284
285 for interface, properties, in interfaces.iteritems():
286 key_i = TrivialArgument(value=interface, type='string')
287 value_p = []
Marri Devender Raofa23d702017-09-02 04:43:42 -0500288 if properties:
289 for prop, value in properties.iteritems():
290 key_p = TrivialArgument(value=prop, type='string')
291 value_v = TrivialArgument(
292 decorators=[Literal(value.get('type', None))],
293 **value)
294 value_p.append(InitializerList(values=[key_p, value_v]))
Brad Bishopdb92c282017-01-21 23:44:28 -0500295
296 value_p = InitializerList(values=value_p)
297 value_i.append(InitializerList(values=[key_i, value_p]))
298
299 value_i = InitializerList(values=value_i)
300 objs.append(InitializerList(values=[key_o, value_i]))
301
302 kw['args'] = [InitializerList(values=objs)]
Brad Bishopc1f47982017-02-09 01:27:38 -0500303 kw['namespace'] = ['functor']
Brad Bishopdb92c282017-01-21 23:44:28 -0500304 super(CreateObjects, self).__init__(**kw)
305
306
Brad Bishopc1f47982017-02-09 01:27:38 -0500307class DestroyObjects(MethodCall):
308 '''Assemble a destroyObject functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500309
310 def __init__(self, **kw):
Brad Bishop7b7e7122017-01-21 21:21:46 -0500311 values = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500312 conditions = [
313 Event.functor_map[
314 x['name']](**x) for x in kw.pop('conditions', [])]
315 conditions = [PathCondition(args=[x]) for x in conditions]
Brad Bishop7b7e7122017-01-21 21:21:46 -0500316 args = [InitializerList(
317 values=[TrivialArgument(**x) for x in values])]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500318 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500319 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500320 kw['namespace'] = ['functor']
Brad Bishop7b7e7122017-01-21 21:21:46 -0500321 super(DestroyObjects, self).__init__(**kw)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500322
323
Brad Bishopc1f47982017-02-09 01:27:38 -0500324class SetProperty(MethodCall):
325 '''Assemble a setProperty functor.'''
Brad Bishope2e402f2016-11-30 18:00:17 -0500326
327 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500328 args = []
329
330 value = kw.pop('value')
331 prop = kw.pop('property')
332 iface = kw.pop('interface')
333 iface = Interface(iface)
334 namespace = iface.namespace().split('::')[:-1]
335 name = iface[-1]
336 t = Template(namespace=namespace, name=iface[-1])
337
Brad Bishope2e402f2016-11-30 18:00:17 -0500338 member = '&%s' % '::'.join(
Brad Bishopc93bcc92017-01-21 16:23:39 -0500339 namespace + [name, NamedElement(name=prop).camelCase])
340 member_type = cppTypeName(value['type'])
341 member_cast = '{0} ({1}::*)({0})'.format(member_type, t.qualified())
Brad Bishope2e402f2016-11-30 18:00:17 -0500342
Brad Bishop02ca0212017-01-28 23:25:58 -0500343 paths = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
344 args.append(InitializerList(
345 values=[TrivialArgument(**x) for x in paths]))
346
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500347 conditions = [
348 Event.functor_map[
349 x['name']](**x) for x in kw.pop('conditions', [])]
350 conditions = [PathCondition(args=[x]) for x in conditions]
351
352 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500353 args.append(TrivialArgument(value=str(iface), type='string'))
354 args.append(TrivialArgument(
355 value=member, decorators=[Cast('static', member_cast)]))
356 args.append(TrivialArgument(**value))
Brad Bishope2e402f2016-11-30 18:00:17 -0500357
Brad Bishopc93bcc92017-01-21 16:23:39 -0500358 kw['templates'] = [Template(name=name, namespace=namespace)]
359 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500360 kw['namespace'] = ['functor']
Brad Bishope2e402f2016-11-30 18:00:17 -0500361 super(SetProperty, self).__init__(**kw)
362
363
Brad Bishopc1f47982017-02-09 01:27:38 -0500364class PropertyChanged(MethodCall):
365 '''Assemble a propertyChanged functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500366
367 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500368 args = []
369 args.append(TrivialArgument(value=kw.pop('interface'), type='string'))
370 args.append(TrivialArgument(value=kw.pop('property'), type='string'))
371 args.append(TrivialArgument(
372 decorators=[
373 Literal(kw['value'].get('type', None))], **kw.pop('value')))
374 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500375 kw['namespace'] = ['functor']
Brad Bishop22cfbe62016-11-30 13:25:10 -0500376 super(PropertyChanged, self).__init__(**kw)
377
378
Brad Bishopc1f47982017-02-09 01:27:38 -0500379class PropertyIs(MethodCall):
380 '''Assemble a propertyIs functor.'''
Brad Bishop040e18b2017-01-21 22:04:00 -0500381
382 def __init__(self, **kw):
383 args = []
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500384 path = kw.pop('path', None)
385 if not path:
386 path = TrivialArgument(value='nullptr')
387 else:
388 path = TrivialArgument(value=path, type='string')
389
390 args.append(path)
Brad Bishop040e18b2017-01-21 22:04:00 -0500391 args.append(TrivialArgument(value=kw.pop('interface'), type='string'))
392 args.append(TrivialArgument(value=kw.pop('property'), type='string'))
393 args.append(TrivialArgument(
394 decorators=[
395 Literal(kw['value'].get('type', None))], **kw.pop('value')))
396
397 service = kw.pop('service', None)
398 if service:
399 args.append(TrivialArgument(value=service, type='string'))
400
401 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500402 kw['namespace'] = ['functor']
Brad Bishop040e18b2017-01-21 22:04:00 -0500403 super(PropertyIs, self).__init__(**kw)
404
405
Brad Bishopc93bcc92017-01-21 16:23:39 -0500406class Event(MethodCall):
407 '''Assemble an inventory manager event.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500408
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500409 functor_map = {
Brad Bishop7b7e7122017-01-21 21:21:46 -0500410 'destroyObjects': DestroyObjects,
Brad Bishopdb92c282017-01-21 23:44:28 -0500411 'createObjects': CreateObjects,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500412 'propertyChangedTo': PropertyChanged,
Brad Bishop040e18b2017-01-21 22:04:00 -0500413 'propertyIs': PropertyIs,
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500414 'setProperty': SetProperty,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500415 }
416
Brad Bishop22cfbe62016-11-30 13:25:10 -0500417 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500418 self.summary = kw.pop('name')
419
420 filters = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500421 self.functor_map[x['name']](**x) for x in kw.pop('filters', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500422 filters = [Filter(args=[x]) for x in filters]
Brad Bishop064c94a2017-01-21 21:33:30 -0500423 filters = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500424 templates=[Template(name='Filter', namespace=[])],
Brad Bishop064c94a2017-01-21 21:33:30 -0500425 args=filters)
Brad Bishopc93bcc92017-01-21 16:23:39 -0500426
427 event = MethodCall(
428 name='make_shared',
429 namespace=['std'],
430 templates=[Template(
431 name=kw.pop('event'),
432 namespace=kw.pop('event_namespace', []))],
Brad Bishop064c94a2017-01-21 21:33:30 -0500433 args=kw.pop('event_args', []) + [filters])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500434
435 events = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500436 templates=[Template(name='EventBasePtr', namespace=[])],
Brad Bishopc93bcc92017-01-21 16:23:39 -0500437 args=[event])
438
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500439 action_type = Template(name='Action', namespace=[])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500440 action_args = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500441 self.functor_map[x['name']](**x) for x in kw.pop('actions', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500442 action_args = [Action(args=[x]) for x in action_args]
Brad Bishopc93bcc92017-01-21 16:23:39 -0500443 actions = Vector(
444 templates=[action_type],
445 args=action_args)
446
447 kw['name'] = 'make_tuple'
448 kw['namespace'] = ['std']
449 kw['args'] = [events, actions]
Brad Bishop22cfbe62016-11-30 13:25:10 -0500450 super(Event, self).__init__(**kw)
Brad Bishopcfb3c892016-11-12 11:43:37 -0500451
Brad Bishopcfb3c892016-11-12 11:43:37 -0500452
Brad Bishop22cfbe62016-11-30 13:25:10 -0500453class MatchEvent(Event):
454 '''Associate one or more dbus signal match signatures with
455 a filter.'''
456
Brad Bishop22cfbe62016-11-30 13:25:10 -0500457 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500458 kw['event'] = 'DbusSignal'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500459 kw['event_namespace'] = []
Brad Bishopc93bcc92017-01-21 16:23:39 -0500460 kw['event_args'] = [
461 DbusSignature(**x) for x in kw.pop('signatures', [])]
462
Brad Bishop22cfbe62016-11-30 13:25:10 -0500463 super(MatchEvent, self).__init__(**kw)
464
465
Brad Bishop828df832017-01-21 22:20:43 -0500466class StartupEvent(Event):
467 '''Assemble a startup event.'''
468
469 def __init__(self, **kw):
470 kw['event'] = 'StartupEvent'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500471 kw['event_namespace'] = []
Brad Bishop828df832017-01-21 22:20:43 -0500472 super(StartupEvent, self).__init__(**kw)
473
474
Brad Bishop22cfbe62016-11-30 13:25:10 -0500475class Everything(Renderer):
476 '''Parse/render entry point.'''
477
478 class_map = {
479 'match': MatchEvent,
Brad Bishop828df832017-01-21 22:20:43 -0500480 'startup': StartupEvent,
Brad Bishop22cfbe62016-11-30 13:25:10 -0500481 }
482
483 @staticmethod
484 def load(args):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500485 # Aggregate all the event YAML in the events.d directory
486 # into a single list of events.
487
Brad Bishop22cfbe62016-11-30 13:25:10 -0500488 events = []
Brad Bishopa6fcd562017-02-03 11:00:27 -0500489 events_dir = os.path.join(args.inputdir, 'events.d')
490
491 if os.path.exists(events_dir):
492 yaml_files = filter(
493 lambda x: x.endswith('.yaml'),
494 os.listdir(events_dir))
495
496 for x in yaml_files:
497 with open(os.path.join(events_dir, x), 'r') as fd:
498 for e in yaml.safe_load(fd.read()).get('events', {}):
499 events.append(e)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500500
Deepak Kodihallief550b12017-08-03 14:00:17 -0500501 interfaces, interface_composite = Everything.get_interfaces(
502 args.ifacesdir)
503 extra_interfaces, extra_interface_composite = \
504 Everything.get_interfaces(
505 os.path.join(args.inputdir, 'extra_interfaces.d'))
506 interface_composite.update(extra_interface_composite)
507 interface_composite = InterfaceComposite(interface_composite)
Brad Bishop834989f2017-02-06 12:08:20 -0500508
Brad Bishop22cfbe62016-11-30 13:25:10 -0500509 return Everything(
510 *events,
Deepak Kodihallief550b12017-08-03 14:00:17 -0500511 interfaces=interfaces + extra_interfaces,
512 interface_composite=interface_composite)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500513
514 @staticmethod
Brad Bishop834989f2017-02-06 12:08:20 -0500515 def get_interfaces(targetdir):
516 '''Scan the interfaces directory for interfaces that PIM can create.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500517
Brad Bishop834989f2017-02-06 12:08:20 -0500518 yaml_files = []
Brad Bishop22cfbe62016-11-30 13:25:10 -0500519 interfaces = []
Deepak Kodihallief550b12017-08-03 14:00:17 -0500520 interface_composite = {}
Brad Bishopa6fcd562017-02-03 11:00:27 -0500521
Brad Bishop834989f2017-02-06 12:08:20 -0500522 if targetdir and os.path.exists(targetdir):
523 for directory, _, files in os.walk(targetdir):
524 if not files:
525 continue
526
527 yaml_files += map(
528 lambda f: os.path.relpath(
529 os.path.join(directory, f),
530 targetdir),
531 filter(lambda f: f.endswith('.interface.yaml'), files))
532
533 for y in yaml_files:
Marri Devender Rao06e3d502017-06-09 11:33:38 -0500534 # parse only phosphor dbus related interface files
535 if not y.startswith('xyz'):
536 continue
Brad Bishop834989f2017-02-06 12:08:20 -0500537 with open(os.path.join(targetdir, y)) as fd:
538 i = y.replace('.interface.yaml', '').replace(os.sep, '.')
539
540 # PIM can't create interfaces with methods.
Brad Bishop834989f2017-02-06 12:08:20 -0500541 parsed = yaml.safe_load(fd.read())
542 if parsed.get('methods', None):
543 continue
Deepak Kodihalli0b6ca102017-08-09 04:39:43 -0500544 # Cereal can't understand the type sdbusplus::object_path. This
545 # type is a wrapper around std::string. Ignore interfaces having
546 # a property of this type for now. The only interface that has a
547 # property of this type now is xyz.openbmc_project.Association,
548 # which is an unused interface. No inventory objects implement
549 # this interface.
550 # TODO via openbmc/openbmc#2123 : figure out how to make Cereal
551 # understand sdbusplus::object_path.
Marri Devender Raofa23d702017-09-02 04:43:42 -0500552 properties = parsed.get('properties', None)
553 if properties:
554 if any('path' in p['type'] for p in properties):
555 continue
Deepak Kodihallief550b12017-08-03 14:00:17 -0500556 interface_composite[i] = properties
Brad Bishop834989f2017-02-06 12:08:20 -0500557 interfaces.append(i)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500558
Deepak Kodihallief550b12017-08-03 14:00:17 -0500559 return interfaces, interface_composite
Brad Bishop22cfbe62016-11-30 13:25:10 -0500560
561 def __init__(self, *a, **kw):
562 self.interfaces = \
563 [Interface(x) for x in kw.pop('interfaces', [])]
Deepak Kodihallief550b12017-08-03 14:00:17 -0500564 self.interface_composite = \
565 kw.pop('interface_composite', {})
Brad Bishop22cfbe62016-11-30 13:25:10 -0500566 self.events = [
567 self.class_map[x['type']](**x) for x in a]
568 super(Everything, self).__init__(**kw)
569
Brad Bishop22cfbe62016-11-30 13:25:10 -0500570 def generate_cpp(self, loader):
571 '''Render the template with the provided events and interfaces.'''
572 with open(os.path.join(
573 args.outputdir,
574 'generated.cpp'), 'w') as fd:
575 fd.write(
576 self.render(
577 loader,
578 'generated.mako.cpp',
579 events=self.events,
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500580 interfaces=self.interfaces,
581 indent=Indent()))
Brad Bishopbf066a62016-10-19 08:09:44 -0400582
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500583 def generate_serialization(self, loader):
584 with open(os.path.join(
585 args.outputdir,
586 'gen_serialization.hpp'), 'w') as fd:
587 fd.write(
588 self.render(
589 loader,
590 'gen_serialization.mako.hpp',
591 interfaces=self.interfaces,
592 interface_composite=self.interface_composite))
593
Brad Bishop95dd98f2016-11-12 12:39:15 -0500594
595if __name__ == '__main__':
596 script_dir = os.path.dirname(os.path.realpath(__file__))
Brad Bishop14a9fe52016-11-12 12:51:26 -0500597 valid_commands = {
598 'generate-cpp': 'generate_cpp',
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500599 'generate-serialization': 'generate_serialization',
Brad Bishop22cfbe62016-11-30 13:25:10 -0500600 }
Brad Bishop95dd98f2016-11-12 12:39:15 -0500601
602 parser = argparse.ArgumentParser(
603 description='Phosphor Inventory Manager (PIM) YAML '
604 'scanner and code generator.')
605 parser.add_argument(
606 '-o', '--output-dir', dest='outputdir',
607 default='.', help='Output directory.')
608 parser.add_argument(
Brad Bishop834989f2017-02-06 12:08:20 -0500609 '-i', '--interfaces-dir', dest='ifacesdir',
610 help='Location of interfaces to be supported.')
611 parser.add_argument(
Brad Bishop95dd98f2016-11-12 12:39:15 -0500612 '-d', '--dir', dest='inputdir',
613 default=os.path.join(script_dir, 'example'),
614 help='Location of files to process.')
Brad Bishopf4666f52016-11-12 12:44:42 -0500615 parser.add_argument(
616 'command', metavar='COMMAND', type=str,
617 choices=valid_commands.keys(),
Brad Bishopc029f6a2017-01-18 19:43:26 -0500618 help='%s.' % " | ".join(valid_commands.keys()))
Brad Bishop95dd98f2016-11-12 12:39:15 -0500619
620 args = parser.parse_args()
Brad Bishop22cfbe62016-11-30 13:25:10 -0500621
622 if sys.version_info < (3, 0):
623 lookup = mako.lookup.TemplateLookup(
624 directories=[script_dir],
625 disable_unicode=True)
626 else:
627 lookup = mako.lookup.TemplateLookup(
628 directories=[script_dir])
629
630 function = getattr(
631 Everything.load(args),
632 valid_commands[args.command])
633 function(lookup)
Brad Bishop95dd98f2016-11-12 12:39:15 -0500634
635
Brad Bishopbf066a62016-10-19 08:09:44 -0400636# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4