commit a2d2e1a736dded77429dd4324701d59e64e12b80
Author: Iustin Pop <iustin@google.com>
Date:   Fri Nov 21 15:35:52 2008 +0000

    Move FieldSet class to utils.py
    
    Since we can use the FieldSet class in cli.py to nicely format disk
    sizes and such, we move it to utils.py and also move its associated
    unittest. I didn't remove the cmdlib.py unittest file as that's not the
    good direction :)
    
    Reviewed-by: ultrotter

diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index c65919e..f3ac782 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -32,7 +32,6 @@ import re
 import platform
 import logging
 import copy
-import itertools
 
 from ganeti import ssh
 from ganeti import utils
@@ -323,48 +322,6 @@ class NoHooksLU(LogicalUnit):
   HTYPE = None
 
 
-class _FieldSet(object):
-  """A simple field set.
-
-  Among the features are:
-    - checking if a string is among a list of static string or regex objects
-    - checking if a whole list of string matches
-    - returning the matching groups from a regex match
-
-  Internally, all fields are held as regular expression objects.
-
-  """
-  def __init__(self, *items):
-    self.items = [re.compile("^%s$" % value) for value in items]
-
-  def Extend(self, other_set):
-    """Extend the field set with the items from another one"""
-    self.items.extend(other_set.items)
-
-  def Matches(self, field):
-    """Checks if a field matches the current set
-
-    @type field: str
-    @param field: the string to match
-    @return: either False or a regular expression match object
-
-    """
-    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
-      return m
-    return False
-
-  def NonMatching(self, items):
-    """Returns the list of fields not matching the current set
-
-    @type items: list
-    @param items: the list of fields to check
-    @rtype: list
-    @return: list of non-matching fields
-
-    """
-    return [val for val in items if not self.Matches(val)]
-
-
 def _GetWantedNodes(lu, nodes):
   """Returns list of checked and expanded node names.
 
@@ -416,13 +373,13 @@ def _GetWantedInstances(lu, instances):
 def _CheckOutputFields(static, dynamic, selected):
   """Checks whether all selected fields are valid.
 
-  @type static: L{_FieldSet}
+  @type static: L{utils.FieldSet}
   @param static: static fields set
-  @type dynamic: L{_FieldSet}
+  @type dynamic: L{utils.FieldSet}
   @param dynamic: dynamic fields set
 
   """
-  f = _FieldSet()
+  f = utils.FieldSet()
   f.Extend(static)
   f.Extend(dynamic)
 
@@ -1362,8 +1319,8 @@ class LUDiagnoseOS(NoHooksLU):
   """
   _OP_REQP = ["output_fields", "names"]
   REQ_BGL = False
-  _FIELDS_STATIC = _FieldSet()
-  _FIELDS_DYNAMIC = _FieldSet("name", "valid", "node_status")
+  _FIELDS_STATIC = utils.FieldSet()
+  _FIELDS_DYNAMIC = utils.FieldSet("name", "valid", "node_status")
 
   def ExpandNames(self):
     if self.op.names:
@@ -1518,14 +1475,14 @@ class LUQueryNodes(NoHooksLU):
   """
   _OP_REQP = ["output_fields", "names"]
   REQ_BGL = False
-  _FIELDS_DYNAMIC = _FieldSet(
+  _FIELDS_DYNAMIC = utils.FieldSet(
     "dtotal", "dfree",
     "mtotal", "mnode", "mfree",
     "bootid",
     "ctotal",
     )
 
-  _FIELDS_STATIC = _FieldSet(
+  _FIELDS_STATIC = utils.FieldSet(
     "name", "pinst_cnt", "sinst_cnt",
     "pinst_list", "sinst_list",
     "pip", "sip", "tags",
@@ -1657,8 +1614,8 @@ class LUQueryNodeVolumes(NoHooksLU):
   """
   _OP_REQP = ["nodes", "output_fields"]
   REQ_BGL = False
-  _FIELDS_DYNAMIC = _FieldSet("phys", "vg", "name", "size", "instance")
-  _FIELDS_STATIC = _FieldSet("node")
+  _FIELDS_DYNAMIC = utils.FieldSet("phys", "vg", "name", "size", "instance")
+  _FIELDS_STATIC = utils.FieldSet("node")
 
   def ExpandNames(self):
     _CheckOutputFields(static=self._FIELDS_STATIC,
@@ -1979,8 +1936,8 @@ class LUQueryConfigValues(NoHooksLU):
   """
   _OP_REQP = []
   REQ_BGL = False
-  _FIELDS_DYNAMIC = _FieldSet()
-  _FIELDS_STATIC = _FieldSet("cluster_name", "master_node", "drain_flag")
+  _FIELDS_DYNAMIC = utils.FieldSet()
+  _FIELDS_STATIC = utils.FieldSet("cluster_name", "master_node", "drain_flag")
 
   def ExpandNames(self):
     self.needed_locks = {}
@@ -2714,22 +2671,22 @@ class LUQueryInstances(NoHooksLU):
   """
   _OP_REQP = ["output_fields", "names"]
   REQ_BGL = False
-  _FIELDS_STATIC = _FieldSet(*["name", "os", "pnode", "snodes",
-                               "admin_state", "admin_ram",
-                               "disk_template", "ip", "mac", "bridge",
-                               "sda_size", "sdb_size", "vcpus", "tags",
-                               "network_port", "beparams",
-                               "(disk).(size)/([0-9]+)",
-                               "(disk).(sizes)",
-                               "(nic).(mac|ip|bridge)/([0-9]+)",
-                               "(nic).(macs|ips|bridges)",
-                               "(disk|nic).(count)",
-                               "serial_no", "hypervisor", "hvparams",] +
-                             ["hv/%s" % name
-                              for name in constants.HVS_PARAMETERS] +
-                             ["be/%s" % name
-                              for name in constants.BES_PARAMETERS])
-  _FIELDS_DYNAMIC = _FieldSet("oper_state", "oper_ram", "status")
+  _FIELDS_STATIC = utils.FieldSet(*["name", "os", "pnode", "snodes",
+                                    "admin_state", "admin_ram",
+                                    "disk_template", "ip", "mac", "bridge",
+                                    "sda_size", "sdb_size", "vcpus", "tags",
+                                    "network_port", "beparams",
+                                    "(disk).(size)/([0-9]+)",
+                                    "(disk).(sizes)",
+                                    "(nic).(mac|ip|bridge)/([0-9]+)",
+                                    "(nic).(macs|ips|bridges)",
+                                    "(disk|nic).(count)",
+                                    "serial_no", "hypervisor", "hvparams",] +
+                                  ["hv/%s" % name
+                                   for name in constants.HVS_PARAMETERS] +
+                                  ["be/%s" % name
+                                   for name in constants.BES_PARAMETERS])
+  _FIELDS_DYNAMIC = utils.FieldSet("oper_state", "oper_ram", "status")
 
 
   def ExpandNames(self):
diff --git a/lib/utils.py b/lib/utils.py
index e0dfcb2..582b61a 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -1818,3 +1818,45 @@ class SignalHandler(object):
     # This is not nice and not absolutely atomic, but it appears to be the only
     # solution in Python -- there are no atomic types.
     self.called = True
+
+
+class FieldSet(object):
+  """A simple field set.
+
+  Among the features are:
+    - checking if a string is among a list of static string or regex objects
+    - checking if a whole list of string matches
+    - returning the matching groups from a regex match
+
+  Internally, all fields are held as regular expression objects.
+
+  """
+  def __init__(self, *items):
+    self.items = [re.compile("^%s$" % value) for value in items]
+
+  def Extend(self, other_set):
+    """Extend the field set with the items from another one"""
+    self.items.extend(other_set.items)
+
+  def Matches(self, field):
+    """Checks if a field matches the current set
+
+    @type field: str
+    @param field: the string to match
+    @return: either False or a regular expression match object
+
+    """
+    for m in itertools.ifilter(None, (val.match(field) for val in self.items)):
+      return m
+    return False
+
+  def NonMatching(self, items):
+    """Returns the list of fields not matching the current set
+
+    @type items: list
+    @param items: the list of fields to check
+    @rtype: list
+    @return: list of non-matching fields
+
+    """
+    return [val for val in items if not self.Matches(val)]
diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py
index 1fcf43a..2955b3d 100755
--- a/test/ganeti.cmdlib_unittest.py
+++ b/test/ganeti.cmdlib_unittest.py
@@ -31,25 +31,5 @@ from ganeti import cmdlib
 from ganeti import errors
 
 
-class FieldSetTestCase(unittest.TestCase):
-  """Test case for FieldSets"""
-
-  def testSimpleMatch(self):
-    f = cmdlib._FieldSet("a", "b", "c", "def")
-    self.failUnless(f.Matches("a"))
-    self.failIf(f.Matches("d"), "Substring matched")
-    self.failIf(f.Matches("defghi"), "Prefix string matched")
-    self.failIf(f.NonMatching(["b", "c"]))
-    self.failIf(f.NonMatching(["a", "b", "c", "def"]))
-    self.failUnless(f.NonMatching(["a", "d"]))
-
-  def testRegexMatch(self):
-    f = cmdlib._FieldSet("a", "b([0-9]+)", "c")
-    self.failUnless(f.Matches("b1"))
-    self.failUnless(f.Matches("b99"))
-    self.failIf(f.Matches("b/1"))
-    self.failIf(f.NonMatching(["b12", "c"]))
-    self.failUnless(f.NonMatching(["a", "1"]))
-
 if __name__ == '__main__':
   unittest.main()
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index d0dff6e..ce54fd1 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -824,5 +824,26 @@ class TestTimeFunctions(unittest.TestCase):
     self.assertRaises(AssertionError, utils.MergeTime, (-9999, 0))
 
 
+class FieldSetTestCase(unittest.TestCase):
+  """Test case for FieldSets"""
+
+  def testSimpleMatch(self):
+    f = utils.FieldSet("a", "b", "c", "def")
+    self.failUnless(f.Matches("a"))
+    self.failIf(f.Matches("d"), "Substring matched")
+    self.failIf(f.Matches("defghi"), "Prefix string matched")
+    self.failIf(f.NonMatching(["b", "c"]))
+    self.failIf(f.NonMatching(["a", "b", "c", "def"]))
+    self.failUnless(f.NonMatching(["a", "d"]))
+
+  def testRegexMatch(self):
+    f = utils.FieldSet("a", "b([0-9]+)", "c")
+    self.failUnless(f.Matches("b1"))
+    self.failUnless(f.Matches("b99"))
+    self.failIf(f.Matches("b/1"))
+    self.failIf(f.NonMatching(["b12", "c"]))
+    self.failUnless(f.NonMatching(["a", "1"]))
+
+
 if __name__ == '__main__':
   unittest.main()
