blob: a31267f7113f492b6588c24bd3c654b9f32fcb82 [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):
47 names = [x["name"] for x in self.dict[interface]]
48 return names
49
50
Brad Bishop22cfbe62016-11-30 13:25:10 -050051class Interface(list):
52 '''Provide various interface transformations.'''
53
54 def __init__(self, iface):
55 super(Interface, self).__init__(iface.split('.'))
56
57 def namespace(self):
58 '''Represent as an sdbusplus namespace.'''
59 return '::'.join(['sdbusplus'] + self[:-1] + ['server', self[-1]])
60
61 def header(self):
62 '''Represent as an sdbusplus server binding header.'''
63 return os.sep.join(self + ['server.hpp'])
64
65 def __str__(self):
66 return '.'.join(self)
Brad Bishopbf066a62016-10-19 08:09:44 -040067
Brad Bishopcfb3c892016-11-12 11:43:37 -050068
Brad Bishop9b5a12f2017-01-21 14:42:11 -050069class Indent(object):
70 '''Help templates be depth agnostic.'''
71
72 def __init__(self, depth=0):
73 self.depth = depth
74
75 def __add__(self, depth):
76 return Indent(self.depth + depth)
77
78 def __call__(self, depth):
79 '''Render an indent at the current depth plus depth.'''
80 return 4*' '*(depth + self.depth)
81
82
83class Template(NamedElement):
84 '''Associate a template name with its namespace.'''
85
86 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -050087 self.namespace = kw.pop('namespace', [])
Brad Bishop9b5a12f2017-01-21 14:42:11 -050088 super(Template, self).__init__(**kw)
89
90 def qualified(self):
91 return '::'.join(self.namespace + [self.name])
92
93
Brad Bishopdb9b3252017-01-30 08:58:40 -050094class FixBool(object):
95 '''Un-capitalize booleans.'''
96
97 def __call__(self, arg):
98 return '{0}'.format(arg.lower())
99
100
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500101class Quote(object):
102 '''Decorate an argument by quoting it.'''
103
104 def __call__(self, arg):
105 return '"{0}"'.format(arg)
106
107
108class Cast(object):
109 '''Decorate an argument by casting it.'''
110
111 def __init__(self, cast, target):
112 '''cast is the cast type (static, const, etc...).
113 target is the cast target type.'''
114 self.cast = cast
115 self.target = target
116
117 def __call__(self, arg):
118 return '{0}_cast<{1}>({2})'.format(self.cast, self.target, arg)
119
120
121class Literal(object):
122 '''Decorate an argument with a literal operator.'''
123
Brad Bishop134d2cb2017-02-23 12:37:56 -0500124 integer_types = [
125 'int8',
126 'int16',
127 'int32',
128 'int64',
129 'uint8',
130 'uint16',
131 'uint32',
132 'uint64'
133 ]
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500134
135 def __init__(self, type):
136 self.type = type
137
138 def __call__(self, arg):
Brad Bishop134d2cb2017-02-23 12:37:56 -0500139 if 'uint' in self.type:
140 arg = '{0}ull'.format(arg)
141 elif 'int' in self.type:
142 arg = '{0}ll'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500143
Brad Bishop134d2cb2017-02-23 12:37:56 -0500144 if self.type in self.integer_types:
145 return Cast('static', '{0}_t'.format(self.type))(arg)
146
147 if self.type == 'string':
148 return '{0}s'.format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500149
150 return arg
151
152
Brad Bishop75800cf2017-01-21 15:24:18 -0500153class Argument(NamedElement, Renderer):
154 '''Define argument type inteface.'''
155
156 def __init__(self, **kw):
157 self.type = kw.pop('type', None)
158 super(Argument, self).__init__(**kw)
159
160 def argument(self, loader, indent):
161 raise NotImplementedError
162
163
164class TrivialArgument(Argument):
165 '''Non-array type arguments.'''
Brad Bishop14a9fe52016-11-12 12:51:26 -0500166
Brad Bishop22cfbe62016-11-30 13:25:10 -0500167 def __init__(self, **kw):
168 self.value = kw.pop('value')
Brad Bishop75800cf2017-01-21 15:24:18 -0500169 self.decorators = kw.pop('decorators', [])
170 if kw.get('type', None) == 'string':
171 self.decorators.insert(0, Quote())
Brad Bishopdb9b3252017-01-30 08:58:40 -0500172 if kw.get('type', None) == 'boolean':
173 self.decorators.insert(0, FixBool())
Brad Bishop75800cf2017-01-21 15:24:18 -0500174
Brad Bishop75800cf2017-01-21 15:24:18 -0500175 super(TrivialArgument, self).__init__(**kw)
176
177 def argument(self, loader, indent):
178 a = str(self.value)
179 for d in self.decorators:
180 a = d(a)
181
182 return a
Brad Bishop14a9fe52016-11-12 12:51:26 -0500183
Brad Bishop14a9fe52016-11-12 12:51:26 -0500184
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500185class InitializerList(Argument):
186 '''Initializer list arguments.'''
187
188 def __init__(self, **kw):
189 self.values = kw.pop('values')
190 super(InitializerList, self).__init__(**kw)
191
192 def argument(self, loader, indent):
193 return self.render(
194 loader,
195 'argument.mako.cpp',
196 arg=self,
197 indent=indent)
198
199
Brad Bishop75800cf2017-01-21 15:24:18 -0500200class DbusSignature(Argument):
201 '''DBus signature arguments.'''
202
203 def __init__(self, **kw):
204 self.sig = {x: y for x, y in kw.iteritems()}
205 kw.clear()
206 super(DbusSignature, self).__init__(**kw)
207
208 def argument(self, loader, indent):
209 return self.render(
210 loader,
211 'signature.mako.cpp',
212 signature=self,
213 indent=indent)
214
215
Brad Bishopc93bcc92017-01-21 16:23:39 -0500216class MethodCall(Argument):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500217 '''Render syntatically correct c++ method calls.'''
218
219 def __init__(self, **kw):
220 self.namespace = kw.pop('namespace', [])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500221 self.templates = kw.pop('templates', [])
222 self.args = kw.pop('args', [])
Brad Bishop22cfbe62016-11-30 13:25:10 -0500223 super(MethodCall, self).__init__(**kw)
224
Brad Bishopcab2bdd2017-01-21 15:00:54 -0500225 def call(self, loader, indent):
226 return self.render(
227 loader,
228 'method.mako.cpp',
229 method=self,
230 indent=indent)
231
232 def argument(self, loader, indent):
233 return self.call(loader, indent)
234
Brad Bishop14a9fe52016-11-12 12:51:26 -0500235
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500236class Vector(MethodCall):
237 '''Convenience type for vectors.'''
238
239 def __init__(self, **kw):
240 kw['name'] = 'vector'
241 kw['namespace'] = ['std']
242 kw['args'] = [InitializerList(values=kw.pop('args'))]
243 super(Vector, self).__init__(**kw)
244
245
Brad Bishopc1f47982017-02-09 01:27:38 -0500246class Filter(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500247 '''Convenience type for filters'''
Brad Bishopbf066a62016-10-19 08:09:44 -0400248
Brad Bishop22cfbe62016-11-30 13:25:10 -0500249 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500250 kw['name'] = 'make_filter'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500251 super(Filter, self).__init__(**kw)
Brad Bishopbf066a62016-10-19 08:09:44 -0400252
Brad Bishop0a6a4792016-11-12 12:10:07 -0500253
Brad Bishopc1f47982017-02-09 01:27:38 -0500254class Action(MethodCall):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500255 '''Convenience type for actions'''
Brad Bishop561a5652016-10-26 21:13:32 -0500256
Brad Bishop22cfbe62016-11-30 13:25:10 -0500257 def __init__(self, **kw):
Brad Bishopc1f47982017-02-09 01:27:38 -0500258 kw['name'] = 'make_action'
Brad Bishop22cfbe62016-11-30 13:25:10 -0500259 super(Action, self).__init__(**kw)
Brad Bishop92665b22016-10-26 20:51:16 -0500260
Brad Bishopcfb3c892016-11-12 11:43:37 -0500261
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500262class PathCondition(MethodCall):
263 '''Convenience type for path conditions'''
264
265 def __init__(self, **kw):
266 kw['name'] = 'make_path_condition'
267 super(PathCondition, self).__init__(**kw)
268
269
Brad Bishopc1f47982017-02-09 01:27:38 -0500270class CreateObjects(MethodCall):
271 '''Assemble a createObjects functor.'''
Brad Bishopdb92c282017-01-21 23:44:28 -0500272
273 def __init__(self, **kw):
274 objs = []
275
276 for path, interfaces in kw.pop('objs').iteritems():
277 key_o = TrivialArgument(
278 value=path,
279 type='string',
280 decorators=[Literal('string')])
281 value_i = []
282
283 for interface, properties, in interfaces.iteritems():
284 key_i = TrivialArgument(value=interface, type='string')
285 value_p = []
286
287 for prop, value in properties.iteritems():
288 key_p = TrivialArgument(value=prop, type='string')
289 value_v = TrivialArgument(
290 decorators=[Literal(value.get('type', None))],
291 **value)
292 value_p.append(InitializerList(values=[key_p, value_v]))
293
294 value_p = InitializerList(values=value_p)
295 value_i.append(InitializerList(values=[key_i, value_p]))
296
297 value_i = InitializerList(values=value_i)
298 objs.append(InitializerList(values=[key_o, value_i]))
299
300 kw['args'] = [InitializerList(values=objs)]
Brad Bishopc1f47982017-02-09 01:27:38 -0500301 kw['namespace'] = ['functor']
Brad Bishopdb92c282017-01-21 23:44:28 -0500302 super(CreateObjects, self).__init__(**kw)
303
304
Brad Bishopc1f47982017-02-09 01:27:38 -0500305class DestroyObjects(MethodCall):
306 '''Assemble a destroyObject functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500307
308 def __init__(self, **kw):
Brad Bishop7b7e7122017-01-21 21:21:46 -0500309 values = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500310 conditions = [
311 Event.functor_map[
312 x['name']](**x) for x in kw.pop('conditions', [])]
313 conditions = [PathCondition(args=[x]) for x in conditions]
Brad Bishop7b7e7122017-01-21 21:21:46 -0500314 args = [InitializerList(
315 values=[TrivialArgument(**x) for x in values])]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500316 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500317 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500318 kw['namespace'] = ['functor']
Brad Bishop7b7e7122017-01-21 21:21:46 -0500319 super(DestroyObjects, self).__init__(**kw)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500320
321
Brad Bishopc1f47982017-02-09 01:27:38 -0500322class SetProperty(MethodCall):
323 '''Assemble a setProperty functor.'''
Brad Bishope2e402f2016-11-30 18:00:17 -0500324
325 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500326 args = []
327
328 value = kw.pop('value')
329 prop = kw.pop('property')
330 iface = kw.pop('interface')
331 iface = Interface(iface)
332 namespace = iface.namespace().split('::')[:-1]
333 name = iface[-1]
334 t = Template(namespace=namespace, name=iface[-1])
335
Brad Bishope2e402f2016-11-30 18:00:17 -0500336 member = '&%s' % '::'.join(
Brad Bishopc93bcc92017-01-21 16:23:39 -0500337 namespace + [name, NamedElement(name=prop).camelCase])
338 member_type = cppTypeName(value['type'])
339 member_cast = '{0} ({1}::*)({0})'.format(member_type, t.qualified())
Brad Bishope2e402f2016-11-30 18:00:17 -0500340
Brad Bishop02ca0212017-01-28 23:25:58 -0500341 paths = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
342 args.append(InitializerList(
343 values=[TrivialArgument(**x) for x in paths]))
344
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500345 conditions = [
346 Event.functor_map[
347 x['name']](**x) for x in kw.pop('conditions', [])]
348 conditions = [PathCondition(args=[x]) for x in conditions]
349
350 args.append(InitializerList(values=conditions))
Brad Bishopc93bcc92017-01-21 16:23:39 -0500351 args.append(TrivialArgument(value=str(iface), type='string'))
352 args.append(TrivialArgument(
353 value=member, decorators=[Cast('static', member_cast)]))
354 args.append(TrivialArgument(**value))
Brad Bishope2e402f2016-11-30 18:00:17 -0500355
Brad Bishopc93bcc92017-01-21 16:23:39 -0500356 kw['templates'] = [Template(name=name, namespace=namespace)]
357 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500358 kw['namespace'] = ['functor']
Brad Bishope2e402f2016-11-30 18:00:17 -0500359 super(SetProperty, self).__init__(**kw)
360
361
Brad Bishopc1f47982017-02-09 01:27:38 -0500362class PropertyChanged(MethodCall):
363 '''Assemble a propertyChanged functor.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500364
365 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500366 args = []
367 args.append(TrivialArgument(value=kw.pop('interface'), type='string'))
368 args.append(TrivialArgument(value=kw.pop('property'), type='string'))
369 args.append(TrivialArgument(
370 decorators=[
371 Literal(kw['value'].get('type', None))], **kw.pop('value')))
372 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500373 kw['namespace'] = ['functor']
Brad Bishop22cfbe62016-11-30 13:25:10 -0500374 super(PropertyChanged, self).__init__(**kw)
375
376
Brad Bishopc1f47982017-02-09 01:27:38 -0500377class PropertyIs(MethodCall):
378 '''Assemble a propertyIs functor.'''
Brad Bishop040e18b2017-01-21 22:04:00 -0500379
380 def __init__(self, **kw):
381 args = []
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500382 path = kw.pop('path', None)
383 if not path:
384 path = TrivialArgument(value='nullptr')
385 else:
386 path = TrivialArgument(value=path, type='string')
387
388 args.append(path)
Brad Bishop040e18b2017-01-21 22:04:00 -0500389 args.append(TrivialArgument(value=kw.pop('interface'), type='string'))
390 args.append(TrivialArgument(value=kw.pop('property'), type='string'))
391 args.append(TrivialArgument(
392 decorators=[
393 Literal(kw['value'].get('type', None))], **kw.pop('value')))
394
395 service = kw.pop('service', None)
396 if service:
397 args.append(TrivialArgument(value=service, type='string'))
398
399 kw['args'] = args
Brad Bishopc1f47982017-02-09 01:27:38 -0500400 kw['namespace'] = ['functor']
Brad Bishop040e18b2017-01-21 22:04:00 -0500401 super(PropertyIs, self).__init__(**kw)
402
403
Brad Bishopc93bcc92017-01-21 16:23:39 -0500404class Event(MethodCall):
405 '''Assemble an inventory manager event.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500406
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500407 functor_map = {
Brad Bishop7b7e7122017-01-21 21:21:46 -0500408 'destroyObjects': DestroyObjects,
Brad Bishopdb92c282017-01-21 23:44:28 -0500409 'createObjects': CreateObjects,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500410 'propertyChangedTo': PropertyChanged,
Brad Bishop040e18b2017-01-21 22:04:00 -0500411 'propertyIs': PropertyIs,
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500412 'setProperty': SetProperty,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500413 }
414
Brad Bishop22cfbe62016-11-30 13:25:10 -0500415 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500416 self.summary = kw.pop('name')
417
418 filters = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500419 self.functor_map[x['name']](**x) for x in kw.pop('filters', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500420 filters = [Filter(args=[x]) for x in filters]
Brad Bishop064c94a2017-01-21 21:33:30 -0500421 filters = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500422 templates=[Template(name='Filter', namespace=[])],
Brad Bishop064c94a2017-01-21 21:33:30 -0500423 args=filters)
Brad Bishopc93bcc92017-01-21 16:23:39 -0500424
425 event = MethodCall(
426 name='make_shared',
427 namespace=['std'],
428 templates=[Template(
429 name=kw.pop('event'),
430 namespace=kw.pop('event_namespace', []))],
Brad Bishop064c94a2017-01-21 21:33:30 -0500431 args=kw.pop('event_args', []) + [filters])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500432
433 events = Vector(
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500434 templates=[Template(name='EventBasePtr', namespace=[])],
Brad Bishopc93bcc92017-01-21 16:23:39 -0500435 args=[event])
436
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500437 action_type = Template(name='Action', namespace=[])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500438 action_args = [
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500439 self.functor_map[x['name']](**x) for x in kw.pop('actions', [])]
Brad Bishopc1f47982017-02-09 01:27:38 -0500440 action_args = [Action(args=[x]) for x in action_args]
Brad Bishopc93bcc92017-01-21 16:23:39 -0500441 actions = Vector(
442 templates=[action_type],
443 args=action_args)
444
445 kw['name'] = 'make_tuple'
446 kw['namespace'] = ['std']
447 kw['args'] = [events, actions]
Brad Bishop22cfbe62016-11-30 13:25:10 -0500448 super(Event, self).__init__(**kw)
Brad Bishopcfb3c892016-11-12 11:43:37 -0500449
Brad Bishopcfb3c892016-11-12 11:43:37 -0500450
Brad Bishop22cfbe62016-11-30 13:25:10 -0500451class MatchEvent(Event):
452 '''Associate one or more dbus signal match signatures with
453 a filter.'''
454
Brad Bishop22cfbe62016-11-30 13:25:10 -0500455 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500456 kw['event'] = 'DbusSignal'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500457 kw['event_namespace'] = []
Brad Bishopc93bcc92017-01-21 16:23:39 -0500458 kw['event_args'] = [
459 DbusSignature(**x) for x in kw.pop('signatures', [])]
460
Brad Bishop22cfbe62016-11-30 13:25:10 -0500461 super(MatchEvent, self).__init__(**kw)
462
463
Brad Bishop828df832017-01-21 22:20:43 -0500464class StartupEvent(Event):
465 '''Assemble a startup event.'''
466
467 def __init__(self, **kw):
468 kw['event'] = 'StartupEvent'
Brad Bishop12f8a3c2017-02-09 00:02:00 -0500469 kw['event_namespace'] = []
Brad Bishop828df832017-01-21 22:20:43 -0500470 super(StartupEvent, self).__init__(**kw)
471
472
Brad Bishop22cfbe62016-11-30 13:25:10 -0500473class Everything(Renderer):
474 '''Parse/render entry point.'''
475
476 class_map = {
477 'match': MatchEvent,
Brad Bishop828df832017-01-21 22:20:43 -0500478 'startup': StartupEvent,
Brad Bishop22cfbe62016-11-30 13:25:10 -0500479 }
480
481 @staticmethod
482 def load(args):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500483 # Aggregate all the event YAML in the events.d directory
484 # into a single list of events.
485
Brad Bishop22cfbe62016-11-30 13:25:10 -0500486 events = []
Brad Bishopa6fcd562017-02-03 11:00:27 -0500487 events_dir = os.path.join(args.inputdir, 'events.d')
488
489 if os.path.exists(events_dir):
490 yaml_files = filter(
491 lambda x: x.endswith('.yaml'),
492 os.listdir(events_dir))
493
494 for x in yaml_files:
495 with open(os.path.join(events_dir, x), 'r') as fd:
496 for e in yaml.safe_load(fd.read()).get('events', {}):
497 events.append(e)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500498
Deepak Kodihallief550b12017-08-03 14:00:17 -0500499 interfaces, interface_composite = Everything.get_interfaces(
500 args.ifacesdir)
501 extra_interfaces, extra_interface_composite = \
502 Everything.get_interfaces(
503 os.path.join(args.inputdir, 'extra_interfaces.d'))
504 interface_composite.update(extra_interface_composite)
505 interface_composite = InterfaceComposite(interface_composite)
Brad Bishop834989f2017-02-06 12:08:20 -0500506
Brad Bishop22cfbe62016-11-30 13:25:10 -0500507 return Everything(
508 *events,
Deepak Kodihallief550b12017-08-03 14:00:17 -0500509 interfaces=interfaces + extra_interfaces,
510 interface_composite=interface_composite)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500511
512 @staticmethod
Brad Bishop834989f2017-02-06 12:08:20 -0500513 def get_interfaces(targetdir):
514 '''Scan the interfaces directory for interfaces that PIM can create.'''
Brad Bishop22cfbe62016-11-30 13:25:10 -0500515
Brad Bishop834989f2017-02-06 12:08:20 -0500516 yaml_files = []
Brad Bishop22cfbe62016-11-30 13:25:10 -0500517 interfaces = []
Deepak Kodihallief550b12017-08-03 14:00:17 -0500518 interface_composite = {}
Brad Bishopa6fcd562017-02-03 11:00:27 -0500519
Brad Bishop834989f2017-02-06 12:08:20 -0500520 if targetdir and os.path.exists(targetdir):
521 for directory, _, files in os.walk(targetdir):
522 if not files:
523 continue
524
525 yaml_files += map(
526 lambda f: os.path.relpath(
527 os.path.join(directory, f),
528 targetdir),
529 filter(lambda f: f.endswith('.interface.yaml'), files))
530
531 for y in yaml_files:
Marri Devender Rao06e3d502017-06-09 11:33:38 -0500532 # parse only phosphor dbus related interface files
533 if not y.startswith('xyz'):
534 continue
Brad Bishop834989f2017-02-06 12:08:20 -0500535 with open(os.path.join(targetdir, y)) as fd:
536 i = y.replace('.interface.yaml', '').replace(os.sep, '.')
537
538 # PIM can't create interfaces with methods.
539 # PIM can't create interfaces without properties.
540 parsed = yaml.safe_load(fd.read())
541 if parsed.get('methods', None):
542 continue
Deepak Kodihallief550b12017-08-03 14:00:17 -0500543 properties = parsed.get('properties', None)
544 if not properties:
Brad Bishop834989f2017-02-06 12:08:20 -0500545 continue
Deepak Kodihalli0b6ca102017-08-09 04:39:43 -0500546 # Cereal can't understand the type sdbusplus::object_path. This
547 # type is a wrapper around std::string. Ignore interfaces having
548 # a property of this type for now. The only interface that has a
549 # property of this type now is xyz.openbmc_project.Association,
550 # which is an unused interface. No inventory objects implement
551 # this interface.
552 # TODO via openbmc/openbmc#2123 : figure out how to make Cereal
553 # understand sdbusplus::object_path.
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