[svn] commit: r116 - in /experiments/likun-bigtool: README lib/bigtool.py lib/command.py lib/exception.py lib/moduleinfo.py test_bigtool.py test_command.py

BIND 10 source code commits bind10-changes at lists.isc.org
Sat Oct 24 12:37:08 UTC 2009


Author: zhanglikun
Date: Sat Oct 24 12:37:08 2009
New Revision: 116

Log:
Commit code of version2.
Main Changes:
1. Add help information.
2. Change command line syntax.

Modified:
    experiments/likun-bigtool/README
    experiments/likun-bigtool/lib/bigtool.py
    experiments/likun-bigtool/lib/command.py
    experiments/likun-bigtool/lib/exception.py
    experiments/likun-bigtool/lib/moduleinfo.py
    experiments/likun-bigtool/test_bigtool.py
    experiments/likun-bigtool/test_command.py

Modified: experiments/likun-bigtool/README
==============================================================================
--- experiments/likun-bigtool/README (original)
+++ experiments/likun-bigtool/README Sat Oct 24 12:37:08 2009
@@ -1,4 +1,8 @@
 1. Run the bigtool mock-up by input "python3 test_bigtool.py"
+
+
+TODO:
+    1. Add multilingual internationalization services.
 
 
 

Modified: experiments/likun-bigtool/lib/bigtool.py
==============================================================================
--- experiments/likun-bigtool/lib/bigtool.py (original)
+++ experiments/likun-bigtool/lib/bigtool.py Sat Oct 24 12:37:08 2009
@@ -1,67 +1,83 @@
 import sys
 import readline
+import collections
 from cmd import Cmd
 from lib.exception import *
 from lib.moduleinfo import ModuleInfo
 from lib.command import BigToolCmd
 
+CONST_BIGTOOL_HELP = """Bigtool, verstion 0.1
+usage: <module name> <command name> [param1 = value1 [, param2 = value2]]
+Type Tab character to get the hint of module/command/paramters.
+Type \"help(? h)\" for help on bigtool.
+Type \"<module_name> help\" for help on the specific module.
+Type \"<module_name> <command_name> help\" for help on the specific command.
+\nAvailable module names: """
+
 class BigTool(Cmd):
-    """simple bigtool command example."""
-    
-    doc_leader = ""
-    doc_header = "sub commands (type help <topic>):"
+    """simple bigtool command example."""    
 
     def __init__(self):
         Cmd.__init__(self)
         self.prompt = '> '
         self.ruler = '-'
-        self.modules = {}
-        self.complete_hint = []
-
-    def parse_cmd(self, line):
-        try:
-            cmd = BigToolCmd(line)
-            self._validate_cmd(cmd)
-            self._handle_cmd(cmd)
-        except BigToolException as e:
-            print(e)
-    
-
-    def _validate_cmd(self, cmd):
-        if not cmd.module_name in self.modules:
-            raise UnknownModule(cmd.module_name)
-        
-        module_info = self.modules[cmd.module_name]
-        if not module_info.has_command_with_name(cmd.command_name):
-            raise UnknownCmd(cmd.module_name, cmd.command_name)
-
-        command_info = module_info.get_command_with_name(cmd.command_name)
-        support_params = command_info.get_parameter_names()
-        if not cmd.parameters and support_params:
-            raise MissingParameter(cmd.module_name, cmd.command_name, support_params[0])
-        elif cmd.parameters and not support_params:
-            raise UnknownParameter(cmd.module_name, cmd.command_name, list(cmd.parameters.keys())[0])
-        elif cmd.parameters:
-            for param in cmd.parameters:
-                if not param in support_params:
-                    raise UnknownParameter(cmd.module_name, cmd.command_name, param)
-            for param in support_params:
-                if not param in cmd.parameters:
-                    raise MissingParameter(cmd.module_name, cmd.command_name, param)
-            
+        self.modules = collections.OrderedDict()
+        self.add_module_info(ModuleInfo("help", desc = "Get help for bigtool"))
+                    
+
+    def validate_cmd(self, cmd):
+        if not cmd.module in self.modules:
+            raise CmdUnknownModuleSyntaxError(cmd.module)
+        
+        module_info = self.modules[cmd.module]
+        if not module_info.has_command_with_name(cmd.command):
+            raise CmdUnknownCmdSyntaxError(cmd.module, cmd.command)
+
+        command_info = module_info.get_command_with_name(cmd.command)
+        manda_params = command_info.get_mandatory_param_names()
+        all_params = command_info.get_param_names()
+        if command_info.need_instance_param():
+            inst_name = module_info.get_instance_param_name()
+            if inst_name:
+                manda_params.append(inst_name)
+                all_params.append(inst_name)
+        
+        # If help is inputed, don't do further paramters validation.
+        for val in cmd.params.keys():
+            if val == "help":
+                return
+        
+        params = cmd.params.copy()       
+        if not params and manda_params:            
+            raise CmdMissParamSyntaxError(cmd.module, cmd.command, manda_params[0])            
+        elif params and not all_params:
+            raise CmdUnknownParamSyntaxError(cmd.module, cmd.command, 
+                                             list(params.keys())[0])
+        elif params:
+            for name in params:
+                if not name in all_params:
+                    raise CmdUnknownParamSyntaxError(cmd.module, cmd.command, name)
+            for name in manda_params:
+                if not name in params:
+                    raise CmdMissParamSyntaxError(cmd.module, cmd.command, name)
+                              
 
     def _handle_cmd(self, cmd):
         #to do, consist xml package and send to bind10
-        pass
-
-    def add_module_info(self, module_info):
-        if not isinstance(module_info, ModuleInfo):
-            raise UnknownModule(type(module_info))
+        if cmd.command == "help" or ("help" in cmd.params.keys()):
+            self._handle_help(cmd)
+        else:
+            self._temp_print_parse_result(cmd)
+
+    def add_module_info(self, module_info):        
         self.modules[module_info.name] = module_info
+        
+    def get_module_names(self):
+        return list(self.modules.keys())
 
     #override methods in cmd
-    def default(self, line):        
-        self.parse_cmd(line)
+    def default(self, line):
+        self._parse_cmd(line)
 
     def emptyline(self):
         pass
@@ -72,67 +88,146 @@
         except KeyboardInterrupt:
             return True
             
-    def do_help(self, module_name):
-        if module_name in self.modules.keys():
-            print(self.modules[module_name].desc)
-        else:
-            print("Unknow module")
+    def do_help(self, name):
+        print(CONST_BIGTOOL_HELP)
+        for k in self.modules.keys():
+            print("\t", self.modules[k])
+                
     
     def onecmd(self, line):
         if line == 'EOF'or line.lower() == "quit":
             return True
+            
+        if line == 'h':
+            line = 'help'
+        
         Cmd.onecmd(self, line)
                     
     def complete(self, text, state):
         if 0 == state:
-            self.complete_hint = []
-            current_input_line = readline.get_line_buffer()
+            text = text.strip()
+            hints = []
+            cur_line = readline.get_line_buffer()            
             try:
-                cmd = BigToolCmd(current_input_line)
-                if cmd.parameters:
-                    self.complete_hint = self._get_support_parameters_startswith_name(cmd.module_name, cmd.command_name, text)
-                else:
-                    self.complete_hint = self._get_support_commands_startswith_name(cmd.module_name, text)
+                cmd = BigToolCmd(cur_line)
+                if not cmd.params and text:
+                    hints = self._get_command_startswith(cmd.module, text)
+                else:                       
+                    hints = self._get_param_startswith(cmd.module, cmd.command,
+                                                       text)
+            except CmdModuleNameFormatError:
+                if not text:
+                    hints = list(self.modules.keys())
                     
-
-            except CmdWithoutModuleName:
-                self.complete_hint = list(self.modules.keys())
-
-            except CmdWithoutCommandName as e:
-                if e.module_name in self.modules and text == "":
-                    self.complete_hint = self.modules[e.module_name].get_command_names()
-                else:
-                    self.complete_hint = self._get_support_modules_startswith_name(text)
-
-            except CmdParameterFormatError as e:
-                self.complete_hint = self._get_support_parameters_startswith_name(e.module_name, e.command_name, text)
+            except CmdMissCommandNameFormatError as e:
+                if not text.strip(): # command name is empty
+                    hints = self.modules[e.module].get_command_names()                    
+                else: 
+                    hints = self._get_module_startswith(text)
+
+            except CmdCommandNameFormatError as e:
+                if e.module in self.modules:
+                    hints = self._get_command_startswith(e.module, text)
+
+            except CmdParamFormatError as e:
+                hints = self._get_param_startswith(e.module, e.command, text)
 
             except BigToolException:
-                self.complete_hint = []
-
-        if state < len(self.complete_hint):
-            return self.complete_hint[state]
+                hints = []
+            
+            self.hint = hints
+            self._append_space_to_hint()
+
+        if state < len(self.hint):
+            return self.hint[state]
         else:
             return None
-
-    def _get_support_modules_startswith_name(self, full_or_partial_module_name):
-        return [module_name for module_name in self.modules if module_name.startswith(full_or_partial_module_name)]
-
-
-    def _get_support_commands_startswith_name(self, module_name, full_or_partial_command_name):
-        if module_name in self.modules:
-            return [command_name 
-                    for command_name in self.modules[module_name].get_command_names() 
-                    if command_name.startswith(full_or_partial_command_name)]
+            
+
+    def _get_module_startswith(self, text):       
+        return [module
+                for module in self.modules 
+                if module.startswith(text)]
+
+
+    def _get_command_startswith(self, module, text):
+        if module in self.modules:            
+            return [command
+                    for command in self.modules[module].get_command_names() 
+                    if command.startswith(text)]
+        
+        return []                    
+                        
+
+    def _get_param_startswith(self, module, command, text):        
+        if module in self.modules:
+            module_info = self.modules[module]            
+            if command in module_info.get_command_names():                
+                cmd_info = module_info.get_command_with_name(command)
+                params = cmd_info.get_param_names() 
+                if cmd_info.need_instance_param():
+                    inst_name = module_info.get_instance_param_name()
+                    if inst_name:
+                        params.append(inst_name)
+                
+                hint = []
+                if text:    
+                    hint = [val for val in params if val.startswith(text)]
+                else:
+                    hint = list(params)
+                
+                if len(hint) == 1 and hint[0] != "help":
+                    hint[0] = hint[0] + " ="    
+                
+                return hint
+
+        return []
+        
+
+    def _parse_cmd(self, line):
+        try:
+            cmd = BigToolCmd(line)
+            self.validate_cmd(cmd)
+            self._handle_cmd(cmd)
+        except BigToolException as e:
+            print("Error! ", e)
+            self._print_correct_usage(e)
+            
+            
+    def _print_correct_usage(self, ept):        
+        if isinstance(ept, CmdUnknownModuleSyntaxError):
+            self.do_help(None)
+            
+        elif isinstance(ept, CmdUnknownCmdSyntaxError):
+            self.modules[ept.module].module_help()
+            
+        elif isinstance(ept, CmdMissParamSyntaxError) or \
+             isinstance(ept, CmdUnknownParamSyntaxError):
+             self.modules[ept.module].command_help(ept.command)
+                 
+    
+    def _temp_print_parse_result(self, cmd):
+        print("command line is parsed:\nmodule_name: %s\ncommand_name: %s\n"\
+              "paramters:" % (cmd.module, cmd.command))
+              
+        for name in cmd.params.keys():            
+            print("\t%s \t%s" % (name, cmd.params[name]))
+            
+                
+    def _append_space_to_hint(self):
+        """Append one space at the end of complete hint."""
+        
+        self.hint = [(val + " ") for val in self.hint]
+            
+            
+    def _handle_help(self, cmd):
+        if cmd.command == "help":
+            self.modules[cmd.module].module_help()
         else:
-            return []
-
-    def _get_support_parameters_startswith_name(self, module_name, command_name, full_or_partial_parameter_name):
-        if module_name in self.modules:
-            if command_name in self.modules[module_name].get_command_names():
-                command_info = self.modules[module_name].get_command_with_name(command_name)
-                return [param for param in command_info.get_parameter_names() if param.startswith(full_or_partial_parameter_name)]
-        return []
-
-
-                
+            self.modules[cmd.module].command_help(cmd.command)
+            
+            
+        
+            
+            
+            

Modified: experiments/likun-bigtool/lib/command.py
==============================================================================
--- experiments/likun-bigtool/lib/command.py (original)
+++ experiments/likun-bigtool/lib/command.py Sat Oct 24 12:37:08 2009
@@ -1,51 +1,98 @@
 import re
+import collections
 from lib.exception import *
 
-CMD_WITH_PARAMETER_PATTERN = re.compile("^\s*([\d\w_]*)\s*([\d\w_]*)\s*,(.*)$")
-CMD_WITHOUT_PARAMETER_PATTERN = re.compile("^\s*([\d\w_]*)\s*([\d\w_]*)\s*$")
-PARAMETER_PATTERN = re.compile("^\s*([\d\w_\"\']+)\s*=\s*([\d\w_\.\"\']+)\s*$")
 
-   
+param_name_str = "^\s*(?P<param_name>[\w]+)\s*=\s*"
+param_value_str = "(?P<param_value>[\w\.]+)"
+param_value_with_quota_str = "[\"\'](?P<param_value>[\w\., ]+)[\"\']"
+next_params_str = "(?P<blank>\s*)(?P<comma>,?)(?P<next_params>.*)$"
+
+PARAM_WITH_QUOTA_PATTERN = re.compile(param_name_str + 
+                                      param_value_with_quota_str +
+                                      next_params_str)
+PARAM_PATTERN = re.compile(param_name_str + param_value_str + next_params_str)
+                           
+# Used for module and command name
+MODULE_CMD_NAME_PATTERN = re.compile("^\s*(?P<name>[\w]+)(?P<blank>\s*)(?P<others>.*)$")
+
 class BigToolCmd:
     """ This class will parse the command line usr input into three part
     module name, cmmand, parameters
-    the first two parts are strings and parameter is one hash and parameter part is optional
-    example: zone reload, zone_name=example.com 
-    module_name == zone
-    command_name == reload
-    parameters == {'zone_name' = 'example.com'}
+    the first two parts are strings and parameter is one hash, 
+    parameter part is optional
+    
+    Example: zone reload, zone_name=example.com 
+    module == zone
+    command == reload
+    params == [zone_name = 'example.com']
     """
+    
     def __init__(self, cmd):
+        self.params = collections.OrderedDict()
+        self.module = ''
+        self.command = ''
         self._parse_cmd(cmd)
 
-    def _parse_cmd(self, cmd):    
-        cmd_with_parameter = cmd.find(",") != -1
-        cmd_group = (cmd_with_parameter and CMD_WITH_PARAMETER_PATTERN or CMD_WITHOUT_PARAMETER_PATTERN).match(cmd)
-        if not cmd_group: 
-            raise CmdFormatError
+    def _parse_cmd(self, text_str):    
+        # Get module name
+        groups = MODULE_CMD_NAME_PATTERN.match(text_str)
+        if not groups:
+            raise CmdModuleNameFormatError
+        
+        self.module = groups.group('name')
+        cmd_str = groups.group('others')
+        if cmd_str:
+            if not groups.group('blank'):
+                raise CmdModuleNameFormatError
+        else:            
+            raise CmdMissCommandNameFormatError(self.module)
+            
+        # Get command name
+        groups = MODULE_CMD_NAME_PATTERN.match(cmd_str)
+        if (not groups):
+            raise CmdCommandNameFormatError(self.module)
+        
+        self.command = groups.group('name')
+        param_str = groups.group('others')
+        if param_str:
+            if not groups.group('blank'):
+                raise CmdCommandNameFormatError(self.module)
 
-        if not cmd_group.group(1):
-            raise CmdWithoutModuleName
-        self.module_name = cmd_group.group(1)
+            self._parse_params(param_str)
 
-        if not cmd_group.group(2):
-            raise CmdWithoutCommandName(cmd_group.group(1))
-        self.command_name = cmd_group.group(2)
 
-        self.parameters = None
-        if cmd_with_parameter:
-            self._parse_parameters(cmd_group.group(3))
+    def _parse_params(self, param_text):
+        """convert a=b,c=d into one hash """
+        
+        # Check parameter name "help"
+        param = MODULE_CMD_NAME_PATTERN.match(param_text)
+        if param and param.group('name') == "help":
+            self.params["help"] = "help"
+            return
+        
+        while True:
+            if not param_text.strip():
+                break
+                
+            groups = PARAM_PATTERN.match(param_text) or \
+                     PARAM_WITH_QUOTA_PATTERN.match(param_text)
+            
+            if not groups:                
+                raise CmdParamFormatError(self.module, self.command)
+            else:
+                self.params[groups.group('param_name')] = groups.group('param_value')                
+                param_text = groups.group('next_params')
+                if not param_text or (not param_text.strip()):
+                    break
 
-    def _parse_parameters(self, parameters):
-        """convert a=b,c=d into one hash """
-        key_value_pairs = parameters.split(",")
-        if len(key_value_pairs) == 0:
-            raise CmdParameterFormatError(self.module_name, self.command_name, "empty parameters")
+                if not groups.group('blank') and \
+                   not groups.group('comma'):
+                    raise CmdParamFormatError(self.module, self.command)
+                    
+                
+            
+            
+            
+    
 
-        self.parameters = {}
-        for kv in key_value_pairs:
-            key_value = PARAMETER_PATTERN.match(kv)
-            if not key_value or not key_value.group(1) or not key_value.group(2):
-                raise CmdParameterFormatError(self.module_name, self.command_name, "parameter format should looks like (key = value)")
-            self.parameters[key_value.group(1)] = key_value.group(2)
-

Modified: experiments/likun-bigtool/lib/exception.py
==============================================================================
--- experiments/likun-bigtool/lib/exception.py (original)
+++ experiments/likun-bigtool/lib/exception.py Sat Oct 24 12:37:08 2009
@@ -2,82 +2,102 @@
     """Abstract base class shared by all bigtool exceptions"""
     def __str__(self):
         return "Big tool has problem"
-    pass
 
+# Begin define Format exception
 
 class CmdFormatError(BigToolException):
     """Command is malformed"""
     def __str__(self):
         return "Command is malformed"
 
-class CmdWithoutModuleName(CmdFormatError):
-    """Command is malformed which doesn't have module name"""
-    def __str__(self):
-        return "Command doesn't have module name"
-
-class CmdWithoutCommandName(CmdFormatError):
-    """Command is malformed which donesn't have command name"""
-    def __init__(self, module_name):
-        super(CmdWithoutCommandName, self).__init__(self)
-        self.module_name = module_name
+        
+class CmdModuleNameFormatError(CmdFormatError):
+    """module name format error"""
 
     def __str__(self):
-        return "No command name is speicfied for module "\
-                + "\"" + self.module_name + "\""
+        return "Module name format error: the charater of name can only be '0-9a-zA-Z_'" 
+                      
+                
+class CmdCommandNameFormatError(CmdFormatError):
+    """command name format error"""
+    
+    def __init__(self, module):
+        self.module = module        
+        
+    def __str__(self):
+        return "Command name format error: the charater of name can only be '0-9a-zA-Z_'"      
+        
+        
+class CmdMissCommandNameFormatError(CmdFormatError):
+    """Module name isn't finished"""
+    
+    def __init__(self, module):
+        self.module = module
+        
+    def __str__(self):
+        return "command name is missed"   
 
-class CmdParameterFormatError(CmdFormatError):
+
+class CmdParamFormatError(CmdFormatError):
     """Command is malformed which parameter isn't key value pair"""
-    def __init__(self, module_name, command_name, error_reason):
-        super(CmdParameterFormatError, self).__init__(self)
-        self.module_name = module_name
-        self.command_name = command_name
-        self.error_reason = error_reason
+    
+    def __init__(self, module, command):        
+        self.module = module
+        self.command = command        
 
     def __str__(self):
-        return "Parameter belongs to command " + "\"" + self.command_name + "\""\
-                + " in module " + "\"" + self.module_name + "\""\
-                + " has error : " + "\"" + self.error_reason + "\""
+        return  "Parameter format error, it should like 'key = value'"         
+        
+# Begin define the exception for syntax
 
-class UnknownModule(BigToolException):
+class CmdSyntaxError(BigToolException):
+    """Command line has syntax error"""
+    
+    def __str__(self):
+        return "Command line has syntax error"
+
+
+class CmdUnknownModuleSyntaxError(CmdSyntaxError):
     """Command is unknown"""
-    def __init__(self, module_name):
-        self.module_name = module_name
+    def __init__(self, module):
+        self.module = module
 
     def __str__(self):
-        return "Module " + "\"" + self.module_name + "\"" + " is unknown"
+        return str("Unknown module '%s'" % self.module)
+        
 
-class UnknownCmd(BigToolException):
+class CmdUnknownCmdSyntaxError(CmdSyntaxError):
     """Command is unknown"""
-    def __init__(self, module_name, command_name):
-        self.module_name = module_name
-        self.command_name = command_name
+    def __init__(self, module, command):
+        self.module = module
+        self.command = command
 
     def __str__(self):
-        return "Module " + "\"" + self.module_name + "\""\
-                + " doesn't has command " + "\"" + self.command_name + "\""
+        return str("Unknown command '%s' to module '%s'" % 
+                    (self.command, self.module))
+                    
 
-class UnknownParameter(BigToolException):
+class CmdUnknownParamSyntaxError(CmdSyntaxError):
     """The parameter of command is unknown"""
-    def __init__(self, module_name, command_name, parameter_name):
-        self.module_name = module_name
-        self.command_name = command_name
-        self.parameter_name = parameter_name
+    def __init__(self, module, command, param):
+        self.module = module
+        self.command = command
+        self.param = param
 
     def __str__(self):
-        return "Command " + "\"" + self.command_name + "\""\
-                + " in module " + "\"" + self.module_name + "\"" \
-                + " doesn't has parameter " + "\"" + self.parameter_name + "\""
+        return str("Unknown parameter '%s' to command '%s' of module '%s'" %
+                   (self.param, self.command, self.module))
+                   
 
-
-class MissingParameter(BigToolException):
+class CmdMissParamSyntaxError(CmdSyntaxError):
     """The parameter of one command is missed"""
-    def __init__(self, module_name, command_name, parameter_name):
-        self.module_name = module_name
-        self.command_name = command_name
-        self.parameter_name = parameter_name
+    def __init__(self, module, command, param):
+        self.module = module
+        self.command = command
+        self.param = param
 
     def __str__(self):
-        return "Command " + "\"" + self.command_name + "\"" + \
-               " in module " + "\"" + self.module_name + "\"" + \
-               " is missing parameter " + "\"" + self.parameter_name + "\""
-
+        return str("Parameter '%s' is missed for command '%s' of moudule '%s'" % 
+                   (self.param, self.command, self.module))
+                   
+   

Modified: experiments/likun-bigtool/lib/moduleinfo.py
==============================================================================
--- experiments/likun-bigtool/lib/moduleinfo.py (original)
+++ experiments/likun-bigtool/lib/moduleinfo.py Sat Oct 24 12:37:08 2009
@@ -1,67 +1,167 @@
+import collections
+
+# Define value type
+STRING_TYPE = "string"
+LIST_TYPE = "list"
+INT_TYPE = "int"
+
 class ParamInfo:
     """The parameter of one command
     each command parameter have four attributes, 
     parameter name, parameter type, parameter value, and parameter description
     """
-    def __init__(self, name, type, value, desc):
+    def __init__(self, name, desc = '', type = STRING_TYPE, 
+                 optional = False, value = ''):
         self.name = name
         self.type = type
-        self.value = value
+        self.value = value #Save parameter's value
         self.desc = desc
+        self.optional = optional
+        
+    def is_optional(self):
+        return self.optional        
+    
+    def __str__(self):        
+        return str("\t%s <type: %s> \t(%s)" % (self.name, self.type, self.desc))
+        
 
 class CommandInfo:
-    """One command which provide by one bind10 module, it has zero or more parameters"""
+    """One command which provide by one bind10 module, it has zero or 
+    more parameters
+    """
 
-    def __init__(self, name, desc):
+    def __init__(self, name, desc = "", need_inst_param = True):
         self.name = name
+        # Wether command needs parameter "instance_name" 
+        self.need_inst_param = need_inst_param 
         self.desc = desc
-        self.params = {}
+        self.params = collections.OrderedDict()        
+        # Set default parameter "help"
+        self.add_param(ParamInfo("help", 
+                                  desc = "Get help for command",
+                                  optional = True))
+                
+    def __str__(self):
+        return str("%s \t(%s)" % (self.name, self.desc))
+        
 
-    def add_parameter(self, paraminfo):
-        if not isinstance(paraminfo, ParamInfo):
-            raise UnknowParamType
+    def add_param(self, paraminfo):
+        self.params[paraminfo.name] = paraminfo
+        
 
-        self.params[paraminfo.name] = paraminfo
+    def has_param_with_name(self, param_name):
+        return param_name in self.params
+        
 
-    def has_parameter_with_name(self, param_name):
-        return param_name in self.params
+    def get_param_with_name(self, param_name):
+        return self.params[param_name]
+        
 
-    def get_parameter_with_name(self, param_name):
-        return self.params[param_name]
+    def get_params(self):
+        return list(self.params.values())
+        
 
-    def get_parameters(self):
-        return list(self.params.values())
+    def get_param_names(self):
+        return list(self.params.keys())
+        
+        
+    def get_mandatory_param_names(self):
+        all_names = self.params.keys()
+        return [name for name in all_names 
+                if not self.params[name].is_optional()]        
+        
+        
+    def need_instance_param(self):
+        return self.need_inst_param
+        
 
-    def get_parameter_names(self):
-        return list(self.params.keys())
-
- 
+    def command_help(self, inst_name, inst_type, inst_desc):
+        print("Command ", self)
+        print("\t\thelp (Get help for command)")
+                
+        params = self.params.copy()
+        del params["help"]
+        if self.need_inst_param:
+            params[inst_name] = ParamInfo(name = inst_name, type = inst_type,
+                                          desc = inst_desc)        
+        if len(params) == 0:
+            print("\tNo parameters for the command")
+            return
+        
+        print("\n\tMandatory parameters:")
+        find_optional = False
+        for info in params.values():            
+            if not info.is_optional():
+                print("\t", info)
+            else:
+                find_optional = True
+                              
+        if find_optional:
+            print("\n\tOptional parameters:")            
+            for info in params.values():
+                if info.is_optional():
+                    print("\t", info)
 
 
 class ModuleInfo:
     """Define the information of one module, include module name, 
-    module supporting commands
+    module supporting commands, instance name and the value type of instance name
     """    
     
-    def __init__(self, name, desc):
+    def __init__(self, name, inst_name = "", inst_type = STRING_TYPE, 
+                 inst_desc = "", desc = ""):
         self.name = name
+        self.inst_name = inst_name
+        self.inst_type = inst_type
+        self.inst_desc = inst_desc
         self.desc = desc
-        self.commands = {}
+        self.commands = collections.OrderedDict()         
+        # Add defaut help command
+        self.add_command(CommandInfo(name = "help", 
+                                     desc = "Get help for module",
+                                     need_inst_param = False))
         
-    def add_command(self, commandInfo):
-        if not isinstance(commandInfo, CommandInfo):
-            raise UnknownCmdType
+    def __str__(self):
+        return str("%s \t%s" % (self.name, self.desc))
+        
+    def add_command(self, commandInfo):        
         self.commands[commandInfo.name] = commandInfo
+        
         
     def has_command_with_name(self, command_name):
         return command_name in self.commands
+        
 
     def get_command_with_name(self, command_name):
         return self.commands[command_name]
         
+        
     def get_commands(self):
         return list(self.commands.values())
+        
     
     def get_command_names(self):
         return list(self.commands.keys())
         
+    
+    def get_instance_param_name(self):
+        return self.inst_name
+        
+        
+    def get_instance_param_type(self):
+        return self.inst_type
+        
+
+    def module_help(self):
+        print("Module ", self, "\nAvailable commands:")
+        for k in self.commands.keys():
+            print("\t", self.commands[k])
+            
+            
+    def command_help(self, command):
+        self.commands[command].command_help(self.inst_name, 
+                                            self.inst_type,
+                                            self.inst_desc)
+        
+            
+        

Modified: experiments/likun-bigtool/test_bigtool.py
==============================================================================
--- experiments/likun-bigtool/test_bigtool.py (original)
+++ experiments/likun-bigtool/test_bigtool.py Sat Oct 24 12:37:08 2009
@@ -1,23 +1,34 @@
 from lib import *
+from lib.moduleinfo import *
 
 def _prepare_fake_data(bigtool):
     #module zone, has two command : 
     #   zone load, zone_name = "" 
-    #   zone set, zone_name = "", attr_name = "", attr_value = ""
-    zone_name_param = moduleinfo.ParamInfo("zone_name", "string", "", "specify the zone name")
-    zone_file_param = moduleinfo.ParamInfo("zone_file", "string", "", "specify the data source")
-    load_cmd = moduleinfo.CommandInfo("load", "load one zone")
-    load_cmd.add_parameter(zone_name_param)
-    load_cmd.add_parameter(zone_file_param)
+    #   zone set, zone_name = "", master = "", allow_update = ""    
+    zone_file_param = ParamInfo(name = "zone_file", 
+                                desc = "specify the data source")
+    load_cmd = CommandInfo(name = "load", desc = "load one zone")
+    load_cmd.add_param(zone_file_param)
 
-    attr_name_param = moduleinfo.ParamInfo("attr_name", "string", "", "specify attribute name")
-    attr_value_param = moduleinfo.ParamInfo("attr_value", "string", "", "specify attribute value")
-    set_cmd = moduleinfo.CommandInfo("set", "set the master of one zone")
-    set_cmd.add_parameter(attr_name_param)
-    set_cmd.add_parameter(attr_value_param)
-    set_cmd.add_parameter(zone_name_param)
-        
-    zone_module = moduleinfo.ModuleInfo("zone", "manage all the zones")
+    set_param_master = ParamInfo(name = "master", 
+                                 desc = "mater of the server", 
+                                 optional = True)
+                                 
+    set_param_allow_update = ParamInfo(name = "allow_update", 
+                                       desc = "The addresses allowed to update ",
+                                       type = LIST_TYPE,
+                                       optional = True)
+                                       
+    set_cmd = CommandInfo(name = "set", desc = "set attributes of one zone")
+    set_cmd.add_param(set_param_master)
+    set_cmd.add_param(set_param_allow_update)
+
+    zone_module = ModuleInfo(name = "zone", 
+                             inst_name = "zone_name", 
+                             inst_type = STRING_TYPE, 
+                             inst_desc = "the name of one zone",
+                             desc = "manage all the zones")
+
     zone_module.add_command(load_cmd)
     zone_module.add_command(set_cmd)
     bigtool.add_module_info(zone_module)
@@ -25,22 +36,33 @@
     #module log, has two command
     #log change_level, module_name = "", level = ""
     #log close
-    name_param = moduleinfo.ParamInfo("module_name", "string", "", "module name")
-    level_param = moduleinfo.ParamInfo("level", "int", "", "module's new log level")
-    change_level_cmd = moduleinfo.CommandInfo("change_level", "change module's log level")
-    change_level_cmd.add_parameter(name_param)
-    change_level_cmd.add_parameter(level_param)
+    level_param = ParamInfo(name = "level", 
+                            desc = "module's new log level", 
+                            type = INT_TYPE)
+    change_level_cmd = CommandInfo(name = "change_level", 
+                                   desc = "change module's log level")
+    change_level_cmd.add_param(level_param)
 
-    log_close_cmd = moduleinfo.CommandInfo("close", "close log system")
-    log_module = moduleinfo.ModuleInfo("log", "manage log system")
+    log_close_cmd = CommandInfo(name = "close", 
+                                desc = "close log system")
+                                
+    log_module = ModuleInfo(name = "log", 
+                            inst_name = "log_module",                             
+                            inst_desc = "log module's name" ,
+                            desc = "manage log system")
+                            
     log_module.add_command(change_level_cmd)
     log_module.add_command(log_close_cmd)
     bigtool.add_module_info(log_module)
     
-    #module config, has one command
+    #module config, has one command "reload", and the command has no parameters
     #config reload
-    config_module = moduleinfo.ModuleInfo("config", "config manager")
-    reload_cmd = moduleinfo.CommandInfo("reload", "reload configuration")
+    reload_cmd = CommandInfo(name = "reload", 
+                             desc = "reload configuration", 
+                             need_inst_param = False)
+
+    config_module = ModuleInfo(name = "config", 
+                               desc = "config manager")    
     config_module.add_command(reload_cmd)
     bigtool.add_module_info(config_module)
     

Modified: experiments/likun-bigtool/test_command.py
==============================================================================
--- experiments/likun-bigtool/test_command.py (original)
+++ experiments/likun-bigtool/test_command.py Sat Oct 24 12:37:08 2009
@@ -1,37 +1,188 @@
 import unittest
 from lib import command
+from lib import bigtool
 from lib import exception
 
-class TestCommand(unittest.TestCase):
+from lib.moduleinfo import *
+from lib.exception import *
+    
+
+class TestBigToolCmd(unittest.TestCase):
+    
+    def my_assert_raise(self, exception_type, cmd_line):
+        self.assertRaises(exception_type, command.BigToolCmd, cmd_line)
+
 
     def testCommandWithoutParameter(self):
         cmd = command.BigToolCmd("zone add")
-        assert cmd.module_name == "zone"
-        assert cmd.command_name == "add"
-        assert cmd.parameters == None
+        assert cmd.module == "zone"
+        assert cmd.command == "add"
+        self.assertEqual(len(cmd.params), 0)
+        
+    
+    def testCommandWithParameters(self):
+        lines = {"zone add zone_name = cnnic.cn, file = cnnic.cn.file master=1.1.1.1",
+                 "zone add zone_name = \"cnnic.cn\", file ='cnnic.cn.file' master=1.1.1.1  ",
+                 "zone add zone_name = 'cnnic.cn\", file ='cnnic.cn.file' master=1.1.1.1, " }
+        
+        for cmd_line in lines:
+            cmd = command.BigToolCmd(cmd_line)
+            assert cmd.module == "zone"
+            assert cmd.command == "add"
+            assert cmd.params["zone_name"] == "cnnic.cn"
+            assert cmd.params["file"] == "cnnic.cn.file"
+            assert cmd.params["master"] == '1.1.1.1'
+            
+            
+    def testCommandWithListParam(self):
+            cmd = command.BigToolCmd("zone set zone_name='cnnic.cn', master='1.1.1.1, 2.2.2.2'")
+            assert cmd.params["master"] == '1.1.1.1, 2.2.2.2'            
+        
+        
+    def testCommandWithHelpParam(self):
+        cmd = command.BigToolCmd("zone add help")
+        assert cmd.params["help"] == "help"
+        
+        cmd = command.BigToolCmd("zone add help *&)&)*&&$#$^%")
+        assert cmd.params["help"] == "help"
+        self.assertEqual(len(cmd.params), 1)
+        
 
-    def testCommandWithParameters(self):
-        cmd = command.BigToolCmd("zone add, zone_name = example.com, file = db.example.com.info")
-        assert cmd.module_name == "zone"
-        assert cmd.command_name == "add"
-        assert cmd.parameters["zone_name"] == "example.com"
-        assert cmd.parameters["file"] == "db.example.com.info"
+    def testCmdModuleNameFormatError(self):
+        self.my_assert_raise(CmdModuleNameFormatError, "zone=good")
+        self.my_assert_raise(CmdModuleNameFormatError, "zo/ne")        
+        self.my_assert_raise(CmdModuleNameFormatError, "")        
+        self.my_assert_raise(CmdModuleNameFormatError, "=zone")
+        self.my_assert_raise(CmdModuleNameFormatError, "zone,")        
+        
+        
+    def testCmdMissCommandNameFormatError(self):
+        self.my_assert_raise(CmdMissCommandNameFormatError, "zone")
+        self.my_assert_raise(CmdMissCommandNameFormatError, "zone ")
+        self.my_assert_raise(CmdMissCommandNameFormatError, "help ")
+        
+             
+    def testCmdCommandNameFormatError(self):
+        self.my_assert_raise(CmdCommandNameFormatError, "zone =d")
+        self.my_assert_raise(CmdCommandNameFormatError, "zone z=d")
+        self.my_assert_raise(CmdCommandNameFormatError, "zone z-d ")
+        self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/")
+        self.my_assert_raise(CmdCommandNameFormatError, "zone zdd/ \"")
+        
+
+    def testCmdParamFormatError(self): 
+        self.my_assert_raise(CmdParamFormatError, "zone load load")
+        self.my_assert_raise(CmdParamFormatError, "zone load load=")
+        self.my_assert_raise(CmdParamFormatError, "zone load load==dd")
+        self.my_assert_raise(CmdParamFormatError, "zone load , zone_name=dd zone_file=d" )
+        self.my_assert_raise(CmdParamFormatError, "zone load zone_name=dd zone_file" )
+        self.my_assert_raise(CmdParamFormatError, "zone zdd \"")
+        
+
+class TestValidateCmd(unittest.TestCase):
     
-    def testCommandWithFormatError(self):
-        self.assertRaises(exception.CmdFormatError, command.BigToolCmd, "zone=good")
-        self.assertRaises(exception.CmdFormatError, command.BigToolCmd, "zo/ne")
-        self.assertRaises(exception.CmdWithoutModuleName, command.BigToolCmd, "")
-
-        self.assertRaises(exception.CmdWithoutCommandName, command.BigToolCmd, "zone")
-        self.assertRaises(exception.CmdFormatError, command.BigToolCmd, "zone i-s")
-        self.assertRaises(exception.CmdFormatError, command.BigToolCmd, "zone i=good")
-
-
-        self.assertRaises(exception.CmdFormatError, command.BigToolCmd, "zone load load")
-        self.assertRaises(exception.CmdFormatError, command.BigToolCmd, "zone file=db.exmaple.info,load")
-        self.assertRaises(exception.CmdFormatError, command.BigToolCmd, "zone file=db.exmaple.info load")
-
-        self.assertRaises(exception.CmdParameterFormatError, command.BigToolCmd, "zone load, file=db.exmaple.info load")
-
+    def _create_bigtool(self):
+        """Create one bigtool"""
+        
+        tool = bigtool.BigTool()        
+        zone_file_param = ParamInfo(name = "zone_file")
+        load_cmd = CommandInfo(name = "load")
+        load_cmd.add_param(zone_file_param)
+        
+        param_master = ParamInfo(name = "master", optional = True)                                 
+        param_allow_update = ParamInfo(name = "allow_update", optional = True)                                           
+        set_cmd = CommandInfo(name = "set")
+        set_cmd.add_param(param_master)
+        set_cmd.add_param(param_allow_update)
+        
+        reload_all_cmd = CommandInfo(name = "reload_all", need_inst_param = False)        
+        
+        zone_module = ModuleInfo(name = "zone", inst_name = "zone_name")                             
+        zone_module.add_command(load_cmd)
+        zone_module.add_command(set_cmd)
+        zone_module.add_command(reload_all_cmd)
+        
+        tool.add_module_info(zone_module)
+        return tool
+        
+        
+    def setUp(self):
+        self.bigtool = self._create_bigtool()
+        
+        
+    def no_assert_raise(self, cmd_line):
+        cmd = command.BigToolCmd(cmd_line)
+        self.bigtool.validate_cmd(cmd) 
+        
+        
+    def my_assert_raise(self, exception_type, cmd_line):
+        cmd = command.BigToolCmd(cmd_line)
+        self.assertRaises(exception_type, self.bigtool.validate_cmd, cmd)  
+        
+        
+    def testValidateSuccess(self):
+        self.no_assert_raise("zone load zone_file='cn' zone_name='cn'")
+        self.no_assert_raise("zone load zone_file='cn', zone_name='cn', ")
+        self.no_assert_raise("zone help ")
+        self.no_assert_raise("zone load help ")
+        self.no_assert_raise("zone help help='dd' ")
+        self.no_assert_raise("zone set allow_update='1.1.1.1' zone_name='cn'")
+        self.no_assert_raise("zone set zone_name='cn'")
+        self.no_assert_raise("zone reload_all")        
+        
+    
+    def testCmdUnknownModuleSyntaxError(self):
+        self.my_assert_raise(CmdUnknownModuleSyntaxError, "zoned d")
+        self.my_assert_raise(CmdUnknownModuleSyntaxError, "dd dd  ")
+        
+              
+    def testCmdUnknownCmdSyntaxError(self):
+        self.my_assert_raise(CmdUnknownCmdSyntaxError, "zone dd")
+        
+    def testCmdMissParamSyntaxError(self):
+        self.my_assert_raise(CmdMissParamSyntaxError, "zone load zone_file='cn'")
+        self.my_assert_raise(CmdMissParamSyntaxError, "zone load zone_name='cn'")
+        self.my_assert_raise(CmdMissParamSyntaxError, "zone set allow_update='1.1.1.1'")
+        self.my_assert_raise(CmdMissParamSyntaxError, "zone set ")
+        
+    def testCmdUnknownParamSyntaxError(self):
+        self.my_assert_raise(CmdUnknownParamSyntaxError, "zone load zone_d='cn'")
+        self.my_assert_raise(CmdUnknownParamSyntaxError, "zone reload_all zone_name = 'cn'")  
+        
+    
+class TestNameSequence(unittest.TestCase):
+    """
+    Test if the module/command/parameters is saved in the order creation
+    """
+    
+    def _create_bigtool(self):
+        """Create one bigtool"""     
+        
+        self._cmd = CommandInfo(name = "load")
+        self.module = ModuleInfo(name = "zone")
+        self.tool = bigtool.BigTool()        
+        for random_str in self.random_names:
+            self._cmd.add_param(ParamInfo(name = random_str))
+            self.module.add_command(CommandInfo(name = random_str))
+            self.tool.add_module_info(ModuleInfo(name = random_str))  
+        
+    def setUp(self):
+        self.random_names = ['1erdfeDDWsd', '3fe', '2009erd', 'Fe231', 'tere142', 'rei8WD']
+        self._create_bigtool()
+        
+    def testSequence(self):        
+        param_names = self._cmd.get_param_names()
+        cmd_names = self.module.get_command_names()
+        module_names = self.tool.get_module_names()
+        
+        i = 0
+        while i < len(self.random_names):
+            assert self.random_names[i] == param_names[i+1]
+            assert self.random_names[i] == cmd_names[i+1]
+            assert self.random_names[i] == module_names[i+1]
+            i = i + 1
+        
+    
 if __name__== "__main__":
     unittest.main()
+    




More information about the bind10-changes mailing list