blob: 30a93fb2b8676bd5dae3a4671029056df0d8b16b [file] [log] [blame]
Brad Bishop732c6db2015-10-19 14:49:21 -04001#!/usr/bin/env python
2
3# Contributors Listed Below - COPYRIGHT 2015
4# [+] International Business Machines Corp.
5#
6#
7# Licensed under the Apache License, Version 2.0 (the "License");
8# you may not use this file except in compliance with the License.
9# You may obtain a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS,
15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16# implied. See the License for the specific language governing
17# permissions and limitations under the License.
18
Brad Bishop3f43cdb2015-10-28 22:02:09 -040019from xml.etree import ElementTree
20import dbus
21
Brad Bishop732c6db2015-10-19 14:49:21 -040022MAPPER_NAME = 'org.openbmc.objectmapper'
23MAPPER_IFACE = MAPPER_NAME + '.ObjectMapper'
24MAPPER_PATH = '/org/openbmc/objectmapper/objectmapper'
25
26class Path:
27 def __init__(self, path):
28 self.parts = filter(bool, path.split('/'))
29
30 def rel(self, first = None, last = None):
31 # relative
32 return self.get('', first, last)
33
34 def fq(self, first = None, last = None):
35 # fully qualified
36 return self.get('/', first, last)
37
38 def depth(self):
39 return len(self.parts)
40
41 def get(self, prefix = '/', first = None, last = None):
42 if not first:
43 first = 0
44 if not last:
45 last = self.depth()
46 return prefix + '/'.join(self.parts[first:last])
Brad Bishop3f43cdb2015-10-28 22:02:09 -040047
48class IntrospectionNodeParser:
49 def __init__(self, data):
50 self.data = data
51 self.cache = {}
52
53 def parse_args(self):
54 return [ x.attrib for x in self.data.findall('arg') ]
55
56 def parse_children(self):
57 return [ x.attrib['name'] for x in self.data.findall('node') ]
58
59 def parse_method_or_signal(self):
60 name = self.data.attrib['name']
61 return name, self.parse_args()
62
63 def parse_interface(self):
64 iface = {}
65 iface['method'] = {}
66 iface['signal'] = {}
67 name = self.data.attrib['name']
68
69 for node in self.data:
70 p = IntrospectionNodeParser(node)
71 if node.tag not in ['method', 'signal']:
72 continue
73 n, element = p.parse_method_or_signal()
74 iface[node.tag][n] = element
75
76 return name, iface
77
78 def parse_node(self):
79 if self.cache:
80 return self.cache
81
82 self.cache['interfaces'] = {}
83 self.cache['children'] = []
84
85 for node in self.data:
86 p = IntrospectionNodeParser(node)
87 if node.tag == 'interface':
88 name, ifaces = p.parse_interface()
89 self.cache['interfaces'][name] = ifaces
90 elif node.tag == 'node':
91 self.cache['children'] = self.parse_children()
92
93 return self.cache
94
95 def get_interfaces(self):
96 return self.parse_node()['interfaces']
97
98 def get_children(self):
99 return self.parse_node()['children']
100
101 def recursive_binding(self):
102 return any('/' in s for s in self.get_children())
103
104class IntrospectionParser:
105 def __init__(self, name, bus):
106 self.name = name
107 self.bus = bus
108
109 def _introspect(self, path):
110 try:
111 obj = self.bus.get_object(self.name, path)
112 iface = dbus.Interface(obj, dbus.BUS_DAEMON_IFACE + '.Introspectable')
113 data = iface.Introspect()
114 except dbus.DBusException:
115 return None
116
117 return IntrospectionNodeParser(ElementTree.fromstring(data))
118
119 def _discover_flat(self, path, parser):
120 items = {}
121 interfaces = parser.get_interfaces().keys()
122 if interfaces:
123 items[path] = {}
124 items[path]['interfaces'] = interfaces
125
126 return items
127
128 def introspect(self, path = '/', parser = None):
129 items = {}
130 if not parser:
131 parser = self._introspect(path)
132 if not parser:
133 return {}
134 items.update(self._discover_flat(path, parser))
135
136 if path != '/':
137 path += '/'
138
139 if parser.recursive_binding():
140 callback = self._discover_flat
141 else:
142 callback = self.introspect
143
144 for k in parser.get_children():
145 parser = self._introspect(path + k)
146 if not parser:
147 continue
148 items.update(callback(path + k, parser))
149
150 return items