Revision 4d99964c

b/lib/cli.py
234 234
  "FormatError",
235 235
  "FormatQueryResult",
236 236
  "FormatParameterDict",
237
  "FormatParamsDictInfo",
238
  "PrintGenericInfo",
237 239
  "GenerateTable",
238 240
  "AskUser",
239 241
  "FormatTimestamp",
......
3610 3612
      buf.write(" %s\n" % val)
3611 3613

  
3612 3614

  
3615
def FormatParamsDictInfo(param_dict, actual):
3616
  """Formats a parameter dictionary.
3617

  
3618
  @type param_dict: dict
3619
  @param param_dict: the own parameters
3620
  @type actual: dict
3621
  @param actual: the current parameter set (including defaults)
3622
  @rtype: dict
3623
  @return: dictionary where the value of each parameter is either a fully
3624
      formatted string or a dictionary containing formatted strings
3625

  
3626
  """
3627
  ret = {}
3628
  for (key, data) in actual.items():
3629
    if isinstance(data, dict) and data:
3630
      ret[key] = FormatParamsDictInfo(param_dict.get(key, {}), data)
3631
    else:
3632
      ret[key] = str(param_dict.get(key, "default (%s)" % data))
3633
  return ret
3634

  
3635

  
3613 3636
def ConfirmOperation(names, list_type, text, extra=""):
3614 3637
  """Ask the user to confirm an operation on a list of list_type.
3615 3638

  
......
3736 3759
  assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
3737 3760

  
3738 3761
  return ipolicy_out
3762

  
3763

  
3764
def _SerializeGenericInfo(buf, data, level, afterkey=False):
3765
  """Formatting core of L{PrintGenericInfo}.
3766

  
3767
  @param buf: (string) stream to accumulate the result into
3768
  @param data: data to format
3769
  @type level: int
3770
  @param level: depth in the data hierarchy, used for indenting
3771
  @type afterkey: bool
3772
  @param afterkey: True when we are in the middle of a line after a key (used
3773
      to properly add newlines or indentation)
3774

  
3775
  """
3776
  baseind = "  "
3777
  if isinstance(data, dict):
3778
    if not data:
3779
      buf.write("\n")
3780
    else:
3781
      if afterkey:
3782
        buf.write("\n")
3783
        doindent = True
3784
      else:
3785
        doindent = False
3786
      for key in sorted(data):
3787
        if doindent:
3788
          buf.write(baseind * level)
3789
        else:
3790
          doindent = True
3791
        buf.write(key)
3792
        buf.write(": ")
3793
        _SerializeGenericInfo(buf, data[key], level + 1, afterkey=True)
3794
  elif isinstance(data, list) and len(data) > 0 and isinstance(data[0], tuple):
3795
    # list of tuples (an ordered dictionary)
3796
    if afterkey:
3797
      buf.write("\n")
3798
      doindent = True
3799
    else:
3800
      doindent = False
3801
    for (key, val) in data:
3802
      if doindent:
3803
        buf.write(baseind * level)
3804
      else:
3805
        doindent = True
3806
      buf.write(key)
3807
      buf.write(": ")
3808
      _SerializeGenericInfo(buf, val, level + 1, afterkey=True)
3809
  elif isinstance(data, list):
3810
    if not data:
3811
      buf.write("\n")
3812
    else:
3813
      if afterkey:
3814
        buf.write("\n")
3815
        doindent = True
3816
      else:
3817
        doindent = False
3818
      for item in data:
3819
        if doindent:
3820
          buf.write(baseind * level)
3821
        else:
3822
          doindent = True
3823
        buf.write("-")
3824
        buf.write(baseind[1:])
3825
        _SerializeGenericInfo(buf, item, level + 1)
3826
  else:
3827
    # This branch should be only taken for strings, but it's practically
3828
    # impossible to guarantee that no other types are produced somewhere
3829
    buf.write(str(data))
3830
    buf.write("\n")
3831

  
3832

  
3833
def PrintGenericInfo(data):
3834
  """Print information formatted according to the hierarchy.
3835

  
3836
  The output is a valid YAML string.
3837

  
3838
  @param data: the data to print. It's a hierarchical structure whose elements
3839
      can be:
3840
        - dictionaries, where keys are strings and values are of any of the
3841
          types listed here
3842
        - lists of pairs (key, value), where key is a string and value is of
3843
          any of the types listed here; it's a way to encode ordered
3844
          dictionaries
3845
        - lists of any of the types listed here
3846
        - strings
3847

  
3848
  """
3849
  buf = StringIO()
3850
  _SerializeGenericInfo(buf, data, 0)
3851
  ToStdout(buf.getvalue().rstrip("\n"))
b/test/py/ganeti.cli_unittest.py
1044 1044
                     ["zname", kind, "Ztitle", "zzz doc zzz"])
1045 1045

  
1046 1046

  
1047
class TestSerializeGenericInfo(unittest.TestCase):
1048
  """Test case for cli._SerializeGenericInfo"""
1049
  def _RunTest(self, data, expected):
1050
    buf = StringIO()
1051
    cli._SerializeGenericInfo(buf, data, 0)
1052
    self.assertEqual(buf.getvalue(), expected)
1053

  
1054
  def testSimple(self):
1055
    test_samples = [
1056
      ("abc", "abc\n"),
1057
      ([], "\n"),
1058
      ({}, "\n"),
1059
      (["1", "2", "3"], "- 1\n- 2\n- 3\n"),
1060
      ([("z", "26")], "z: 26\n"),
1061
      ({"z": "26"}, "z: 26\n"),
1062
      ([("z", "26"), ("a", "1")], "z: 26\na: 1\n"),
1063
      ({"z": "26", "a": "1"}, "a: 1\nz: 26\n"),
1064
      ]
1065
    for (data, expected) in test_samples:
1066
      self._RunTest(data, expected)
1067

  
1068
  def testLists(self):
1069
    adict = {
1070
      "aa": "11",
1071
      "bb": "22",
1072
      "cc": "33",
1073
      }
1074
    adict_exp = ("- aa: 11\n"
1075
                 "  bb: 22\n"
1076
                 "  cc: 33\n")
1077
    anobj = [
1078
      ("zz", "11"),
1079
      ("ww", "33"),
1080
      ("xx", "22"),
1081
      ]
1082
    anobj_exp = ("- zz: 11\n"
1083
                 "  ww: 33\n"
1084
                 "  xx: 22\n")
1085
    alist = ["aa", "cc", "bb"]
1086
    alist_exp = ("- - aa\n"
1087
                 "  - cc\n"
1088
                 "  - bb\n")
1089
    test_samples = [
1090
      (adict, adict_exp),
1091
      (anobj, anobj_exp),
1092
      (alist, alist_exp),
1093
      ]
1094
    for (base_data, base_expected) in test_samples:
1095
      for k in range(1, 4):
1096
        data = k * [base_data]
1097
        expected = k * base_expected
1098
        self._RunTest(data, expected)
1099

  
1100
  def testDictionaries(self):
1101
    data = [
1102
      ("aaa", ["x", "y"]),
1103
      ("bbb", {
1104
          "w": "1",
1105
          "z": "2",
1106
          }),
1107
      ("ccc", [
1108
          ("xyz", "123"),
1109
          ("efg", "456"),
1110
          ]),
1111
      ]
1112
    expected = ("aaa: \n"
1113
                "  - x\n"
1114
                "  - y\n"
1115
                "bbb: \n"
1116
                "  w: 1\n"
1117
                "  z: 2\n"
1118
                "ccc: \n"
1119
                "  xyz: 123\n"
1120
                "  efg: 456\n")
1121
    self._RunTest(data, expected)
1122
    self._RunTest(dict(data), expected)
1123

  
1124

  
1047 1125
if __name__ == "__main__":
1048 1126
  testutils.GanetiTestProgram()

Also available in: Unified diff