From bba3c93508ba1c16fab8dcd042c715e261bad31b Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Wed, 24 Jul 2013 14:37:07 -0400 Subject: [PATCH] xmlbuilder: Always keep around an xml node, even if building from scratch This further unifies the 'parse existing' vs. 'build new' case. --- tests/cli-test-xml/compare/clone-auto1.xml | 6 +- tests/cli-test-xml/compare/clone-auto2.xml | 2 +- tests/clone-xml/cross-pool-out.xml | 4 +- tests/clone-xml/empty-disks-out.xml | 2 +- tests/clone-xml/force-out.xml | 4 +- tests/clone-xml/managed-storage-out.xml | 4 +- tests/clone-xml/readonly-disks-out.xml | 2 +- tests/clone-xml/skip-out.xml | 2 +- tests/nodedev-xml/devxml/pcidev.xml | 11 +- tests/nodedev-xml/devxml/usbdev1.xml | 13 +- tests/nodedev-xml/devxml/usbdev2.xml | 15 +- tests/xmlconfig-xml/boot-cpuset.xml | 2 +- tests/xmlconfig-xml/rhel6-kvm-stage1.xml | 4 +- tests/xmlconfig.py | 31 +-- tests/xmlparse-xml/add-devices-out.xml | 2 +- tests/xmlparse-xml/change-boot-multi-out.xml | 2 +- tests/xmlparse-xml/change-chars-out.xml | 2 +- tests/xmlparse-xml/change-disk-out.xml | 4 +- tests/xmlparse-xml/change-guest-out.xml | 5 +- .../xmlparse-xml/change-minimal-guest-out.xml | 4 +- tests/xmlparse-xml/change-nics-out.xml | 4 +- tests/xmlparse.py | 2 +- virtinst/CPU.py | 2 +- virtinst/Guest.py | 27 +- virtinst/VirtualCharDevice.py | 2 +- virtinst/VirtualDisk.py | 7 +- virtinst/xmlbuilder.py | 245 +++++++++--------- 27 files changed, 206 insertions(+), 204 deletions(-) diff --git a/tests/cli-test-xml/compare/clone-auto1.xml b/tests/cli-test-xml/compare/clone-auto1.xml index 8de43fce..1af5374c 100644 --- a/tests/cli-test-xml/compare/clone-auto1.xml +++ b/tests/cli-test-xml/compare/clone-auto1.xml @@ -20,10 +20,10 @@ /usr/lib/xen/bin/qemu-dm +
- @@ -45,14 +45,14 @@
+
- +
- diff --git a/tests/cli-test-xml/compare/clone-auto2.xml b/tests/cli-test-xml/compare/clone-auto2.xml index e6cb868c..0fe424d1 100644 --- a/tests/cli-test-xml/compare/clone-auto2.xml +++ b/tests/cli-test-xml/compare/clone-auto2.xml @@ -20,9 +20,9 @@ /usr/lib/xen/bin/qemu-dm +
- diff --git a/tests/clone-xml/cross-pool-out.xml b/tests/clone-xml/cross-pool-out.xml index 6035a5da..4fac96b0 100644 --- a/tests/clone-xml/cross-pool-out.xml +++ b/tests/clone-xml/cross-pool-out.xml @@ -18,12 +18,12 @@ /usr/bin/qemu-kvm - + - + diff --git a/tests/clone-xml/empty-disks-out.xml b/tests/clone-xml/empty-disks-out.xml index fbf079f6..546a9304 100644 --- a/tests/clone-xml/empty-disks-out.xml +++ b/tests/clone-xml/empty-disks-out.xml @@ -29,8 +29,8 @@ - + diff --git a/tests/clone-xml/force-out.xml b/tests/clone-xml/force-out.xml index 1a44f3de..0375f39e 100644 --- a/tests/clone-xml/force-out.xml +++ b/tests/clone-xml/force-out.xml @@ -18,8 +18,8 @@ /usr/bin/qemu-kvm - + @@ -29,8 +29,8 @@ - + diff --git a/tests/clone-xml/managed-storage-out.xml b/tests/clone-xml/managed-storage-out.xml index 46653cb2..eeb0bd45 100644 --- a/tests/clone-xml/managed-storage-out.xml +++ b/tests/clone-xml/managed-storage-out.xml @@ -18,13 +18,13 @@ /usr/bin/qemu-kvm + - - + diff --git a/tests/clone-xml/readonly-disks-out.xml b/tests/clone-xml/readonly-disks-out.xml index 19c22d31..93933feb 100644 --- a/tests/clone-xml/readonly-disks-out.xml +++ b/tests/clone-xml/readonly-disks-out.xml @@ -27,8 +27,8 @@ - + diff --git a/tests/clone-xml/skip-out.xml b/tests/clone-xml/skip-out.xml index 90319888..baa41e49 100644 --- a/tests/clone-xml/skip-out.xml +++ b/tests/clone-xml/skip-out.xml @@ -29,8 +29,8 @@ - + diff --git a/tests/nodedev-xml/devxml/pcidev.xml b/tests/nodedev-xml/devxml/pcidev.xml index 2f3dd5da..dca82993 100644 --- a/tests/nodedev-xml/devxml/pcidev.xml +++ b/tests/nodedev-xml/devxml/pcidev.xml @@ -1,5 +1,6 @@ - - -
- - + + +
+ + + diff --git a/tests/nodedev-xml/devxml/usbdev1.xml b/tests/nodedev-xml/devxml/usbdev1.xml index eeb90f1f..44712453 100644 --- a/tests/nodedev-xml/devxml/usbdev1.xml +++ b/tests/nodedev-xml/devxml/usbdev1.xml @@ -1,6 +1,7 @@ - - - - - - + + + + + + + diff --git a/tests/nodedev-xml/devxml/usbdev2.xml b/tests/nodedev-xml/devxml/usbdev2.xml index 522f7dae..73364b56 100644 --- a/tests/nodedev-xml/devxml/usbdev2.xml +++ b/tests/nodedev-xml/devxml/usbdev2.xml @@ -1,7 +1,8 @@ - - - - -
- - + + + + +
+ + + diff --git a/tests/xmlconfig-xml/boot-cpuset.xml b/tests/xmlconfig-xml/boot-cpuset.xml index ac4627ad..c8f35b19 100644 --- a/tests/xmlconfig-xml/boot-cpuset.xml +++ b/tests/xmlconfig-xml/boot-cpuset.xml @@ -13,7 +13,7 @@ - + footest Intel diff --git a/tests/xmlconfig-xml/rhel6-kvm-stage1.xml b/tests/xmlconfig-xml/rhel6-kvm-stage1.xml index 19c1b946..f3a49b7c 100644 --- a/tests/xmlconfig-xml/rhel6-kvm-stage1.xml +++ b/tests/xmlconfig-xml/rhel6-kvm-stage1.xml @@ -6,8 +6,8 @@ 5 hvm - kernel - initrd + ./virtinst-vmlinuz. + ./virtinst-initrd.img. method=tests/cli-test-xml/fakerhel6tree diff --git a/tests/xmlconfig.py b/tests/xmlconfig.py index 774936ea..74a62921 100644 --- a/tests/xmlconfig.py +++ b/tests/xmlconfig.py @@ -18,8 +18,6 @@ import unittest import os import logging -import urlgrabber.progress as progress - import virtinst from virtinst import VirtualDisk from virtinst import VirtualAudio @@ -67,7 +65,7 @@ class TestXMLConfig(unittest.TestCase): do_create=True): filename = filebase and build_xmlfile(filebase) or None - guest._prepare_install(progress.BaseMeter()) + guest._prepare_install(None) try: actualXML = guest.get_install_xml(install=do_install, disk_boot=do_disk_boot) @@ -93,11 +91,6 @@ class TestXMLConfig(unittest.TestCase): guest.start_install(consolecb, meter, removeOld, wait) guest.domain.destroy() - # Replace kernel/initrd with known info - if guest.installer._install_kernel: - guest.installer._install_kernel = "kernel" - guest.installer._install_initrd = "initrd" - xmlinst = guest.get_install_xml(True, False) xmlboot = guest.get_install_xml(False, False) xmlcont = guest.get_install_xml(True, True) @@ -320,10 +313,6 @@ class TestXMLConfig(unittest.TestCase): # Call get_xml_config sets first round of defaults w/o os_variant set g.get_install_xml(do_install) - g._prepare_install(None) - g.get_install_xml(do_install) - g._prepare_install(None) - g.get_install_xml(do_install) g.os_variant = "fedora11" self._compare(g, "install-f11", do_install) @@ -992,19 +981,19 @@ class TestXMLConfig(unittest.TestCase): dev3.macaddr = "22:22:33:44:55:68" utils.diff_compare(dev1.get_xml_config(), None, - " \n" - " \n" - " \n" - " ") + "\n" + " \n" + " \n" + "\n") utils.diff_compare(dev2.get_xml_config(), None, "\n" - " \n" - " \n" - " \n") + " \n" + " \n" + "\n") utils.diff_compare(dev3.get_xml_config(), None, "\n" - " \n" - " \n") + " \n" + "\n") finally: if util and origfunc: util.default_bridge = origfunc diff --git a/tests/xmlparse-xml/add-devices-out.xml b/tests/xmlparse-xml/add-devices-out.xml index 114088a5..24d48bcb 100644 --- a/tests/xmlparse-xml/add-devices-out.xml +++ b/tests/xmlparse-xml/add-devices-out.xml @@ -38,11 +38,11 @@ - + diff --git a/tests/xmlparse-xml/change-boot-multi-out.xml b/tests/xmlparse-xml/change-boot-multi-out.xml index a374cb3f..1d1a1596 100644 --- a/tests/xmlparse-xml/change-boot-multi-out.xml +++ b/tests/xmlparse-xml/change-boot-multi-out.xml @@ -7,10 +7,10 @@ hvm /usr/lib/xen/boot/hvmloader - foo.img bar.img ks=foo.ks + diff --git a/tests/xmlparse-xml/change-chars-out.xml b/tests/xmlparse-xml/change-chars-out.xml index 9f94987a..c94c3ad4 100644 --- a/tests/xmlparse-xml/change-chars-out.xml +++ b/tests/xmlparse-xml/change-chars-out.xml @@ -37,8 +37,8 @@ - + diff --git a/tests/xmlparse-xml/change-disk-out.xml b/tests/xmlparse-xml/change-disk-out.xml index 7f60efaa..6702201d 100644 --- a/tests/xmlparse-xml/change-disk-out.xml +++ b/tests/xmlparse-xml/change-disk-out.xml @@ -21,8 +21,8 @@ frob - + @@ -50,9 +50,9 @@ 5 6 + - diff --git a/tests/xmlparse-xml/change-guest-out.xml b/tests/xmlparse-xml/change-guest-out.xml index 6a211e05..eb3dd42a 100644 --- a/tests/xmlparse-xml/change-guest-out.xml +++ b/tests/xmlparse-xml/change-guest-out.xml @@ -6,12 +6,11 @@ xen /foo/loader - /sbin/init + /sbin/init - - + diff --git a/tests/xmlparse-xml/change-minimal-guest-out.xml b/tests/xmlparse-xml/change-minimal-guest-out.xml index 1821aaa9..c0bebc2b 100644 --- a/tests/xmlparse-xml/change-minimal-guest-out.xml +++ b/tests/xmlparse-xml/change-minimal-guest-out.xml @@ -19,12 +19,12 @@ - + foobar - + diff --git a/tests/xmlparse-xml/change-nics-out.xml b/tests/xmlparse-xml/change-nics-out.xml index cf978c4e..8ee098e5 100644 --- a/tests/xmlparse-xml/change-nics-out.xml +++ b/tests/xmlparse-xml/change-nics-out.xml @@ -20,13 +20,13 @@ /usr/lib/xen/bin/qemu-dm - + + - diff --git a/tests/xmlparse.py b/tests/xmlparse.py index bbca0950..ef7e7e88 100644 --- a/tests/xmlparse.py +++ b/tests/xmlparse.py @@ -744,8 +744,8 @@ class XMLParseTest(unittest.TestCase): adddev.macaddr = "1A:2A:3A:4A:5A:6A" guest.add_device(virtinst.VirtualWatchdog(conn)) - guest.add_device(adddev) + guest.add_device(adddev) guest.remove_device(adddev) guest.add_device(adddev) diff --git a/virtinst/CPU.py b/virtinst/CPU.py index 0c9456a4..af3744e4 100644 --- a/virtinst/CPU.py +++ b/virtinst/CPU.py @@ -70,7 +70,7 @@ class CPU(XMLBuilder): def _parsexml(self, xml, node): XMLBuilder._parsexml(self, xml, node) - for node in self._xml_node.children: + for node in self._xml_node.children or []: if node.name != "feature": continue if not node.prop("name"): diff --git a/virtinst/Guest.py b/virtinst/Guest.py index 5026f258..fa31f639 100644 --- a/virtinst/Guest.py +++ b/virtinst/Guest.py @@ -337,12 +337,9 @@ class Guest(XMLBuilder): @param dev: VirtualDevice instance to attach to guest @param set_defaults: Whether to set defaults for the device """ - if self._is_parse(): - self._add_child("./devices", dev) - self._track_device(dev) - if self._is_parse(): - self._recalculate_device_xpaths() + self._add_child("./devices", dev) + self._recalculate_device_xpaths() if set_defaults: origdev = self._devices @@ -365,7 +362,6 @@ class Guest(XMLBuilder): VirtualDevice.virtual_device_types) """ devlist = self._dev_build_list(devtype) - devlist.extend(self._install_devices) return self._dev_build_list(devtype, devlist) def get_all_devices(self): @@ -384,7 +380,7 @@ class Guest(XMLBuilder): @param dev: VirtualDevice instance """ found = False - for devlist in [self._devices, self._install_devices]: + for devlist in [self._devices]: if found: break @@ -396,11 +392,13 @@ class Guest(XMLBuilder): if not found: raise ValueError(_("Did not find device %s") % str(dev)) - if self._is_parse(): - xpath = dev.get_root_xpath() - if xpath: - self._remove_child_xpath(xpath) - self._recalculate_device_xpaths() + xpath = dev.get_root_xpath() + xml = dev.get_xml_config() + dev.set_root_xpath(None) + dev._parsexml(xml, None) + if xpath: + self._remove_child_xpath(xpath) + self._recalculate_device_xpaths() ################################ @@ -410,7 +408,7 @@ class Guest(XMLBuilder): def _parsexml(self, xml, node): XMLBuilder._parsexml(self, xml, node) - for node in self._xml_node.children: + for node in self._xml_node.children or []: if node.name != "devices": continue @@ -455,6 +453,8 @@ class Guest(XMLBuilder): ############################ def _prepare_install(self, meter, dry=False): + for dev in self._install_devices: + self.remove_device(dev) self._install_devices = [] ignore = dry @@ -464,6 +464,7 @@ class Guest(XMLBuilder): # Initialize install device list for dev in self.installer.install_devices: + self.add_device(dev) self._install_devices.append(dev) def _cleanup_install(self): diff --git a/virtinst/VirtualCharDevice.py b/virtinst/VirtualCharDevice.py index fdcc24fa..3895b35a 100644 --- a/virtinst/VirtualCharDevice.py +++ b/virtinst/VirtualCharDevice.py @@ -139,7 +139,7 @@ class _VirtualCharDevice(VirtualDevice): return hasattr(self, propname) - _XML_PROP_ORDER = ["type", + _XML_PROP_ORDER = ["type", "_has_mode_bind", "_has_mode_connect", "bind_host", "bind_port", "source_mode", "source_path", "source_host", "source_port", diff --git a/virtinst/VirtualDisk.py b/virtinst/VirtualDisk.py index fc6b7235..3118b6af 100644 --- a/virtinst/VirtualDisk.py +++ b/virtinst/VirtualDisk.py @@ -607,9 +607,12 @@ class VirtualDisk(VirtualDevice): # # This will update the XML value with the newly determined # default value, but it won't edit propstore. This means + if self.is_build(): + return prop = self.all_xml_props()[propname] - val = getattr(prop, "_default_cb")(self) - prop.setter(self, val, call_fset=False) + candefault, val = getattr(prop, "_default_get_value")(self) + if candefault: + getattr(prop, "_set_xml")(self, val) refresh_prop_xml("type") refresh_prop_xml("driver_name") diff --git a/virtinst/xmlbuilder.py b/virtinst/xmlbuilder.py index b4f8e338..bad71c83 100644 --- a/virtinst/xmlbuilder.py +++ b/virtinst/xmlbuilder.py @@ -351,19 +351,6 @@ class XMLProperty(property): return xmlbuilder.fix_relative_xpath(ret) - def _convert_value_for_setter(self, xmlbuilder): - # Convert from API value to XML value - val = self._nonxml_fget(xmlbuilder) - if self._default_name and val == self._default_name: - val = self._default_cb(xmlbuilder) - elif self._is_yesno: - if val is not None: - val = bool(val) and "yes" or "no" - - if self._convert_value_for_setter_cb: - val = self._convert_value_for_setter_cb(xmlbuilder, val) - return val - def _build_node_list(self, xmlbuilder, xpath): """ Build list of nodes that the passed xpaths reference @@ -408,11 +395,37 @@ class XMLProperty(property): ret = val return ret + def _convert_set_value(self, xmlbuilder, val): + if self._default_name and val == self._default_name: + val = self._default_cb(xmlbuilder) + elif self._is_yesno: + if val is not None: + val = bool(val) and "yes" or "no" + + if self._convert_value_for_setter_cb: + val = self._convert_value_for_setter_cb(xmlbuilder, val) + return val + def _prop_is_unset(self, xmlbuilder): propstore = getattr(xmlbuilder, "_propstore") propname = self._findpropname(xmlbuilder) return (propname not in propstore) + def _default_get_value(self, xmlbuilder): + """ + Return (can use default, default value) + """ + ret = (False, -1) + if not self._prop_is_unset(xmlbuilder): + return ret + if not self._default_cb: + return ret + + if self._default_name: + return (True, self._default_name) + return (True, self._default_cb(xmlbuilder)) + + def _set_default(self, xmlbuilder): """ Encode the property default into the XML and propstore, but @@ -422,13 +435,10 @@ class XMLProperty(property): This is called during the get_xml_config process and shouldn't be called from outside this file. """ - if not self._prop_is_unset(xmlbuilder): + candefault, val = self._default_get_value(xmlbuilder) + if not candefault: return - if not self._default_cb: - return - if self._default_cb(xmlbuilder) is None: - return - self.setter(xmlbuilder, self.getter(xmlbuilder), validate=False) + self.setter(xmlbuilder, val, validate=False) def _nonxml_fset(self, xmlbuilder, val): """ @@ -453,17 +463,17 @@ class XMLProperty(property): The flip side to nonxml_fset, fetch the value from XMLBuilder._propstore """ + candefault, val = self._default_get_value(xmlbuilder) + if candefault: + return val + propstore = getattr(xmlbuilder, "_propstore") propname = self._findpropname(xmlbuilder) - unset = (propname not in propstore) - if unset and self._default_cb: - if self._default_name: - return self._default_name - return self._default_cb(xmlbuilder) return propstore.get(propname, None) def _clear(self, xmlbuilder): self.setter(xmlbuilder, None) + self._set_xml(xmlbuilder, None) ################################## @@ -471,33 +481,38 @@ class XMLProperty(property): ################################## def getter(self, xmlbuilder): - if xmlbuilder._xml_ctx is None: - fgetval = self._nonxml_fget(xmlbuilder) - return self._convert_get_value(fgetval) + if self._prop_is_unset(xmlbuilder) and not xmlbuilder.is_build(): + val = self._get_xml(xmlbuilder) + else: + val = self._nonxml_fget(xmlbuilder) + ret = self._convert_get_value(val) + return ret + def _get_xml(self, xmlbuilder): xpath = self._xpath_for_getter(xmlbuilder) node = _get_xpath_node(xmlbuilder._xml_ctx, xpath) - if not node: - return self._convert_get_value(None) + return None content = node.content if self._is_bool: content = True - return self._convert_get_value(content) + return content - def setter(self, xmlbuilder, val, call_fset=True, validate=True): - if call_fset: - if validate and self._validate_cb: - self._validate_cb(xmlbuilder, val) - self._nonxml_fset(xmlbuilder, val) + def setter(self, xmlbuilder, val, validate=True): + if validate and self._validate_cb: + self._validate_cb(xmlbuilder, val) + self._nonxml_fset(xmlbuilder, + self._convert_set_value(xmlbuilder, val)) - root_node = getattr(xmlbuilder, "_xml_node") - if root_node is None: + if xmlbuilder.is_build(): return + self._convert_set_value(xmlbuilder, val) + def _set_xml(self, xmlbuilder, setval, root_node=None): + if root_node is None: + root_node = xmlbuilder._xml_node xpath = self._xpath_for_setter(xmlbuilder) - setval = self._convert_value_for_setter(xmlbuilder) node = _get_xpath_node(xmlbuilder._xml_ctx, xpath) clearlist = self._build_clear_list(xmlbuilder, node) @@ -562,8 +577,11 @@ class XMLBuilder(object): self._propstore = {} self._proporder = [] - if parsexml or parsexmlnode: - self._parsexml(parsexml, parsexmlnode) + self._is_build = False + if not (parsexml or parsexmlnode): + parsexml = self._make_xml_stub() + self._is_build = True + self._parsexml(parsexml, parsexmlnode) ############## @@ -580,7 +598,8 @@ class XMLBuilder(object): self._parsexml(xml, None) def set_root_xpath(self, xpath): - self._xml_root_xpath = xpath + self._xml_root_xpath = xpath or "" + self._xml_dump_xpath = xpath or self._XML_ROOT_XPATH xmlprops = self.all_xml_props() for propname in self._XML_PROP_ORDER: @@ -608,30 +627,12 @@ class XMLBuilder(object): for prop in self.all_xml_props().values(): prop._clear(self) - def _do_get_xml_config(self): - """ - Construct and return object xml - - @return: object xml representation as a string - @rtype: str - """ - if self._xml_ctx: - node = _get_xpath_node(self._xml_ctx, self._xml_dump_xpath) - if not node: - ret = "" - else: - ret = _sanitize_libxml_xml(node.serialize()) - else: - xmlstub = self._make_xml_stub() - if xmlstub is None: - return None - - ret = self._add_parse_bits(xmlstub) - if ret == xmlstub: - ret = "" - - if ret and self._xml_root_name == "domain" and not ret.endswith("\n"): - ret += "\n" + def all_xml_props(self): + ret = {} + for c in reversed(type.mro(self.__class__)[:-1]): + for key, val in c.__dict__.items(): + if val.__class__ is XMLProperty: + ret[key] = val return ret @@ -639,8 +640,8 @@ class XMLBuilder(object): # Internal helper API # ####################### - def _is_parse(self): - return bool(self._xml_node or self._xml_ctx) + def is_build(self): + return bool(self._is_build) ################### @@ -663,6 +664,36 @@ class XMLBuilder(object): # Internal XML parsers # ######################## + def _get_node_xml(self, ctx=None): + if ctx is None: + ctx = self._xml_ctx + + node = _get_xpath_node(ctx, self._xml_dump_xpath) + if not node: + return "" + return _sanitize_libxml_xml(node.serialize()) + + def _do_get_xml_config(self): + xmlstub = self._make_xml_stub() + + try: + node = None + ctx = None + if self.is_build(): + node = self._xml_node.docCopyNodeList(self._xml_node.doc) + ctx = self._make_xml_context(node) + ret = self._add_parse_bits(node, ctx) + finally: + if node: + node.freeNode() + + if ret == xmlstub: + ret = "" + + if ret and self._xml_root_name == "domain" and not ret.endswith("\n"): + ret += "\n" + return ret + def _make_xml_stub(self): return _indent("<%s/>" % (self._xml_root_name), self._xml_indent) @@ -671,26 +702,30 @@ class XMLBuilder(object): Insert the passed XMLBuilder object into our XML document at the specified path """ - dev.set_new_xml(dev.get_xml_config()) - newnode = dev._xml_node - ret = _build_xpath_node(self._xml_ctx, parent_xpath, newnode) - return ret + if not dev.is_build(): + newnode = libxml2.parseDoc(dev.get_xml_config()).children + _build_xpath_node(self._xml_ctx, parent_xpath, newnode) + dev._parsexml(None, self._xml_node) def _remove_child_xpath(self, xpath): _remove_xpath_node(self._xml_ctx, xpath, dofree=False) self._set_xml_context() - def _set_xml_context(self): - doc = self._xml_node.doc + def _make_xml_context(self, node): + doc = node.doc ctx = _CtxCleanupWrapper(doc.xpathNewContext()) - ctx.setContextNode(self._xml_node) - self._xml_ctx = ctx + ctx.setContextNode(node) + return ctx + + def _set_xml_context(self): + self._xml_ctx = self._make_xml_context(self._xml_node) def _parsexml(self, xml, node): if xml: doc = libxml2.parseDoc(xml) self._xml_root_doc = _DocCleanupWrapper(doc) self._xml_node = doc.children + self._xml_node.virtinst_is_build = self._is_build self._xml_dump_xpath = "." # This just stores a reference to our root doc wrapper in @@ -699,41 +734,19 @@ class XMLBuilder(object): self._xml_node.virtinst_root_doc = self._xml_root_doc else: self._xml_node = node + self._is_build = (getattr(node, "virtinst_is_build", False) or + self._is_build) self._xml_dump_xpath = self._XML_ROOT_XPATH self._set_xml_context() - def all_xml_props(self): - ret = {} - for c in reversed(type.mro(self.__class__)[:-1]): - for key, val in c.__dict__.items(): - if val.__class__ is XMLProperty: - ret[key] = val - return ret - - def _do_add_parse_bits(self, xml, node): + def _do_add_parse_bits(self, node, ctx): # Set all defaults if the properties have one registered xmlprops = self.all_xml_props() - for prop in xmlprops.values(): - prop._set_default(self) - # Default props alter our _propstore. But at this point _propstore - # is empty, there's nothing for us to do, so exit early - if not self._propstore: - return xml - - # Unindent XML - indent = 0 - if xml: - for c in xml: - if c != " ": - break - indent += 1 - xml = "\n".join([l[indent:] for l in xml.splitlines()]) - - # Parse the XML into our internal state. Use the raw - # _parsexml so we don't hit Guest parsing into its internal state - XMLBuilder._parsexml(self, xml, node) + if self.is_build(): + for prop in xmlprops.values(): + prop._set_default(self) # Set up preferred XML ordering do_order = self._proporder[:] @@ -747,32 +760,26 @@ class XMLBuilder(object): # Alter the XML for key in do_order: if key in xmlprops: - xmlprops[key].setter(self, self._propstore[key], - validate=False) - else: - for obj in util.listify(getattr(self, key)): - if self._xml_root_xpath and not obj._xml_root_xpath: - obj._xml_root_xpath = self._xml_root_xpath - obj._add_parse_bits(xml=None, node=self._xml_node) + xmlprops[key]._set_xml(self, self._propstore[key], node) + continue - return _indent(self._do_get_xml_config(), indent) + for obj in util.listify(getattr(self, key)): + if self._xml_root_xpath and not obj._xml_root_xpath: + obj._xml_root_xpath = self._xml_root_xpath + obj._add_parse_bits(node, ctx) - def _add_parse_bits(self, xml, node=None): + return self._get_node_xml(ctx) + + def _add_parse_bits(self, node, ctx): """ Callback that adds the implicitly tracked XML properties to the manually generated xml. This should only exist until all classes are converted to all parsing all the time """ - if self._is_parse(): - return xml - origproporder = self._proporder[:] origpropstore = self._propstore.copy() try: - return self._do_add_parse_bits(xml, node) + return self._do_add_parse_bits(node, ctx) finally: - self._xml_root_doc = None - self._xml_node = None - self._xml_ctx = None self._proporder = origproporder self._propstore = origpropstore