Use qom-tree-get to speed up the qom-tree command. Signed-off-by: Steve Sistare <steven.sist...@oracle.com> --- python/qemu/utils/qom.py | 36 +++++++++++++++---------------- python/qemu/utils/qom_common.py | 48 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 18 deletions(-)
diff --git a/python/qemu/utils/qom.py b/python/qemu/utils/qom.py index 426a0f2..33d0a60 100644 --- a/python/qemu/utils/qom.py +++ b/python/qemu/utils/qom.py @@ -35,6 +35,7 @@ from qemu.qmp import ExecuteError from .qom_common import QOMCommand +from .qom_common import ObjectNode try: @@ -224,28 +225,27 @@ def __init__(self, args: argparse.Namespace): super().__init__(args) self.path = args.path - def _list_node(self, path: str) -> None: + def _list_tree(self, node: ObjectNode, path: str) -> None: print(path) - items = self.qom_list(path) - for item in items: - if item.child: - continue - try: - rsp = self.qmp.cmd('qom-get', path=path, - property=item.name) - print(f" {item.name}: {rsp} ({item.type})") - except ExecuteError as err: - print(f" {item.name}: <EXCEPTION: {err!s}> ({item.type})") + + for item in node.properties: + value = item.value + if value == None: + value = f"<EXCEPTION: property could not be read>" + print(f" {item.name}: {value} ({item.type})") + print('') - for item in items: - if not item.child: - continue - if path == '/': - path = '' - self._list_node(f"{path}/{item.name}") + if path == '/': + path = '' + + for child in node.children: + self._list_tree(child, f"{path}/{child.name}") + def run(self) -> int: - self._list_node(self.path) + root = self.qom_tree_get(self.path) + self._list_tree(root, self.path) + return 0 diff --git a/python/qemu/utils/qom_common.py b/python/qemu/utils/qom_common.py index dd2c8b1..8c242cc 100644 --- a/python/qemu/utils/qom_common.py +++ b/python/qemu/utils/qom_common.py @@ -65,6 +65,47 @@ def link(self) -> bool: return self.type.startswith('link<') +class ObjectPropertyValue: + """ + Represents a property return from e.g. qom-tree-get + """ + def __init__(self, name: str, type_: str, value: object): + self.name = name + self.type = type_ + self.value = value + + @classmethod + def make(cls, value: Dict[str, Any]) -> 'ObjectPropertyValue': + """ + Build an ObjectPropertyValue from a Dict with an unknown shape. + """ + assert value.keys() >= {'name', 'type'} + assert value.keys() <= {'name', 'type', 'value'} + return cls(value['name'], value['type'], value.get('value')) + + +class ObjectNode: + """ + Represents the return type from e.g. qom-tree-get + """ + def __init__(self, name: str, children: List['ObjectNode'], + properties: List[ObjectPropertyValue]): + self.name = name + self.children = children + self.properties = properties + + @classmethod + def make(cls, value: Dict[str, Any]) -> 'ObjectNode': + """ + Build an ObjectNode from a Dict with an unknown shape. + """ + assert value.keys() == {'name', 'children', 'properties'} + + props = [ObjectPropertyValue.make(x) for x in value['properties']] + children = [ObjectNode.make(x) for x in value['children']] + return cls(value['name'], children, props) + + CommandT = TypeVar('CommandT', bound='QOMCommand') @@ -145,6 +186,13 @@ def qom_list(self, path: str) -> List[ObjectPropertyInfo]: assert isinstance(rsp, list) return [ObjectPropertyInfo.make(x) for x in rsp] + def qom_tree_get(self, path: str) -> ObjectNode: + """ + :return: a strongly typed root node from the 'qom-tree-get' command. + """ + rsp = self.qmp.cmd('qom-tree-get', path=path) + return ObjectNode.make(rsp) + @classmethod def command_runner( cls: Type[CommandT], -- 1.8.3.1