From 2cea517823b505f1f6577fd8a31f123f1772a173 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Sun, 14 Jul 2013 15:06:40 -0400 Subject: [PATCH] xmlbuilder: Allow classes to specify order of certain xml elements This will save us some test case churn. As an example, we now do auto building of disk XML and it doesn't alter things. Without this bus and target are often swapped. --- tests/cli-test-xml/compare/many-devices.xml | 8 +-- tests/utils.py | 1 + virtinst/VirtualDisk.py | 8 +-- virtinst/xmlbuilder.py | 60 +++++++++++++++++++-- 4 files changed, 65 insertions(+), 12 deletions(-) diff --git a/tests/cli-test-xml/compare/many-devices.xml b/tests/cli-test-xml/compare/many-devices.xml index dc2cdb821..50df586da 100644 --- a/tests/cli-test-xml/compare/many-devices.xml +++ b/tests/cli-test-xml/compare/many-devices.xml @@ -23,17 +23,17 @@ /usr/bin/test-hv + WD-WMAP9A966149 - + - @@ -110,17 +110,17 @@ /usr/bin/test-hv + WD-WMAP9A966149 - + - diff --git a/tests/utils.py b/tests/utils.py index 4357e8fe0..70722380d 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -157,6 +157,7 @@ def read_file(filename): def diff_compare(actual_out, filename=None, expect_out=None): """Compare passed string output to contents of filename""" if not expect_out: + #file(filename, "w").write(actual_out) expect_out = read_file(filename) diff = "".join(difflib.unified_diff(expect_out.splitlines(1), diff --git a/virtinst/VirtualDisk.py b/virtinst/VirtualDisk.py index 80445e905..e468211b9 100644 --- a/virtinst/VirtualDisk.py +++ b/virtinst/VirtualDisk.py @@ -388,10 +388,14 @@ class VirtualDisk(VirtualDevice): except Exception, e: raise ValueError(_("Couldn't lookup volume object: %s" % str(e))) - _DEFAULT_SENTINEL = -1234 + + _XMLELEMENTORDER = ["driver", "source", "target"] + _XMLPROPORDER = ["target", "bus"] + def __init__(self, conn, parsexml=None, parsexmlnode=None): VirtualDevice.__init__(self, conn, parsexml, parsexmlnode) + self._DEFAULT_SENTINEL = -1234 self._device = self.DEVICE_DISK self._type = self._DEFAULT_SENTINEL self._driverName = self._DEFAULT_SENTINEL @@ -756,8 +760,6 @@ class VirtualDisk(VirtualDevice): if path is not None: ret += " \n" % (typeattr, path) - ret += " \n" % (self.target) - addr = self.indent(self.address.get_xml_config(), 6) if addr: ret += addr diff --git a/virtinst/xmlbuilder.py b/virtinst/xmlbuilder.py index 8b3964c62..f53f30395 100644 --- a/virtinst/xmlbuilder.py +++ b/virtinst/xmlbuilder.py @@ -521,6 +521,12 @@ class XMLBuilder(object): xml += " " * level + l + "\n" return xml + # Specify a list of tag values here and we will arrange them when + # outputing XML. They will be put before every other element. This + # is strictly to keep test suite happy. + _XMLELEMENTORDER = [] + _XMLPROPORDER = [] + _dumpxml_xpath = "." def __init__(self, conn, parsexml=None, parsexmlnode=None): """ @@ -596,10 +602,20 @@ class XMLBuilder(object): if not self._propstore or self._is_parse(): return xml + do_order = [] + proporder = self._proporder[:] + propstore = self._propstore.copy() + + for key in self._XMLPROPORDER: + if key in proporder: + proporder.remove(key) + do_order.append(key) + proporder = do_order + proporder + try: self._parsexml(xml, None) - for key in self._proporder[:]: - setattr(self, key, self._propstore[key]) + for key in proporder: + setattr(self, key, propstore[key]) ret = self.get_xml_config() for c in xml: if c != " ": @@ -627,6 +643,37 @@ class XMLBuilder(object): """ raise NotImplementedError() + def _order_xml_elements(self, xml): + # This whole thing is reeeally hacky but it saves us some + # unittest churn. + if not self._XMLELEMENTORDER: + return xml + + split = xml.splitlines() + if len(split) < 3: + return xml + + head = split[0] + end = split[-1] + split = split[1:-1] + + baseindent = 0 + for i in head: + if i != " ": + break + baseindent += 1 + + neworder = [] + for prio in reversed(self._XMLELEMENTORDER): + tag = "%s<%s " % ((baseindent + 2) * " ", prio) + for idx in range(len(split)): + if split[idx].startswith(tag): + neworder.insert(0, split.pop(idx)) + break + neworder += split + + return "\n".join([head] + neworder + [end]) + def get_xml_config(self, *args, **kwargs): """ Construct and return object xml @@ -637,7 +684,10 @@ class XMLBuilder(object): if self._xml_ctx: node = _get_xpath_node(self._xml_ctx, self._dumpxml_xpath) if not node: - return "" - return _sanitize_libxml_xml(node.serialize()) + ret = "" + else: + ret = _sanitize_libxml_xml(node.serialize()) + else: + ret = self._get_xml_config(*args, **kwargs) - return self._get_xml_config(*args, **kwargs) + return self._order_xml_elements(ret)