Brad Bishop | 732c6db | 2015-10-19 14:49:21 -0400 | [diff] [blame] | 1 | #!/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 Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 19 | from xml.etree import ElementTree |
| 20 | import dbus |
| 21 | |
Brad Bishop | 732c6db | 2015-10-19 14:49:21 -0400 | [diff] [blame] | 22 | MAPPER_NAME = 'org.openbmc.objectmapper' |
| 23 | MAPPER_IFACE = MAPPER_NAME + '.ObjectMapper' |
| 24 | MAPPER_PATH = '/org/openbmc/objectmapper/objectmapper' |
| 25 | |
| 26 | class 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 Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 47 | |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 48 | def org_dot_openbmc_match(name): |
| 49 | return 'org.openbmc' in name |
| 50 | |
| 51 | class TagListMatch(object): |
| 52 | def __init__(self, tag_list): |
| 53 | self.tag_list = tag_list |
| 54 | |
| 55 | def __call__(self, tag): |
| 56 | return tag in self.tag_list |
| 57 | |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 58 | class IntrospectionNodeParser: |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 59 | def __init__(self, data, tag_match = bool, intf_match = bool): |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 60 | self.data = data |
| 61 | self.cache = {} |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 62 | self.tag_match = tag_match |
| 63 | self.intf_match = intf_match |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 64 | |
| 65 | def parse_args(self): |
| 66 | return [ x.attrib for x in self.data.findall('arg') ] |
| 67 | |
| 68 | def parse_children(self): |
| 69 | return [ x.attrib['name'] for x in self.data.findall('node') ] |
| 70 | |
| 71 | def parse_method_or_signal(self): |
| 72 | name = self.data.attrib['name'] |
| 73 | return name, self.parse_args() |
| 74 | |
| 75 | def parse_interface(self): |
| 76 | iface = {} |
| 77 | iface['method'] = {} |
| 78 | iface['signal'] = {} |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 79 | |
| 80 | for node in self.data: |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 81 | if node.tag not in ['method', 'signal']: |
| 82 | continue |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 83 | if not self.tag_match(node.tag): |
| 84 | continue |
| 85 | p = IntrospectionNodeParser( |
| 86 | node, self.tag_match, self.intf_match) |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 87 | n, element = p.parse_method_or_signal() |
| 88 | iface[node.tag][n] = element |
| 89 | |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 90 | return iface |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 91 | |
| 92 | def parse_node(self): |
| 93 | if self.cache: |
| 94 | return self.cache |
| 95 | |
| 96 | self.cache['interfaces'] = {} |
| 97 | self.cache['children'] = [] |
| 98 | |
| 99 | for node in self.data: |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 100 | if node.tag == 'interface': |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 101 | p = IntrospectionNodeParser( |
| 102 | node, self.tag_match, self.intf_match) |
| 103 | name = p.data.attrib['name'] |
| 104 | if not self.intf_match(name): |
| 105 | continue |
| 106 | self.cache['interfaces'][name] = p.parse_interface() |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 107 | elif node.tag == 'node': |
| 108 | self.cache['children'] = self.parse_children() |
| 109 | |
| 110 | return self.cache |
| 111 | |
| 112 | def get_interfaces(self): |
| 113 | return self.parse_node()['interfaces'] |
| 114 | |
| 115 | def get_children(self): |
| 116 | return self.parse_node()['children'] |
| 117 | |
| 118 | def recursive_binding(self): |
| 119 | return any('/' in s for s in self.get_children()) |
| 120 | |
| 121 | class IntrospectionParser: |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 122 | def __init__(self, name, bus, tag_match = bool, intf_match = bool): |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 123 | self.name = name |
| 124 | self.bus = bus |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 125 | self.tag_match = tag_match |
| 126 | self.intf_match = intf_match |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 127 | |
| 128 | def _introspect(self, path): |
| 129 | try: |
| 130 | obj = self.bus.get_object(self.name, path) |
| 131 | iface = dbus.Interface(obj, dbus.BUS_DAEMON_IFACE + '.Introspectable') |
| 132 | data = iface.Introspect() |
| 133 | except dbus.DBusException: |
| 134 | return None |
| 135 | |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 136 | return IntrospectionNodeParser( |
| 137 | ElementTree.fromstring(data), |
| 138 | self.tag_match, |
| 139 | self.intf_match) |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 140 | |
| 141 | def _discover_flat(self, path, parser): |
| 142 | items = {} |
| 143 | interfaces = parser.get_interfaces().keys() |
| 144 | if interfaces: |
| 145 | items[path] = {} |
| 146 | items[path]['interfaces'] = interfaces |
| 147 | |
| 148 | return items |
| 149 | |
| 150 | def introspect(self, path = '/', parser = None): |
| 151 | items = {} |
| 152 | if not parser: |
| 153 | parser = self._introspect(path) |
| 154 | if not parser: |
| 155 | return {} |
| 156 | items.update(self._discover_flat(path, parser)) |
| 157 | |
| 158 | if path != '/': |
| 159 | path += '/' |
| 160 | |
| 161 | if parser.recursive_binding(): |
| 162 | callback = self._discover_flat |
| 163 | else: |
| 164 | callback = self.introspect |
| 165 | |
| 166 | for k in parser.get_children(): |
| 167 | parser = self._introspect(path + k) |
| 168 | if not parser: |
| 169 | continue |
| 170 | items.update(callback(path + k, parser)) |
| 171 | |
Brad Bishop | 6fb8461 | 2015-11-01 00:06:24 -0400 | [diff] [blame^] | 172 | if path == '/': |
| 173 | print items |
| 174 | |
Brad Bishop | 3f43cdb | 2015-10-28 22:02:09 -0400 | [diff] [blame] | 175 | return items |