Commit 4d99964c authored by Bernardo Dal Seno's avatar Bernardo Dal Seno
Browse files

Generic function to print data for gnt-xxx info



The function produces a human-readable output, which is also a valid YAML
file, from an intermediate data structure. This will be used by "gnt-xxx
info" commands. The output of "gnt-xxx info" was almost YAML-compliant, and
only minor adjustments are needed to make it fully compliant.
Signed-off-by: default avatarBernardo Dal Seno <bdalseno@google.com>
Reviewed-by: default avatarHelga Velroyen <helgav@google.com>
parent 61f8fda4
......@@ -234,6 +234,8 @@ __all__ = [
"FormatError",
"FormatQueryResult",
"FormatParameterDict",
"FormatParamsDictInfo",
"PrintGenericInfo",
"GenerateTable",
"AskUser",
"FormatTimestamp",
......@@ -3610,6 +3612,27 @@ def FormatParameterDict(buf, param_dict, actual, level=1):
buf.write(" %s\n" % val)
def FormatParamsDictInfo(param_dict, actual):
"""Formats a parameter dictionary.
@type param_dict: dict
@param param_dict: the own parameters
@type actual: dict
@param actual: the current parameter set (including defaults)
@rtype: dict
@return: dictionary where the value of each parameter is either a fully
formatted string or a dictionary containing formatted strings
"""
ret = {}
for (key, data) in actual.items():
if isinstance(data, dict) and data:
ret[key] = FormatParamsDictInfo(param_dict.get(key, {}), data)
else:
ret[key] = str(param_dict.get(key, "default (%s)" % data))
return ret
def ConfirmOperation(names, list_type, text, extra=""):
"""Ask the user to confirm an operation on a list of list_type.
......@@ -3736,3 +3759,93 @@ def CreateIPolicyFromOpts(ispecs_mem_size=None,
assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
return ipolicy_out
def _SerializeGenericInfo(buf, data, level, afterkey=False):
"""Formatting core of L{PrintGenericInfo}.
@param buf: (string) stream to accumulate the result into
@param data: data to format
@type level: int
@param level: depth in the data hierarchy, used for indenting
@type afterkey: bool
@param afterkey: True when we are in the middle of a line after a key (used
to properly add newlines or indentation)
"""
baseind = " "
if isinstance(data, dict):
if not data:
buf.write("\n")
else:
if afterkey:
buf.write("\n")
doindent = True
else:
doindent = False
for key in sorted(data):
if doindent:
buf.write(baseind * level)
else:
doindent = True
buf.write(key)
buf.write(": ")
_SerializeGenericInfo(buf, data[key], level + 1, afterkey=True)
elif isinstance(data, list) and len(data) > 0 and isinstance(data[0], tuple):
# list of tuples (an ordered dictionary)
if afterkey:
buf.write("\n")
doindent = True
else:
doindent = False
for (key, val) in data:
if doindent:
buf.write(baseind * level)
else:
doindent = True
buf.write(key)
buf.write(": ")
_SerializeGenericInfo(buf, val, level + 1, afterkey=True)
elif isinstance(data, list):
if not data:
buf.write("\n")
else:
if afterkey:
buf.write("\n")
doindent = True
else:
doindent = False
for item in data:
if doindent:
buf.write(baseind * level)
else:
doindent = True
buf.write("-")
buf.write(baseind[1:])
_SerializeGenericInfo(buf, item, level + 1)
else:
# This branch should be only taken for strings, but it's practically
# impossible to guarantee that no other types are produced somewhere
buf.write(str(data))
buf.write("\n")
def PrintGenericInfo(data):
"""Print information formatted according to the hierarchy.
The output is a valid YAML string.
@param data: the data to print. It's a hierarchical structure whose elements
can be:
- dictionaries, where keys are strings and values are of any of the
types listed here
- lists of pairs (key, value), where key is a string and value is of
any of the types listed here; it's a way to encode ordered
dictionaries
- lists of any of the types listed here
- strings
"""
buf = StringIO()
_SerializeGenericInfo(buf, data, 0)
ToStdout(buf.getvalue().rstrip("\n"))
......@@ -1044,5 +1044,83 @@ class TestFieldDescValues(unittest.TestCase):
["zname", kind, "Ztitle", "zzz doc zzz"])
class TestSerializeGenericInfo(unittest.TestCase):
"""Test case for cli._SerializeGenericInfo"""
def _RunTest(self, data, expected):
buf = StringIO()
cli._SerializeGenericInfo(buf, data, 0)
self.assertEqual(buf.getvalue(), expected)
def testSimple(self):
test_samples = [
("abc", "abc\n"),
([], "\n"),
({}, "\n"),
(["1", "2", "3"], "- 1\n- 2\n- 3\n"),
([("z", "26")], "z: 26\n"),
({"z": "26"}, "z: 26\n"),
([("z", "26"), ("a", "1")], "z: 26\na: 1\n"),
({"z": "26", "a": "1"}, "a: 1\nz: 26\n"),
]
for (data, expected) in test_samples:
self._RunTest(data, expected)
def testLists(self):
adict = {
"aa": "11",
"bb": "22",
"cc": "33",
}
adict_exp = ("- aa: 11\n"
" bb: 22\n"
" cc: 33\n")
anobj = [
("zz", "11"),
("ww", "33"),
("xx", "22"),
]
anobj_exp = ("- zz: 11\n"
" ww: 33\n"
" xx: 22\n")
alist = ["aa", "cc", "bb"]
alist_exp = ("- - aa\n"
" - cc\n"
" - bb\n")
test_samples = [
(adict, adict_exp),
(anobj, anobj_exp),
(alist, alist_exp),
]
for (base_data, base_expected) in test_samples:
for k in range(1, 4):
data = k * [base_data]
expected = k * base_expected
self._RunTest(data, expected)
def testDictionaries(self):
data = [
("aaa", ["x", "y"]),
("bbb", {
"w": "1",
"z": "2",
}),
("ccc", [
("xyz", "123"),
("efg", "456"),
]),
]
expected = ("aaa: \n"
" - x\n"
" - y\n"
"bbb: \n"
" w: 1\n"
" z: 2\n"
"ccc: \n"
" xyz: 123\n"
" efg: 456\n")
self._RunTest(data, expected)
self._RunTest(dict(data), expected)
if __name__ == "__main__":
testutils.GanetiTestProgram()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment