blob: 0b635bbbba77f3a914df07f3f3f29a3660a31d35 [file] [log] [blame]
Patrick Williams55878982020-04-03 15:24:57 -05001#!/usr/bin/env python3
Brad Bishopbf066a62016-10-19 08:09:44 -04002
Patrick Williams5de46b32022-12-05 10:03:44 -06003"""Phosphor Inventory Manager YAML parser and code generator.
Brad Bishop22cfbe62016-11-30 13:25:10 -05004
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.
Patrick Williams5de46b32022-12-05 10:03:44 -060016"""
Brad Bishop22cfbe62016-11-30 13:25:10 -050017
Brad Bishopbf066a62016-10-19 08:09:44 -040018import argparse
Patrick Williams5de46b32022-12-05 10:03:44 -060019import os
20import sys
21
Brad Bishop22cfbe62016-11-30 13:25:10 -050022import mako.lookup
23import sdbusplus.property
Patrick Williams5de46b32022-12-05 10:03:44 -060024import yaml
Brad Bishop22cfbe62016-11-30 13:25:10 -050025from sdbusplus.namedelement import NamedElement
26from sdbusplus.renderer import Renderer
Brad Bishopbf066a62016-10-19 08:09:44 -040027
Matthew Barth979eb592018-10-05 15:29:26 -050028# Global busname for use within classes where necessary
29busname = "xyz.openbmc_project.Inventory.Manager"
30
31
Brad Bishop9b5a12f2017-01-21 14:42:11 -050032def cppTypeName(yaml_type):
Patrick Williams5de46b32022-12-05 10:03:44 -060033 """Convert yaml types to cpp types."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -050034 return sdbusplus.property.Property(type=yaml_type).cppTypeName
35
36
Deepak Kodihallief550b12017-08-03 14:00:17 -050037class InterfaceComposite(object):
Patrick Williams5de46b32022-12-05 10:03:44 -060038 """Compose interface properties."""
Deepak Kodihallief550b12017-08-03 14:00:17 -050039
40 def __init__(self, dict):
41 self.dict = dict
42
Deepak Kodihallief550b12017-08-03 14:00:17 -050043 def interfaces(self):
Patrick Williams55878982020-04-03 15:24:57 -050044 return list(self.dict.keys())
Deepak Kodihallief550b12017-08-03 14:00:17 -050045
46 def names(self, interface):
Marri Devender Raofa23d702017-09-02 04:43:42 -050047 names = []
48 if self.dict[interface]:
Patrick Williams5de46b32022-12-05 10:03:44 -060049 names = [
50 NamedElement(name=x["name"]) for x in self.dict[interface]
51 ]
Deepak Kodihallief550b12017-08-03 14:00:17 -050052 return names
53
54
Brad Bishop22cfbe62016-11-30 13:25:10 -050055class Interface(list):
Patrick Williams5de46b32022-12-05 10:03:44 -060056 """Provide various interface transformations."""
Brad Bishop22cfbe62016-11-30 13:25:10 -050057
58 def __init__(self, iface):
Patrick Williams5de46b32022-12-05 10:03:44 -060059 super(Interface, self).__init__(iface.split("."))
Brad Bishop22cfbe62016-11-30 13:25:10 -050060
61 def namespace(self):
Patrick Williams5de46b32022-12-05 10:03:44 -060062 """Represent as an sdbusplus namespace."""
63 return "::".join(["sdbusplus"] + self[:-1] + ["server", self[-1]])
Brad Bishop22cfbe62016-11-30 13:25:10 -050064
65 def header(self):
Patrick Williams5de46b32022-12-05 10:03:44 -060066 """Represent as an sdbusplus server binding header."""
67 return os.sep.join(self + ["server.hpp"])
Brad Bishop22cfbe62016-11-30 13:25:10 -050068
69 def __str__(self):
Patrick Williams5de46b32022-12-05 10:03:44 -060070 return ".".join(self)
Brad Bishopbf066a62016-10-19 08:09:44 -040071
Brad Bishopcfb3c892016-11-12 11:43:37 -050072
Brad Bishop9b5a12f2017-01-21 14:42:11 -050073class Indent(object):
Patrick Williams5de46b32022-12-05 10:03:44 -060074 """Help templates be depth agnostic."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -050075
76 def __init__(self, depth=0):
77 self.depth = depth
78
79 def __add__(self, depth):
80 return Indent(self.depth + depth)
81
82 def __call__(self, depth):
Patrick Williams5de46b32022-12-05 10:03:44 -060083 """Render an indent at the current depth plus depth."""
84 return 4 * " " * (depth + self.depth)
Brad Bishop9b5a12f2017-01-21 14:42:11 -050085
86
87class Template(NamedElement):
Patrick Williams5de46b32022-12-05 10:03:44 -060088 """Associate a template name with its namespace."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -050089
90 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -060091 self.namespace = kw.pop("namespace", [])
Brad Bishop9b5a12f2017-01-21 14:42:11 -050092 super(Template, self).__init__(**kw)
93
94 def qualified(self):
Patrick Williams5de46b32022-12-05 10:03:44 -060095 return "::".join(self.namespace + [self.name])
Brad Bishop9b5a12f2017-01-21 14:42:11 -050096
97
Brad Bishopdb9b3252017-01-30 08:58:40 -050098class FixBool(object):
Patrick Williams5de46b32022-12-05 10:03:44 -060099 """Un-capitalize booleans."""
Brad Bishopdb9b3252017-01-30 08:58:40 -0500100
101 def __call__(self, arg):
Patrick Williams5de46b32022-12-05 10:03:44 -0600102 return "{0}".format(arg.lower())
Brad Bishopdb9b3252017-01-30 08:58:40 -0500103
104
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500105class Quote(object):
Patrick Williams5de46b32022-12-05 10:03:44 -0600106 """Decorate an argument by quoting it."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500107
108 def __call__(self, arg):
109 return '"{0}"'.format(arg)
110
111
112class Cast(object):
Patrick Williams5de46b32022-12-05 10:03:44 -0600113 """Decorate an argument by casting it."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500114
115 def __init__(self, cast, target):
Patrick Williams5de46b32022-12-05 10:03:44 -0600116 """cast is the cast type (static, const, etc...).
117 target is the cast target type."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500118 self.cast = cast
119 self.target = target
120
121 def __call__(self, arg):
Patrick Williams5de46b32022-12-05 10:03:44 -0600122 return "{0}_cast<{1}>({2})".format(self.cast, self.target, arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500123
124
125class Literal(object):
Patrick Williams5de46b32022-12-05 10:03:44 -0600126 """Decorate an argument with a literal operator."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500127
Brad Bishop134d2cb2017-02-23 12:37:56 -0500128 integer_types = [
Patrick Williams5de46b32022-12-05 10:03:44 -0600129 "int8",
130 "int16",
131 "int32",
132 "int64",
133 "uint8",
134 "uint16",
135 "uint32",
136 "uint64",
Brad Bishop134d2cb2017-02-23 12:37:56 -0500137 ]
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500138
139 def __init__(self, type):
140 self.type = type
141
142 def __call__(self, arg):
Patrick Williams5de46b32022-12-05 10:03:44 -0600143 if "uint" in self.type:
144 arg = "{0}ull".format(arg)
145 elif "int" in self.type:
146 arg = "{0}ll".format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500147
Brad Bishop134d2cb2017-02-23 12:37:56 -0500148 if self.type in self.integer_types:
Patrick Williams5de46b32022-12-05 10:03:44 -0600149 return Cast("static", "{0}_t".format(self.type))(arg)
Brad Bishop134d2cb2017-02-23 12:37:56 -0500150
Patrick Williams5de46b32022-12-05 10:03:44 -0600151 if self.type == "string":
152 return "{0}s".format(arg)
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500153
154 return arg
155
156
Brad Bishop75800cf2017-01-21 15:24:18 -0500157class Argument(NamedElement, Renderer):
Patrick Williams5de46b32022-12-05 10:03:44 -0600158 """Define argument type inteface."""
Brad Bishop75800cf2017-01-21 15:24:18 -0500159
160 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600161 self.type = kw.pop("type", None)
Brad Bishop75800cf2017-01-21 15:24:18 -0500162 super(Argument, self).__init__(**kw)
163
164 def argument(self, loader, indent):
165 raise NotImplementedError
166
167
168class TrivialArgument(Argument):
Patrick Williams5de46b32022-12-05 10:03:44 -0600169 """Non-array type arguments."""
Brad Bishop14a9fe52016-11-12 12:51:26 -0500170
Brad Bishop22cfbe62016-11-30 13:25:10 -0500171 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600172 self.value = kw.pop("value")
173 self.decorators = kw.pop("decorators", [])
174 if kw.get("type", None) == "string":
Brad Bishop75800cf2017-01-21 15:24:18 -0500175 self.decorators.insert(0, Quote())
Patrick Williams5de46b32022-12-05 10:03:44 -0600176 if kw.get("type", None) == "boolean":
Brad Bishopdb9b3252017-01-30 08:58:40 -0500177 self.decorators.insert(0, FixBool())
Brad Bishop75800cf2017-01-21 15:24:18 -0500178
Brad Bishop75800cf2017-01-21 15:24:18 -0500179 super(TrivialArgument, self).__init__(**kw)
180
181 def argument(self, loader, indent):
182 a = str(self.value)
183 for d in self.decorators:
184 a = d(a)
185
186 return a
Brad Bishop14a9fe52016-11-12 12:51:26 -0500187
Brad Bishop14a9fe52016-11-12 12:51:26 -0500188
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500189class InitializerList(Argument):
Patrick Williams5de46b32022-12-05 10:03:44 -0600190 """Initializer list arguments."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500191
192 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600193 self.values = kw.pop("values")
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500194 super(InitializerList, self).__init__(**kw)
195
196 def argument(self, loader, indent):
197 return self.render(
Patrick Williams5de46b32022-12-05 10:03:44 -0600198 loader, "argument.mako.cpp", arg=self, indent=indent
199 )
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500200
201
Brad Bishop75800cf2017-01-21 15:24:18 -0500202class DbusSignature(Argument):
Patrick Williams5de46b32022-12-05 10:03:44 -0600203 """DBus signature arguments."""
Brad Bishop75800cf2017-01-21 15:24:18 -0500204
205 def __init__(self, **kw):
Patrick Williams55878982020-04-03 15:24:57 -0500206 self.sig = {x: y for x, y in kw.items()}
Brad Bishop75800cf2017-01-21 15:24:18 -0500207 kw.clear()
208 super(DbusSignature, self).__init__(**kw)
209
210 def argument(self, loader, indent):
211 return self.render(
Patrick Williams5de46b32022-12-05 10:03:44 -0600212 loader, "signature.mako.cpp", signature=self, indent=indent
213 )
Brad Bishop75800cf2017-01-21 15:24:18 -0500214
215
Brad Bishopc93bcc92017-01-21 16:23:39 -0500216class MethodCall(Argument):
Patrick Williams5de46b32022-12-05 10:03:44 -0600217 """Render syntatically correct c++ method calls."""
Brad Bishop22cfbe62016-11-30 13:25:10 -0500218
219 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600220 self.namespace = kw.pop("namespace", [])
221 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(
Patrick Williams5de46b32022-12-05 10:03:44 -0600227 loader, "method.mako.cpp", method=self, indent=indent
228 )
Brad Bishopcab2bdd2017-01-21 15:00:54 -0500229
230 def argument(self, loader, indent):
231 return self.call(loader, indent)
232
Brad Bishop14a9fe52016-11-12 12:51:26 -0500233
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500234class Vector(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600235 """Convenience type for vectors."""
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500236
237 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600238 kw["name"] = "vector"
239 kw["namespace"] = ["std"]
240 kw["args"] = [InitializerList(values=kw.pop("args"))]
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500241 super(Vector, self).__init__(**kw)
242
243
Brad Bishopc1f47982017-02-09 01:27:38 -0500244class Filter(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600245 """Convenience type for filters"""
Brad Bishopbf066a62016-10-19 08:09:44 -0400246
Brad Bishop22cfbe62016-11-30 13:25:10 -0500247 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600248 kw["name"] = "make_filter"
Brad Bishop22cfbe62016-11-30 13:25:10 -0500249 super(Filter, self).__init__(**kw)
Brad Bishopbf066a62016-10-19 08:09:44 -0400250
Brad Bishop0a6a4792016-11-12 12:10:07 -0500251
Brad Bishopc1f47982017-02-09 01:27:38 -0500252class Action(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600253 """Convenience type for actions"""
Brad Bishop561a5652016-10-26 21:13:32 -0500254
Brad Bishop22cfbe62016-11-30 13:25:10 -0500255 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600256 kw["name"] = "make_action"
Brad Bishop22cfbe62016-11-30 13:25:10 -0500257 super(Action, self).__init__(**kw)
Brad Bishop92665b22016-10-26 20:51:16 -0500258
Brad Bishopcfb3c892016-11-12 11:43:37 -0500259
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500260class PathCondition(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600261 """Convenience type for path conditions"""
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500262
263 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600264 kw["name"] = "make_path_condition"
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500265 super(PathCondition, self).__init__(**kw)
266
267
Matthew Barth979eb592018-10-05 15:29:26 -0500268class GetProperty(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600269 """Convenience type for getting inventory properties"""
Matthew Barth979eb592018-10-05 15:29:26 -0500270
271 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600272 kw["name"] = "make_get_property"
Matthew Barth979eb592018-10-05 15:29:26 -0500273 super(GetProperty, self).__init__(**kw)
274
275
Brad Bishopc1f47982017-02-09 01:27:38 -0500276class CreateObjects(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600277 """Assemble a createObjects functor."""
Brad Bishopdb92c282017-01-21 23:44:28 -0500278
279 def __init__(self, **kw):
280 objs = []
281
Patrick Williams5de46b32022-12-05 10:03:44 -0600282 for path, interfaces in kw.pop("objs").items():
Brad Bishopdb92c282017-01-21 23:44:28 -0500283 key_o = TrivialArgument(
Patrick Williams5de46b32022-12-05 10:03:44 -0600284 value=path, type="string", decorators=[Literal("string")]
285 )
Brad Bishopdb92c282017-01-21 23:44:28 -0500286 value_i = []
287
Patrick Williams5de46b32022-12-05 10:03:44 -0600288 for (
289 interface,
290 properties,
291 ) in interfaces.items():
292 key_i = TrivialArgument(value=interface, type="string")
Brad Bishopdb92c282017-01-21 23:44:28 -0500293 value_p = []
Marri Devender Raofa23d702017-09-02 04:43:42 -0500294 if properties:
Patrick Williams55878982020-04-03 15:24:57 -0500295 for prop, value in properties.items():
Patrick Williams5de46b32022-12-05 10:03:44 -0600296 key_p = TrivialArgument(value=prop, type="string")
Marri Devender Raofa23d702017-09-02 04:43:42 -0500297 value_v = TrivialArgument(
Patrick Williams5de46b32022-12-05 10:03:44 -0600298 decorators=[Literal(value.get("type", None))],
299 **value
300 )
301 value_p.append(
302 InitializerList(values=[key_p, value_v])
303 )
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
Patrick Williams5de46b32022-12-05 10:03:44 -0600311 kw["args"] = [InitializerList(values=objs)]
312 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):
Patrick Williams5de46b32022-12-05 10:03:44 -0600317 """Assemble a destroyObject functor."""
Brad Bishop22cfbe62016-11-30 13:25:10 -0500318
319 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600320 values = [{"value": x, "type": "string"} for x in kw.pop("paths")]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500321 conditions = [
Patrick Williams5de46b32022-12-05 10:03:44 -0600322 Event.functor_map[x["name"]](**x) for x in kw.pop("conditions", [])
323 ]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500324 conditions = [PathCondition(args=[x]) for x in conditions]
Patrick Williams5de46b32022-12-05 10:03:44 -0600325 args = [InitializerList(values=[TrivialArgument(**x) for x in values])]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500326 args.append(InitializerList(values=conditions))
Patrick Williams5de46b32022-12-05 10:03:44 -0600327 kw["args"] = args
328 kw["namespace"] = ["functor"]
Brad Bishop7b7e7122017-01-21 21:21:46 -0500329 super(DestroyObjects, self).__init__(**kw)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500330
331
Brad Bishopc1f47982017-02-09 01:27:38 -0500332class SetProperty(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600333 """Assemble a setProperty functor."""
Brad Bishope2e402f2016-11-30 18:00:17 -0500334
335 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500336 args = []
337
Patrick Williams5de46b32022-12-05 10:03:44 -0600338 value = kw.pop("value")
339 prop = kw.pop("property")
340 iface = kw.pop("interface")
Brad Bishopc93bcc92017-01-21 16:23:39 -0500341 iface = Interface(iface)
Patrick Williams5de46b32022-12-05 10:03:44 -0600342 namespace = iface.namespace().split("::")[:-1]
Brad Bishopc93bcc92017-01-21 16:23:39 -0500343 name = iface[-1]
344 t = Template(namespace=namespace, name=iface[-1])
345
Patrick Williams5de46b32022-12-05 10:03:44 -0600346 member = "&%s" % "::".join(
347 namespace + [name, NamedElement(name=prop).camelCase]
348 )
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
Patrick Williams5de46b32022-12-05 10:03:44 -0600352 paths = [{"value": x, "type": "string"} for x in kw.pop("paths")]
353 args.append(
354 InitializerList(values=[TrivialArgument(**x) for x in paths])
355 )
Brad Bishop02ca0212017-01-28 23:25:58 -0500356
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500357 conditions = [
Patrick Williams5de46b32022-12-05 10:03:44 -0600358 Event.functor_map[x["name"]](**x) for x in kw.pop("conditions", [])
359 ]
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500360 conditions = [PathCondition(args=[x]) for x in conditions]
361
362 args.append(InitializerList(values=conditions))
Patrick Williams5de46b32022-12-05 10:03:44 -0600363 args.append(TrivialArgument(value=str(iface), type="string"))
364 args.append(
365 TrivialArgument(
366 value=member, decorators=[Cast("static", member_cast)]
367 )
368 )
Brad Bishopc93bcc92017-01-21 16:23:39 -0500369 args.append(TrivialArgument(**value))
Brad Bishope2e402f2016-11-30 18:00:17 -0500370
Patrick Williams5de46b32022-12-05 10:03:44 -0600371 kw["templates"] = [Template(name=name, namespace=namespace)]
372 kw["args"] = args
373 kw["namespace"] = ["functor"]
Brad Bishope2e402f2016-11-30 18:00:17 -0500374 super(SetProperty, self).__init__(**kw)
375
376
Brad Bishopc1f47982017-02-09 01:27:38 -0500377class PropertyChanged(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600378 """Assemble a propertyChanged functor."""
Brad Bishop22cfbe62016-11-30 13:25:10 -0500379
380 def __init__(self, **kw):
Brad Bishopc93bcc92017-01-21 16:23:39 -0500381 args = []
Patrick Williams5de46b32022-12-05 10:03:44 -0600382 args.append(TrivialArgument(value=kw.pop("interface"), type="string"))
383 args.append(TrivialArgument(value=kw.pop("property"), type="string"))
384 args.append(
385 TrivialArgument(
386 decorators=[Literal(kw["value"].get("type", None))],
387 **kw.pop("value")
388 )
389 )
390 kw["args"] = args
391 kw["namespace"] = ["functor"]
Brad Bishop22cfbe62016-11-30 13:25:10 -0500392 super(PropertyChanged, self).__init__(**kw)
393
394
Brad Bishopc1f47982017-02-09 01:27:38 -0500395class PropertyIs(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600396 """Assemble a propertyIs functor."""
Brad Bishop040e18b2017-01-21 22:04:00 -0500397
398 def __init__(self, **kw):
399 args = []
Patrick Williams5de46b32022-12-05 10:03:44 -0600400 path = kw.pop("path", None)
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500401 if not path:
Patrick Williams5de46b32022-12-05 10:03:44 -0600402 path = TrivialArgument(value="nullptr")
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500403 else:
Patrick Williams5de46b32022-12-05 10:03:44 -0600404 path = TrivialArgument(value=path, type="string")
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500405
406 args.append(path)
Patrick Williams5de46b32022-12-05 10:03:44 -0600407 iface = TrivialArgument(value=kw.pop("interface"), type="string")
Matthew Barth979eb592018-10-05 15:29:26 -0500408 args.append(iface)
Patrick Williams5de46b32022-12-05 10:03:44 -0600409 prop = TrivialArgument(value=kw.pop("property"), type="string")
Matthew Barth979eb592018-10-05 15:29:26 -0500410 args.append(prop)
Patrick Williams5de46b32022-12-05 10:03:44 -0600411 args.append(
412 TrivialArgument(
413 decorators=[Literal(kw["value"].get("type", None))],
414 **kw.pop("value")
415 )
416 )
Brad Bishop040e18b2017-01-21 22:04:00 -0500417
Patrick Williams5de46b32022-12-05 10:03:44 -0600418 service = kw.pop("service", None)
Brad Bishop040e18b2017-01-21 22:04:00 -0500419 if service:
Patrick Williams5de46b32022-12-05 10:03:44 -0600420 args.append(TrivialArgument(value=service, type="string"))
Brad Bishop040e18b2017-01-21 22:04:00 -0500421
Patrick Williams5de46b32022-12-05 10:03:44 -0600422 dbusMember = kw.pop("dbusMember", None)
Matthew Barth979eb592018-10-05 15:29:26 -0500423 if dbusMember:
424 # Inventory manager's service name is required
425 if not service or service != busname:
Patrick Williams5de46b32022-12-05 10:03:44 -0600426 args.append(TrivialArgument(value=busname, type="string"))
Matthew Barth979eb592018-10-05 15:29:26 -0500427
428 gpArgs = []
429 gpArgs.append(path)
430 gpArgs.append(iface)
431 # Prepend '&' and append 'getPropertyByName' function on dbusMember
Patrick Williams5de46b32022-12-05 10:03:44 -0600432 gpArgs.append(
433 TrivialArgument(value="&" + dbusMember + "::getPropertyByName")
434 )
Matthew Barth979eb592018-10-05 15:29:26 -0500435 gpArgs.append(prop)
436 fArg = MethodCall(
Patrick Williams5de46b32022-12-05 10:03:44 -0600437 name="getProperty",
438 namespace=["functor"],
439 templates=[Template(name=dbusMember, namespace=[])],
440 args=gpArgs,
441 )
Matthew Barth979eb592018-10-05 15:29:26 -0500442
443 # Append getProperty functor
Patrick Williams5de46b32022-12-05 10:03:44 -0600444 args.append(
445 GetProperty(
446 templates=[
447 Template(
448 name=dbusMember + "::PropertiesVariant",
449 namespace=[],
450 )
451 ],
452 args=[fArg],
453 )
454 )
Matthew Barth979eb592018-10-05 15:29:26 -0500455
Patrick Williams5de46b32022-12-05 10:03:44 -0600456 kw["args"] = args
457 kw["namespace"] = ["functor"]
Brad Bishop040e18b2017-01-21 22:04:00 -0500458 super(PropertyIs, self).__init__(**kw)
459
460
Brad Bishopc93bcc92017-01-21 16:23:39 -0500461class Event(MethodCall):
Patrick Williams5de46b32022-12-05 10:03:44 -0600462 """Assemble an inventory manager event."""
Brad Bishop22cfbe62016-11-30 13:25:10 -0500463
Brad Bishopd0f48ad2017-01-30 08:52:26 -0500464 functor_map = {
Patrick Williams5de46b32022-12-05 10:03:44 -0600465 "destroyObjects": DestroyObjects,
466 "createObjects": CreateObjects,
467 "propertyChangedTo": PropertyChanged,
468 "propertyIs": PropertyIs,
469 "setProperty": SetProperty,
Brad Bishopc93bcc92017-01-21 16:23:39 -0500470 }
471
Brad Bishop22cfbe62016-11-30 13:25:10 -0500472 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600473 self.summary = kw.pop("name")
Brad Bishopc93bcc92017-01-21 16:23:39 -0500474
475 filters = [
Patrick Williams5de46b32022-12-05 10:03:44 -0600476 self.functor_map[x["name"]](**x) for x in kw.pop("filters", [])
477 ]
Brad Bishopc1f47982017-02-09 01:27:38 -0500478 filters = [Filter(args=[x]) for x in filters]
Brad Bishop064c94a2017-01-21 21:33:30 -0500479 filters = Vector(
Patrick Williams5de46b32022-12-05 10:03:44 -0600480 templates=[Template(name="Filter", namespace=[])], args=filters
481 )
Brad Bishopc93bcc92017-01-21 16:23:39 -0500482
483 event = MethodCall(
Patrick Williams5de46b32022-12-05 10:03:44 -0600484 name="make_shared",
485 namespace=["std"],
486 templates=[
487 Template(
488 name=kw.pop("event"),
489 namespace=kw.pop("event_namespace", []),
490 )
491 ],
492 args=kw.pop("event_args", []) + [filters],
493 )
Brad Bishopc93bcc92017-01-21 16:23:39 -0500494
495 events = Vector(
Patrick Williams5de46b32022-12-05 10:03:44 -0600496 templates=[Template(name="EventBasePtr", namespace=[])],
497 args=[event],
498 )
Brad Bishopc93bcc92017-01-21 16:23:39 -0500499
Patrick Williams5de46b32022-12-05 10:03:44 -0600500 action_type = Template(name="Action", namespace=[])
Brad Bishopc93bcc92017-01-21 16:23:39 -0500501 action_args = [
Patrick Williams5de46b32022-12-05 10:03:44 -0600502 self.functor_map[x["name"]](**x) for x in kw.pop("actions", [])
503 ]
Brad Bishopc1f47982017-02-09 01:27:38 -0500504 action_args = [Action(args=[x]) for x in action_args]
Patrick Williams5de46b32022-12-05 10:03:44 -0600505 actions = Vector(templates=[action_type], args=action_args)
Brad Bishopc93bcc92017-01-21 16:23:39 -0500506
Patrick Williams5de46b32022-12-05 10:03:44 -0600507 kw["name"] = "make_tuple"
508 kw["namespace"] = ["std"]
509 kw["args"] = [events, actions]
Brad Bishop22cfbe62016-11-30 13:25:10 -0500510 super(Event, self).__init__(**kw)
Brad Bishopcfb3c892016-11-12 11:43:37 -0500511
Brad Bishopcfb3c892016-11-12 11:43:37 -0500512
Brad Bishop22cfbe62016-11-30 13:25:10 -0500513class MatchEvent(Event):
Patrick Williams5de46b32022-12-05 10:03:44 -0600514 """Associate one or more dbus signal match signatures with
515 a filter."""
Brad Bishop22cfbe62016-11-30 13:25:10 -0500516
Brad Bishop22cfbe62016-11-30 13:25:10 -0500517 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600518 kw["event"] = "DbusSignal"
519 kw["event_namespace"] = []
520 kw["event_args"] = [
521 DbusSignature(**x) for x in kw.pop("signatures", [])
522 ]
Brad Bishopc93bcc92017-01-21 16:23:39 -0500523
Brad Bishop22cfbe62016-11-30 13:25:10 -0500524 super(MatchEvent, self).__init__(**kw)
525
526
Brad Bishop828df832017-01-21 22:20:43 -0500527class StartupEvent(Event):
Patrick Williams5de46b32022-12-05 10:03:44 -0600528 """Assemble a startup event."""
Brad Bishop828df832017-01-21 22:20:43 -0500529
530 def __init__(self, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600531 kw["event"] = "StartupEvent"
532 kw["event_namespace"] = []
Brad Bishop828df832017-01-21 22:20:43 -0500533 super(StartupEvent, self).__init__(**kw)
534
535
Brad Bishop22cfbe62016-11-30 13:25:10 -0500536class Everything(Renderer):
Patrick Williams5de46b32022-12-05 10:03:44 -0600537 """Parse/render entry point."""
Brad Bishop22cfbe62016-11-30 13:25:10 -0500538
539 class_map = {
Patrick Williams5de46b32022-12-05 10:03:44 -0600540 "match": MatchEvent,
541 "startup": StartupEvent,
Brad Bishop22cfbe62016-11-30 13:25:10 -0500542 }
543
544 @staticmethod
545 def load(args):
Brad Bishop22cfbe62016-11-30 13:25:10 -0500546 # Aggregate all the event YAML in the events.d directory
547 # into a single list of events.
548
Brad Bishop22cfbe62016-11-30 13:25:10 -0500549 events = []
Patrick Williams5de46b32022-12-05 10:03:44 -0600550 events_dir = os.path.join(args.inputdir, "events.d")
Brad Bishopa6fcd562017-02-03 11:00:27 -0500551
552 if os.path.exists(events_dir):
Patrick Williams5de46b32022-12-05 10:03:44 -0600553 yaml_files = [
554 x for x in os.listdir(events_dir) if x.endswith(".yaml")
555 ]
Brad Bishopa6fcd562017-02-03 11:00:27 -0500556
557 for x in yaml_files:
Patrick Williams5de46b32022-12-05 10:03:44 -0600558 with open(os.path.join(events_dir, x), "r") as fd:
559 for e in yaml.safe_load(fd.read()).get("events", {}):
Brad Bishopa6fcd562017-02-03 11:00:27 -0500560 events.append(e)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500561
Deepak Kodihallief550b12017-08-03 14:00:17 -0500562 interfaces, interface_composite = Everything.get_interfaces(
Patrick Williams5de46b32022-12-05 10:03:44 -0600563 args.ifacesdir
564 )
565 (
566 extra_interfaces,
567 extra_interface_composite,
568 ) = Everything.get_interfaces(
569 os.path.join(args.inputdir, "extra_interfaces.d")
570 )
Deepak Kodihallief550b12017-08-03 14:00:17 -0500571 interface_composite.update(extra_interface_composite)
572 interface_composite = InterfaceComposite(interface_composite)
Matthew Barth979eb592018-10-05 15:29:26 -0500573 # Update busname if configured differenly than the default
Patrick Williams5de46b32022-12-05 10:03:44 -0600574 global busname
Matthew Barth979eb592018-10-05 15:29:26 -0500575 busname = args.busname
Brad Bishop834989f2017-02-06 12:08:20 -0500576
Brad Bishop22cfbe62016-11-30 13:25:10 -0500577 return Everything(
578 *events,
Deepak Kodihallief550b12017-08-03 14:00:17 -0500579 interfaces=interfaces + extra_interfaces,
Patrick Williams5de46b32022-12-05 10:03:44 -0600580 interface_composite=interface_composite
581 )
Brad Bishop22cfbe62016-11-30 13:25:10 -0500582
583 @staticmethod
Brad Bishop834989f2017-02-06 12:08:20 -0500584 def get_interfaces(targetdir):
Patrick Williams5de46b32022-12-05 10:03:44 -0600585 """Scan the interfaces directory for interfaces that PIM can create."""
Brad Bishop22cfbe62016-11-30 13:25:10 -0500586
Brad Bishop834989f2017-02-06 12:08:20 -0500587 yaml_files = []
Brad Bishop22cfbe62016-11-30 13:25:10 -0500588 interfaces = []
Deepak Kodihallief550b12017-08-03 14:00:17 -0500589 interface_composite = {}
Brad Bishopa6fcd562017-02-03 11:00:27 -0500590
Brad Bishop834989f2017-02-06 12:08:20 -0500591 if targetdir and os.path.exists(targetdir):
592 for directory, _, files in os.walk(targetdir):
593 if not files:
594 continue
595
Patrick Williams5de46b32022-12-05 10:03:44 -0600596 yaml_files += [
597 os.path.relpath(os.path.join(directory, f), targetdir)
598 for f in [
599 f for f in files if f.endswith(".interface.yaml")
600 ]
601 ]
Brad Bishop834989f2017-02-06 12:08:20 -0500602
603 for y in yaml_files:
Marri Devender Rao06e3d502017-06-09 11:33:38 -0500604 # parse only phosphor dbus related interface files
Sunny Srivastava3ce59302022-05-12 20:21:45 +0530605 if not (
606 y.startswith("xyz")
607 or y.startswith("com/ibm/ipzvpd")
608 or y.startswith("com/ibm/Control/Host")
609 ):
Marri Devender Rao06e3d502017-06-09 11:33:38 -0500610 continue
Brad Bishop834989f2017-02-06 12:08:20 -0500611 with open(os.path.join(targetdir, y)) as fd:
Patrick Williams5de46b32022-12-05 10:03:44 -0600612 i = y.replace(".interface.yaml", "").replace(os.sep, ".")
Brad Bishop834989f2017-02-06 12:08:20 -0500613
614 # PIM can't create interfaces with methods.
Brad Bishop834989f2017-02-06 12:08:20 -0500615 parsed = yaml.safe_load(fd.read())
Patrick Williams5de46b32022-12-05 10:03:44 -0600616 if parsed.get("methods", None):
Brad Bishop834989f2017-02-06 12:08:20 -0500617 continue
Deepak Kodihalli0b6ca102017-08-09 04:39:43 -0500618 # Cereal can't understand the type sdbusplus::object_path. This
Patrick Williams5de46b32022-12-05 10:03:44 -0600619 # type is a wrapper around std::string. Ignore interfaces
620 # having a property of this type for now. The only interface
621 # that has a property of this type now is
622 # xyz.openbmc_project.Association, which is an unused
623 # interface. No inventory objects implement this interface.
Deepak Kodihalli0b6ca102017-08-09 04:39:43 -0500624 # TODO via openbmc/openbmc#2123 : figure out how to make Cereal
625 # understand sdbusplus::object_path.
Patrick Williams5de46b32022-12-05 10:03:44 -0600626 properties = parsed.get("properties", None)
Marri Devender Raofa23d702017-09-02 04:43:42 -0500627 if properties:
Patrick Williams5de46b32022-12-05 10:03:44 -0600628 if any("path" in p["type"] for p in properties):
Marri Devender Raofa23d702017-09-02 04:43:42 -0500629 continue
Deepak Kodihallief550b12017-08-03 14:00:17 -0500630 interface_composite[i] = properties
Brad Bishop834989f2017-02-06 12:08:20 -0500631 interfaces.append(i)
Brad Bishop22cfbe62016-11-30 13:25:10 -0500632
Deepak Kodihallief550b12017-08-03 14:00:17 -0500633 return interfaces, interface_composite
Brad Bishop22cfbe62016-11-30 13:25:10 -0500634
635 def __init__(self, *a, **kw):
Patrick Williams5de46b32022-12-05 10:03:44 -0600636 self.interfaces = [Interface(x) for x in kw.pop("interfaces", [])]
637 self.interface_composite = kw.pop("interface_composite", {})
638 self.events = [self.class_map[x["type"]](**x) for x in a]
Brad Bishop22cfbe62016-11-30 13:25:10 -0500639 super(Everything, self).__init__(**kw)
640
Brad Bishop22cfbe62016-11-30 13:25:10 -0500641 def generate_cpp(self, loader):
Patrick Williams5de46b32022-12-05 10:03:44 -0600642 """Render the template with the provided events and interfaces."""
643 with open(os.path.join(args.outputdir, "generated.cpp"), "w") as fd:
Brad Bishop22cfbe62016-11-30 13:25:10 -0500644 fd.write(
645 self.render(
646 loader,
Patrick Williams5de46b32022-12-05 10:03:44 -0600647 "generated.mako.cpp",
Brad Bishop22cfbe62016-11-30 13:25:10 -0500648 events=self.events,
Brad Bishop9b5a12f2017-01-21 14:42:11 -0500649 interfaces=self.interfaces,
Patrick Williams5de46b32022-12-05 10:03:44 -0600650 indent=Indent(),
651 )
652 )
Brad Bishopbf066a62016-10-19 08:09:44 -0400653
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500654 def generate_serialization(self, loader):
Patrick Williams5de46b32022-12-05 10:03:44 -0600655 with open(
656 os.path.join(args.outputdir, "gen_serialization.hpp"), "w"
657 ) as fd:
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500658 fd.write(
659 self.render(
660 loader,
Patrick Williams5de46b32022-12-05 10:03:44 -0600661 "gen_serialization.mako.hpp",
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500662 interfaces=self.interfaces,
Patrick Williams5de46b32022-12-05 10:03:44 -0600663 interface_composite=self.interface_composite,
664 )
665 )
Deepak Kodihallif7b03992017-08-04 11:25:41 -0500666
Brad Bishop95dd98f2016-11-12 12:39:15 -0500667
Patrick Williams5de46b32022-12-05 10:03:44 -0600668if __name__ == "__main__":
Brad Bishop95dd98f2016-11-12 12:39:15 -0500669 script_dir = os.path.dirname(os.path.realpath(__file__))
Brad Bishop14a9fe52016-11-12 12:51:26 -0500670 valid_commands = {
Patrick Williams5de46b32022-12-05 10:03:44 -0600671 "generate-cpp": "generate_cpp",
672 "generate-serialization": "generate_serialization",
Brad Bishop22cfbe62016-11-30 13:25:10 -0500673 }
Brad Bishop95dd98f2016-11-12 12:39:15 -0500674
675 parser = argparse.ArgumentParser(
Patrick Williams5de46b32022-12-05 10:03:44 -0600676 description=(
677 "Phosphor Inventory Manager (PIM) YAML scanner and code generator."
678 )
679 )
Brad Bishop95dd98f2016-11-12 12:39:15 -0500680 parser.add_argument(
Patrick Williams5de46b32022-12-05 10:03:44 -0600681 "-o",
682 "--output-dir",
683 dest="outputdir",
684 default=".",
685 help="Output directory.",
686 )
Brad Bishop95dd98f2016-11-12 12:39:15 -0500687 parser.add_argument(
Patrick Williams5de46b32022-12-05 10:03:44 -0600688 "-i",
689 "--interfaces-dir",
690 dest="ifacesdir",
691 help="Location of interfaces to be supported.",
692 )
Brad Bishop834989f2017-02-06 12:08:20 -0500693 parser.add_argument(
Patrick Williams5de46b32022-12-05 10:03:44 -0600694 "-d",
695 "--dir",
696 dest="inputdir",
697 default=os.path.join(script_dir, "example"),
698 help="Location of files to process.",
699 )
Brad Bishopf4666f52016-11-12 12:44:42 -0500700 parser.add_argument(
Patrick Williams5de46b32022-12-05 10:03:44 -0600701 "-b",
702 "--bus-name",
703 dest="busname",
704 default="xyz.openbmc_project.Inventory.Manager",
705 help="Inventory manager busname.",
706 )
Matthew Barth979eb592018-10-05 15:29:26 -0500707 parser.add_argument(
Patrick Williams5de46b32022-12-05 10:03:44 -0600708 "command",
709 metavar="COMMAND",
710 type=str,
Patrick Williams55878982020-04-03 15:24:57 -0500711 choices=list(valid_commands.keys()),
Patrick Williams5de46b32022-12-05 10:03:44 -0600712 help="%s." % " | ".join(list(valid_commands.keys())),
713 )
Brad Bishop95dd98f2016-11-12 12:39:15 -0500714
715 args = parser.parse_args()
Brad Bishop22cfbe62016-11-30 13:25:10 -0500716
717 if sys.version_info < (3, 0):
718 lookup = mako.lookup.TemplateLookup(
Patrick Williams5de46b32022-12-05 10:03:44 -0600719 directories=[script_dir], disable_unicode=True
720 )
Brad Bishop22cfbe62016-11-30 13:25:10 -0500721 else:
Patrick Williams5de46b32022-12-05 10:03:44 -0600722 lookup = mako.lookup.TemplateLookup(directories=[script_dir])
Brad Bishop22cfbe62016-11-30 13:25:10 -0500723
Patrick Williams5de46b32022-12-05 10:03:44 -0600724 function = getattr(Everything.load(args), valid_commands[args.command])
Brad Bishop22cfbe62016-11-30 13:25:10 -0500725 function(lookup)