216 lines
7.9 KiB
Diff
216 lines
7.9 KiB
Diff
|
Subject: cli: Make _VirtCLIArgument instantiation less crazy
|
||
|
From: Cole Robinson crobinso@redhat.com Fri Oct 20 16:47:56 2017 -0400
|
||
|
Date: Fri Oct 20 17:07:19 2017 -0400:
|
||
|
Git: 999dbb3665fb1cf7d6466dc53583a020b644e522
|
||
|
|
||
|
Motivation is that the other way had changed behavior with python3
|
||
|
which breaks things
|
||
|
|
||
|
diff --git a/virtinst/cli.py b/virtinst/cli.py
|
||
|
index 086aa0e0..2d1c33e5 100644
|
||
|
--- a/virtinst/cli.py
|
||
|
+++ b/virtinst/cli.py
|
||
|
@@ -805,10 +805,10 @@ def _set_attribute(obj, attr, val): # pylint: disable=unused-argument
|
||
|
exec("obj." + attr + " = val ") # pylint: disable=exec-used
|
||
|
|
||
|
|
||
|
-class _VirtCLIArgument(object):
|
||
|
+class _VirtCLIArgumentStatic(object):
|
||
|
"""
|
||
|
- A single subargument passed to compound command lines like --disk,
|
||
|
- --network, etc.
|
||
|
+ Helper class to hold all of the static data we need for knowing
|
||
|
+ how to parse a cli subargument, like --disk path=, or --network mac=.
|
||
|
|
||
|
@attrname: The virtinst API attribute name the cliargument maps to.
|
||
|
If this is a virtinst object method, it will be called.
|
||
|
@@ -838,66 +838,64 @@ class _VirtCLIArgument(object):
|
||
|
VirtualDisk has multiple seclabel children, this provides a hook
|
||
|
to lookup the specified child object.
|
||
|
"""
|
||
|
- attrname = None
|
||
|
- cliname = None
|
||
|
- cb = None
|
||
|
- can_comma = None
|
||
|
- ignore_default = False
|
||
|
- aliases = None
|
||
|
- is_list = False
|
||
|
- is_onoff = False
|
||
|
- lookup_cb = None
|
||
|
- is_novalue = False
|
||
|
- find_inst_cb = None
|
||
|
-
|
||
|
- @staticmethod
|
||
|
- def make_arg(attrname, cliname, **kwargs):
|
||
|
- """
|
||
|
- Generates a new VirtCLIArgument class with the passed static
|
||
|
- values. Initialize it later with the actual command line and value.
|
||
|
- kwargs can be any of the
|
||
|
- """
|
||
|
- class VirtAddArg(_VirtCLIArgument):
|
||
|
- pass
|
||
|
-
|
||
|
- VirtAddArg.attrname = attrname
|
||
|
- VirtAddArg.cliname = cliname
|
||
|
- for key, val in kwargs.items():
|
||
|
- # getattr for validation
|
||
|
- getattr(VirtAddArg, key)
|
||
|
- setattr(VirtAddArg, key, val)
|
||
|
- return VirtAddArg
|
||
|
-
|
||
|
- @classmethod
|
||
|
- def match_name(cls, cliname):
|
||
|
+ def __init__(self, attrname, cliname,
|
||
|
+ cb=None, can_comma=None,
|
||
|
+ ignore_default=False, aliases=None,
|
||
|
+ is_list=False, is_onoff=False,
|
||
|
+ lookup_cb=None, is_novalue=False,
|
||
|
+ find_inst_cb=None):
|
||
|
+ self.attrname = attrname
|
||
|
+ self.cliname = cliname
|
||
|
+ self.cb = cb
|
||
|
+ self.can_comma = can_comma
|
||
|
+ self.ignore_default = ignore_default
|
||
|
+ self.aliases = aliases
|
||
|
+ self.is_list = is_list
|
||
|
+ self.is_onoff = is_onoff
|
||
|
+ self.lookup_cb = lookup_cb
|
||
|
+ self.is_novalue = is_novalue
|
||
|
+ self.find_inst_cb = find_inst_cb
|
||
|
+
|
||
|
+ def match_name(self, cliname):
|
||
|
"""
|
||
|
Return True if the passed argument name matches this
|
||
|
VirtCLIArgument. So for an option like --foo bar=X, this
|
||
|
checks if we are the parser for 'bar'
|
||
|
"""
|
||
|
- for argname in [cls.cliname] + util.listify(cls.aliases):
|
||
|
+ for argname in [self.cliname] + util.listify(self.aliases):
|
||
|
if re.match("^%s$" % argname, cliname):
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
|
||
|
- def __init__(self, key, val):
|
||
|
+class _VirtCLIArgument(object):
|
||
|
+ """
|
||
|
+ A class that combines the static parsing data _VirtCLIArgumentStatic
|
||
|
+ with actual values passed on the command line.
|
||
|
+ """
|
||
|
+
|
||
|
+ def __init__(self, virtarg, key, val):
|
||
|
"""
|
||
|
Instantiate a VirtCLIArgument with the actual key=val pair
|
||
|
from the command line.
|
||
|
"""
|
||
|
# Sanitize the value
|
||
|
if val is None:
|
||
|
- if not self.is_novalue:
|
||
|
+ if not virtarg.is_novalue:
|
||
|
raise RuntimeError("Option '%s' had no value set." % key)
|
||
|
val = ""
|
||
|
if val == "":
|
||
|
val = None
|
||
|
- if self.is_onoff:
|
||
|
+ if virtarg.is_onoff:
|
||
|
val = _on_off_convert(key, val)
|
||
|
|
||
|
self.val = val
|
||
|
self.key = key
|
||
|
+ self._virtarg = virtarg
|
||
|
+
|
||
|
+ # For convenience
|
||
|
+ self.attrname = virtarg.attrname
|
||
|
+ self.cliname = virtarg.cliname
|
||
|
|
||
|
def parse_param(self, parser, inst, support_cb):
|
||
|
"""
|
||
|
@@ -909,12 +907,12 @@ class _VirtCLIArgument(object):
|
||
|
"""
|
||
|
if support_cb:
|
||
|
support_cb(inst, self)
|
||
|
- if self.val == "default" and self.ignore_default:
|
||
|
+ if self.val == "default" and self._virtarg.ignore_default:
|
||
|
return
|
||
|
|
||
|
- if self.find_inst_cb:
|
||
|
- inst = self.find_inst_cb(parser, # pylint: disable=not-callable
|
||
|
- inst, self.val, self, True)
|
||
|
+ if self._virtarg.find_inst_cb:
|
||
|
+ inst = self._virtarg.find_inst_cb(parser,
|
||
|
+ inst, self.val, self, True)
|
||
|
|
||
|
try:
|
||
|
if self.attrname:
|
||
|
@@ -923,9 +921,8 @@ class _VirtCLIArgument(object):
|
||
|
raise RuntimeError("programming error: obj=%s does not have "
|
||
|
"member=%s" % (inst, self.attrname))
|
||
|
|
||
|
- if self.cb:
|
||
|
- self.cb(parser, inst, # pylint: disable=not-callable
|
||
|
- self.val, self)
|
||
|
+ if self._virtarg.cb:
|
||
|
+ self._virtarg.cb(parser, inst, self.val, self)
|
||
|
else:
|
||
|
_set_attribute(inst, self.attrname, self.val)
|
||
|
|
||
|
@@ -938,22 +935,22 @@ class _VirtCLIArgument(object):
|
||
|
instantiated with key=device val=floppy, so return
|
||
|
'inst.device == floppy'
|
||
|
"""
|
||
|
- if not self.attrname and not self.lookup_cb:
|
||
|
+ if not self.attrname and not self._virtarg.lookup_cb:
|
||
|
raise RuntimeError(
|
||
|
_("Don't know how to match device type '%(device_type)s' "
|
||
|
"property '%(property_name)s'") %
|
||
|
{"device_type": getattr(inst, "virtual_device_type", ""),
|
||
|
"property_name": self.key})
|
||
|
|
||
|
- if self.find_inst_cb:
|
||
|
- inst = self.find_inst_cb(parser, # pylint: disable=not-callable
|
||
|
- inst, self.val, self, False)
|
||
|
+ if self._virtarg.find_inst_cb:
|
||
|
+ inst = self._virtarg.find_inst_cb(parser,
|
||
|
+ inst, self.val, self, False)
|
||
|
if not inst:
|
||
|
return False
|
||
|
|
||
|
- if self.lookup_cb:
|
||
|
- return self.lookup_cb(parser, # pylint: disable=not-callable
|
||
|
- inst, self.val, self)
|
||
|
+ if self._virtarg.lookup_cb:
|
||
|
+ return self._virtarg.lookup_cb(parser,
|
||
|
+ inst, self.val, self)
|
||
|
else:
|
||
|
return eval( # pylint: disable=eval-used
|
||
|
"inst." + self.attrname) == self.val
|
||
|
@@ -1095,9 +1092,9 @@ class VirtCLIParser(object):
|
||
|
Add a VirtCLIArgument for this class.
|
||
|
"""
|
||
|
if not cls._virtargs:
|
||
|
- cls._virtargs = [_VirtCLIArgument.make_arg(
|
||
|
+ cls._virtargs = [_VirtCLIArgumentStatic(
|
||
|
None, "clearxml", cb=cls._clearxml_cb, is_onoff=True)]
|
||
|
- cls._virtargs.append(_VirtCLIArgument.make_arg(*args, **kwargs))
|
||
|
+ cls._virtargs.append(_VirtCLIArgumentStatic(*args, **kwargs))
|
||
|
|
||
|
@classmethod
|
||
|
def print_introspection(cls):
|
||
|
@@ -1147,10 +1144,12 @@ class VirtCLIParser(object):
|
||
|
VirtCLIArguments to actually interact with
|
||
|
"""
|
||
|
ret = []
|
||
|
- for param in self._virtargs:
|
||
|
- for key in optdict.keys():
|
||
|
- if param.match_name(key):
|
||
|
- ret.append(param(key, optdict.pop(key)))
|
||
|
+ for virtargstatic in self._virtargs:
|
||
|
+ for key in list(optdict.keys()):
|
||
|
+ if virtargstatic.match_name(key):
|
||
|
+ arginst = _VirtCLIArgument(virtargstatic,
|
||
|
+ key, optdict.pop(key))
|
||
|
+ ret.append(arginst)
|
||
|
return ret
|
||
|
|
||
|
def _check_leftover_opts(self, optdict):
|