xmlbuilder: Drop is_multi option

It complicates things quite a bit. And there's only one user, so just open
code it.
This commit is contained in:
Cole Robinson 2013-07-24 12:35:03 -04:00
parent 7411776c9a
commit 7a369a9802
4 changed files with 68 additions and 61 deletions

View File

@ -6,8 +6,8 @@
<os>
<type arch="i686">hvm</type>
<loader>/usr/lib/xen/boot/hvmloader</loader>
<boot dev="cdrom"/>
<bootmenu enable="yes"/>
<boot dev="cdrom"/>
<kernel>foo.img</kernel>
<initrd>bar.img</initrd>
<cmdline>ks=foo.ks</cmdline>

View File

@ -5,9 +5,9 @@
<uuid>11111111-2222-3333-4444-555555555555</uuid>
<os>
<type machine="pc-0.11">xen</type>
<boot dev="fd"/>
<loader>/foo/loader</loader>
<init>/sbin/init</init>
<boot dev="fd"/>
<bootmenu enable="no"/>
</os>
<features>

View File

@ -20,11 +20,29 @@
from virtinst.xmlbuilder import XMLBuilder, XMLProperty
class BootDevice(XMLBuilder):
_XML_ROOT_XPATH = "/domain/os/boot"
def __init__(self, conn, dev, parsexml=None, parsexmlnode=None):
XMLBuilder.__init__(self, conn, parsexml, parsexmlnode)
self._dev = dev
self._xmldev = dev
def _get_dev(self):
return self._xmldev
dev = property(_get_dev)
def _dev_xpath(self):
return "./os/boot[@dev='%s']/@dev" % self._dev
_xmldev = XMLProperty(name="boot dev type",
make_getter_xpath_cb=_dev_xpath,
make_setter_xpath_cb=_dev_xpath)
class OSXML(XMLBuilder):
"""
Class for generating boot device related XML
"""
BOOT_DEVICE_HARDDISK = "hd"
BOOT_DEVICE_CDROM = "cdrom"
BOOT_DEVICE_FLOPPY = "fd"
@ -32,6 +50,24 @@ class OSXML(XMLBuilder):
boot_devices = [BOOT_DEVICE_HARDDISK, BOOT_DEVICE_CDROM,
BOOT_DEVICE_FLOPPY, BOOT_DEVICE_NETWORK]
def __init__(self, *args, **kwargs):
self._bootdevs = []
XMLBuilder.__init__(self, *args, **kwargs)
def _parsexml(self, xml, node):
XMLBuilder._parsexml(self, xml, node)
for node in self._xml_node.children or []:
if node.name != "boot" or not node.prop("dev"):
continue
bootdev = BootDevice(self.conn, node.prop("dev"),
parsexmlnode=self._xml_node)
self._bootdevs.append(bootdev)
def clear(self):
XMLBuilder.clear(self)
self.bootorder = []
def is_hvm(self):
return self.os_type == "hvm"
def is_xenpv(self):
@ -42,10 +78,19 @@ class OSXML(XMLBuilder):
_XML_ROOT_XPATH = "/domain/os"
_XML_PROP_ORDER = ["arch", "os_type", "loader",
"kernel", "initrd", "kernel_args",
"bootorder"]
"_bootdevs"]
def _get_bootorder(self):
return [dev.dev for dev in self._bootdevs]
def _set_bootorder(self, newdevs):
for dev in self._bootdevs:
dev.clear()
self._bootdevs = [BootDevice(self.conn, d,
parsexmlnode=self._xml_node)
for d in newdevs]
bootorder = property(_get_bootorder, _set_bootorder)
enable_bootmenu = XMLProperty(xpath="./os/bootmenu/@enable", is_yesno=True)
bootorder = XMLProperty(xpath="./os/boot/@dev", is_multi=True)
kernel = XMLProperty(xpath="./os/kernel")
initrd = XMLProperty(xpath="./os/initrd")

View File

@ -87,11 +87,9 @@ def _sanitize_libxml_xml(xml):
return xml
def _get_xpath_node(ctx, xpath, is_multi=False):
def _get_xpath_node(ctx, xpath):
node = ctx.xpathEval(xpath)
if not is_multi:
return (node and node[0] or None)
return node
def _build_xpath_node(ctx, xpath, addnode=None):
@ -244,8 +242,7 @@ class XMLProperty(property):
def __init__(self, doc=None, xpath=None, name=None,
set_converter=None, validate_cb=None,
make_getter_xpath_cb=None, make_setter_xpath_cb=None,
is_bool=False, is_tri=False, is_int=False,
is_multi=False, is_yesno=False,
is_bool=False, is_tri=False, is_int=False, is_yesno=False,
clear_first=None, default_cb=None, default_name=None):
"""
Set a XMLBuilder class property that represents a value in the
@ -277,7 +274,6 @@ class XMLProperty(property):
@param is_bool: Whether this is a boolean property in the XML
@param is_tri: Boolean XML property, but return None if there's
no value set.
@param is_multi: Whether data is coming multiple or a single node
@param is_int: Whethere this is an integer property in the XML
@param is_yesno: Whethere this is a yes/no property in the XML
@param clear_first: List of xpaths to unset before any 'set' operation.
@ -299,7 +295,6 @@ class XMLProperty(property):
self._is_tri = is_tri
self._is_bool = is_bool or is_tri
self._is_int = is_int
self._is_multi = is_multi
self._is_yesno = is_yesno
self._xpath_for_getter_cb = make_getter_xpath_cb
@ -359,23 +354,6 @@ class XMLProperty(property):
return xmlbuilder.fix_relative_xpath(ret)
def _xpath_list_for_setter(self, xpath, setval, nodelist):
if not self._is_multi:
return [xpath]
ret = []
list_length = max(len(nodelist), len(setval), 1)
# This might not generally work, but as of this writing there's
# only one user of is_multi and it works for that. It's probably
# generalizable though.
for i in range(list_length):
idxstr = "[%d]/" % (i + 1)
splitpath = xpath.rsplit("/", 1)
ret.append("%s%s%s" % (splitpath[0], idxstr, splitpath[1]))
return ret
def _convert_value_for_setter(self, xmlbuilder):
# Convert from API value to XML value
val = self._nonxml_fget(xmlbuilder)
@ -394,10 +372,10 @@ class XMLProperty(property):
Build list of nodes that the passed xpaths reference
"""
root_ctx = getattr(xmlbuilder, "_xml_ctx")
nodes = _get_xpath_node(root_ctx, xpath, self._is_multi)
nodes = _get_xpath_node(root_ctx, xpath)
return util.listify(nodes)
def _build_clear_list(self, xmlbuilder, setternodes):
def _build_clear_list(self, xmlbuilder, setternode):
"""
Build a list of nodes that we should erase first before performing
a set operation. But we don't want to unset a node that we are
@ -408,11 +386,10 @@ class XMLProperty(property):
for cpath in self._setter_clear_these_first:
cpath = xmlbuilder.fix_relative_xpath(cpath)
cnode = _get_xpath_node(root_ctx, cpath, False)
cnode = _get_xpath_node(root_ctx, cpath)
if not cnode:
continue
if any([(n and n.nodePath() == cnode.nodePath())
for n in setternodes]):
if setternode and setternode.nodePath() == cnode.nodePath():
continue
clear_nodes.append(cnode)
return clear_nodes
@ -431,8 +408,6 @@ class XMLProperty(property):
ret = int(val, **intkwargs)
elif self._is_yesno and val is not None:
ret = bool(val == "yes")
elif self._is_multi and val is None:
ret = []
else:
ret = val
return ret
@ -492,10 +467,7 @@ class XMLProperty(property):
return propstore.get(propname, None)
def _clear(self, xmlbuilder):
val = None
if self._is_multi:
val = []
self.setter(xmlbuilder, val)
self.setter(xmlbuilder, None)
##################################
@ -503,29 +475,20 @@ class XMLProperty(property):
##################################
def getter(self, xmlbuilder):
root_node = getattr(xmlbuilder, "_xml_node")
if root_node is None:
if xmlbuilder._xml_ctx is None:
fgetval = self._nonxml_fget(xmlbuilder)
return self._convert_get_value(fgetval, initial=True)
xpath = self._xpath_for_getter(xmlbuilder)
nodelist = self._build_node_list(xmlbuilder, xpath)
node = _get_xpath_node(xmlbuilder._xml_ctx, xpath)
if not nodelist:
if not node:
return self._convert_get_value(None)
ret = []
for node in nodelist:
content = node.content
if self._is_bool:
content = True
val = self._convert_get_value(content)
if not self._is_multi:
return val
# If user is querying multiple nodes, return a list of results
ret.append(val)
return ret
return self._convert_get_value(content)
def setter(self, xmlbuilder, val, call_fset=True, validate=True):
if call_fset:
@ -539,14 +502,13 @@ class XMLProperty(property):
xpath = self._xpath_for_setter(xmlbuilder)
setval = self._convert_value_for_setter(xmlbuilder)
nodelist = self._build_node_list(xmlbuilder, xpath)
clearlist = self._build_clear_list(xmlbuilder, nodelist)
node = _get_xpath_node(xmlbuilder._xml_ctx, xpath)
clearlist = self._build_clear_list(xmlbuilder, node)
node_map = []
if clearlist:
node_map += _tuplify_lists(clearlist, None, "")
node_map += _tuplify_lists(nodelist, setval,
self._xpath_list_for_setter(xpath, setval, nodelist))
node_map += [(node, setval, xpath)]
for node, val, use_xpath in node_map:
if node: