moduleinfo.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. # Copyright (C) 2009 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. """This module holds classes representing modules, commands and
  16. parameters for use in bindctl"""
  17. import textwrap
  18. try:
  19. from collections import OrderedDict
  20. except ImportError:
  21. from bindctl.mycollections import OrderedDict
  22. # Define value type
  23. STRING_TYPE = "string"
  24. LIST_TYPE = "list"
  25. INT_TYPE = "int"
  26. MODULE_NODE_NAME = 'module'
  27. COMMAND_NODE_NAME = 'command'
  28. PARAM_NODE_NAME = 'param'
  29. # this is used to align the descriptions in help output
  30. CONST_BINDCTL_HELP_INDENT_WIDTH=12
  31. class ParamInfo:
  32. """One parameter of one command.
  33. Each command parameter has five attributes:
  34. parameter name, parameter type, parameter value,
  35. parameter description and paramter's spec(got from
  36. module spec file).
  37. """
  38. def __init__(self, name, desc = '', type = STRING_TYPE,
  39. optional = False, value = '', default_value = '',
  40. param_spec = None):
  41. self.name = name
  42. self.type = type
  43. self.value = value
  44. self.default_value = default_value
  45. self.desc = desc
  46. self.is_optional = optional
  47. self.param_spec = param_spec
  48. def __str__(self):
  49. return str("\t%s <type: %s> \t(%s)" % (self.name, self.type, self.desc))
  50. def get_basic_info(self):
  51. if self.is_optional:
  52. opt_str = "optional"
  53. else:
  54. opt_str = "mandatory"
  55. return "%s (%s, %s)" % (self.name, self.type, opt_str)
  56. def get_desc(self):
  57. return self.desc
  58. class CommandInfo:
  59. """One command which is provided by one bind10 module, it has zero
  60. or more parameters
  61. """
  62. def __init__(self, name, desc = ""):
  63. self.name = name
  64. self.desc = desc
  65. self.params = OrderedDict()
  66. # Set default parameter "help"
  67. self.add_param(ParamInfo("help",
  68. desc = "Get help for command.",
  69. optional = True))
  70. def __str__(self):
  71. return str("%s \t(%s)" % (self.name, self.desc))
  72. def get_name(self):
  73. return self.name
  74. def get_desc(self):
  75. return self.desc;
  76. def add_param(self, paraminfo):
  77. """Add a ParamInfo object to this CommandInfo"""
  78. self.params[paraminfo.name] = paraminfo
  79. def has_param_with_name(self, param_name):
  80. """Returns true if the parameter with param_name exists"""
  81. return param_name in self.params
  82. def get_param_with_name(self, param_name):
  83. """Returns the ParamInfo with the given name. Raises a
  84. KeyError if it doesn't exist"""
  85. return self.params[param_name]
  86. def get_params(self):
  87. """Returns a list of all ParamInfo objects for this CommandInfo"""
  88. return list(self.params.values())
  89. def get_param_names(self):
  90. """Returns a list of the names of all parameters for this command"""
  91. return list(self.params.keys())
  92. def get_mandatory_param_names(self):
  93. """Returns a list of the names of all mandatory parameters for
  94. this command"""
  95. all_names = self.params.keys()
  96. return [name for name in all_names
  97. if not self.params[name].is_optional]
  98. def get_param_name_by_position(self, pos, param_count):
  99. """
  100. Find a proper parameter name for the position 'pos':
  101. If param_count is equal to the count of mandatory parameters of command,
  102. and there is some optional parameter, find the first mandatory parameter
  103. from the position 'pos' to the end. Else, return the name on position pos.
  104. (This function will be changed if bindctl command line syntax is changed
  105. in the future. )
  106. """
  107. if type(pos) != int:
  108. raise KeyError(str(pos) + " is not an integer")
  109. else:
  110. params = self.params.copy()
  111. del params['help']
  112. count = len(params)
  113. if (pos >= count):
  114. raise KeyError(str(pos) + " out of range")
  115. mandatory_count = len(self.get_mandatory_param_names())
  116. param_names = list(params.keys())
  117. if (param_count == mandatory_count) and (param_count < count):
  118. while pos < count:
  119. if not params[param_names[pos]].is_optional:
  120. return param_names[pos]
  121. pos += 1
  122. raise KeyError(str(pos) + "parameters have error")
  123. else:
  124. return param_names[pos]
  125. def command_help(self):
  126. """Prints the help info for this command to stdout"""
  127. print("Command ", self)
  128. print("\t\thelp (Get help for command)")
  129. params = self.params.copy()
  130. del params["help"]
  131. if len(params) == 0:
  132. print("This command has no parameters")
  133. return
  134. print("Parameters:")
  135. for info in params.values():
  136. print(" %s" % info.get_basic_info())
  137. description = info.get_desc()
  138. if description != "":
  139. print(textwrap.fill(description,
  140. initial_indent=" ",
  141. subsequent_indent=" ",
  142. width=70))
  143. class ModuleInfo:
  144. """Define the information of one module, include module name,
  145. module supporting commands.
  146. """
  147. def __init__(self, name, desc = ""):
  148. self.name = name
  149. self.desc = desc
  150. self.commands = OrderedDict()
  151. self.add_command(CommandInfo(name = "help",
  152. desc = "Get help for module."))
  153. def __str__(self):
  154. return str("%s \t%s" % (self.name, self.desc))
  155. def get_name(self):
  156. return self.name
  157. def get_desc(self):
  158. return self.desc
  159. def add_command(self, command_info):
  160. """Add a CommandInfo to this ModuleInfo."""
  161. self.commands[command_info.name] = command_info
  162. def has_command_with_name(self, command_name):
  163. """Returns true if this module has a command with the given name."""
  164. return command_name in self.commands
  165. def get_command_with_name(self, command_name):
  166. """Returns the CommandInfo for the command with the given name.
  167. Raises a KeyError if not found"""
  168. return self.commands[command_name]
  169. def get_commands(self):
  170. """Returns a list of all CommandInfo objects for this module."""
  171. return list(self.commands.values())
  172. def get_command_names(self):
  173. """Returns a list of the names of all commands for this module."""
  174. return list(self.commands.keys())
  175. def module_help(self):
  176. """Prints the help info for this module to stdout"""
  177. print("Module " + str(self))
  178. print("Available commands:")
  179. for k in self.commands.values():
  180. n = k.get_name()
  181. if len(n) >= CONST_BINDCTL_HELP_INDENT_WIDTH:
  182. print(" %s" % n)
  183. print(textwrap.fill(k.get_desc(),
  184. initial_indent=" ",
  185. subsequent_indent=" " +
  186. " " * CONST_BINDCTL_HELP_INDENT_WIDTH,
  187. width=70))
  188. else:
  189. print(textwrap.fill("%s%s%s" %
  190. (k.get_name(),
  191. " "*(CONST_BINDCTL_HELP_INDENT_WIDTH - len(k.get_name())),
  192. k.get_desc()),
  193. initial_indent=" ",
  194. subsequent_indent=" " +
  195. " " * CONST_BINDCTL_HELP_INDENT_WIDTH,
  196. width=70))
  197. def command_help(self, command):
  198. """Prints the help info for the command with the given name.
  199. Raises KeyError if not found"""
  200. self.commands[command].command_help()