Exemplo n.º 1
0
    def __init__(self, new_base_commands, options):
        """Constructor

        new_base_commands  Additions to the base commands        
        options[in]        Options for the class member variables
        """
        self.options = options
        self.tab_count = 0
        self.base_commands = []
        self.base_commands.extend(new_base_commands)
        self.base_commands.extend(_BASE_COMMANDS)
        self.type_complete_mode = _COMMAND_COMPLETE 
        self.cmd_line = _Command(self.options.get('prompt', '> '))
        self.width = self.options.get('width', 80)
        self.commands = self.options.get("commands", None)
        self.custom_commands = self.options.get("custom", False)
        self.quiet = self.options.get("quiet", False)
        self.variables = Variables(options)
        self.history = _CommandHistory({'max_size' : 20})
        var_list = self.options.get('variables', [])
        for var in var_list:
            self.variables.add_variable(var['name'], var['value'])
Exemplo n.º 2
0
class Console(object):
    """Console class
    """
    def __init__(self, new_base_commands, options):
        """Constructor

        new_base_commands  Additions to the base commands
        options[in]        Options for the class member variables
        """
        self.options = options
        self.tab_count = 0
        self.base_commands = []
        self.base_commands.extend(new_base_commands)
        self.base_commands.extend(_BASE_COMMANDS)
        self.type_complete_mode = _COMMAND_COMPLETE
        self.cmd_line = _Command(self.options.get('prompt', '> '))
        self.width = self.options.get('width', 80)
        self.commands = self.options.get("commands", None)
        self.custom_commands = self.options.get("custom", False)
        self.quiet = self.options.get("quiet", False)
        self.variables = Variables(options)
        self.history = _CommandHistory({'max_size': 20})
        self.position = 0
        self.errors = []
        var_list = self.options.get('variables', [])
        for var in var_list:
            self.variables.add_variable(var['name'], var['value'])

    def show_errors(self):
        """Show errors

        Displays the errors captured when executing an utility.
        """
        if self.quiet:
            return
        if not self.errors:
            print
            print("No errors to display.\n")
        for error in self.errors:
            print
            print("{0}\n".format(error))

    def clear_errors(self):
        """Clear errors

        Clears captured errors occurring while executing an utility.
        """
        if self.quiet:
            return
        self.errors = []
        print

    def show_last_error(self):
        """Show errors

        Displays the last error occurred when executing an utility.
        """
        if self.quiet:
            return
        if not self.errors:
            print
            print("No error to display.\n")
        else:
            print
            print("{0}\n".format(self.errors[-1]))

    def show_custom_command_help(self, arg):
        """Display the help for a custom command.

        Note: Override this method for help on custom commands.

        arg[in]            Help command argument
        """
        if self.quiet:
            return
        print "\nNo commands like '%s' exist.\n" % arg

    def do_custom_tab(self, prefix):
        """Do custom tab key processing

        Note: Override this method for tab completion for custom commands.

        prefix[in]        Prefix of the custom command
        """
        pass

    def do_custom_option_tab(self, prefix):
        """Do custom command option tab key processing

        Note: Override this method for tab completion for options for custom
        commands.

        prefix[in]        Prefix of the custom command
        """
        if self.quiet:
            return
        print "\n\nNo custom commands found.\n"

    @staticmethod
    def is_valid_custom_command(command_text):
        """Is command a valid custom command?

        This method evaluates the custom command for validity.

        Note: Override this command to determine if command_text is a valid
        custom command.

        command_text[in]   The complete command as entered by user

        Returns bool - True if valid, False if not recognized
        """
        return False  # return False by default if method not overridden

    def execute_custom_command(self, command, parameters):
        """Execute a custom command.
        Note: Override this method to execute a custom command.
        """
        pass

    def show_custom_options(self):
        """Show custom options

        Note: Override this for 'show options' functionality.
        """
        if self.quiet:
            return

    def do_option_tab(self, prefix):
        """Do tab completion for options

        This method will search for an option using the prefix passed. It
        first searches the console commands defined at instantiation (the
        general commands for the shell) and if not found, checks the
        options for a custom command.

        prefix[in]        Prefix of the option
        """
        full_command = self.cmd_line.get_command()
        matches = self.get_commands(full_command.strip(' '))
        if len(matches) > 0:
            self.do_base_command_tab(full_command, matches)
        elif self.custom_commands:
            # if prefix is 'help', try command complete for custom commands
            if full_command[0:4].lower() == 'help':
                self.do_custom_tab(prefix)
            else:
                self.do_custom_option_tab(prefix)

    def _set_complete_mode(self):
        """Set the tab completion mode

        If the command buffer is only 1 part (command and no options),
        we are in _COMMAND_COMPLETE mode.

        Else if the nearest option contains a $ at the start, we are in
        _VARIABLE_COMPLETE mode.

        Else we are in _OPTION_COMPLETE mode.

        _COMMAND_COMPLETE = tab complete for base and custom commands
        _VARIABLE_COMPLETE = tab complete for user-defined variables
        _OPTION_COMPLETE = tab complete for base or custom command options
        """
        buf = self.cmd_line.get_command()
        parts = buf.split(' ')
        segment = ''
        if (len(buf) > 0 and len(parts) == 1):
            self.type_complete_mode = _COMMAND_COMPLETE
        else:
            segment = self.cmd_line.get_nearest_option()
            if segment.find('$') > 0:
                self.type_complete_mode = _VARIABLE_COMPLETE
            else:
                self.type_complete_mode = _OPTION_COMPLETE
        return segment

    def show_help(self, parameter):
        """Display the help for either all commands or the help for a
        custom command.

        parameter[in]      Any parameter for the help command.
                           For example, 'help commands'
        """
        if self.quiet:
            return
        if not parameter or (parameter and parameter.lower() == 'commands'):
            print
            print_dictionary_list(['Command', 'Description'],
                                  ['name', 'text', 'alias'],
                                  self.base_commands, self.width, True)
            print
        else:
            matches = self.get_commands(parameter)
            if len(matches) > 0:
                self.show_command_help(matches)
            elif self.custom_commands:
                self.show_custom_command_help(parameter)

    def do_variable_tab(self, segment):
        """Do the tab completion for a variable

        This method will attempt to find a variable in the list of user-
        defined variables and complete the name of variable. If the user
        types 'TAB' twice, it will display a list of all possible matches.
        """
        # find the last $
        variable = ''
        start_var = 0
        new_var = ''
        stop = len(segment)
        for i in range(stop - 1, 0, -1):
            if segment[i] == ' ':
                break
            elif segment[i] == '$':
                variable = segment[i + 1:]
                start_var = i

        if start_var == stop:
            # show all of the variables
            matches = self.variables.get_matches({})
        else:
            matches = self.variables.get_matches(variable)

        if self.tab_count == 2:
            if len(matches) > 0:
                self.variables.show_variables(matches)
            else:
                self.variables.show_variables({})
            self.cmd_line.display_command()
            self.tab_count = 0
        else:
            # Do command completion here
            if len(matches) == 1:
                new_var = matches[0].items()[0][0] + ' '
                self.cmd_line.add(new_var[len(variable):])
                self.tab_count = 0

    def do_command_tab(self, command_text):
        """Do the tab completion for a command

        If the command is in the base commands, complete it there. If not,
        attempt to perform tab completion for custom commands (if defined).
        """
        # See if command is in the base command list first
        matches = self.get_commands(command_text)
        if len(matches) > 0:
            self.do_base_command_tab(command_text, matches)
        # Ok, not in command list, now check custom commands
        elif self.custom_commands:
            self.do_custom_tab(command_text)

    def do_base_command_tab(self, command_text, matches):
        """Do the tab completion for a base command.

        This method prints the list of base commands that match the
        command. If the user pressed TAB twice, it displays the list of all
        matches. If a single match is found, it returns the balance of the
        command.

        Note: this method gets its matches from do_command_tab.

        command_text[in]   Command
        matches[in]        Known matches (from do_command_tab)
        """
        if self.tab_count == 2:
            print "\n"
            print_dictionary_list(['Command', 'Description'],
                                  ['name', 'text', 'alias'], matches,
                                  self.width, True)
            print
            self.cmd_line.display_command()
            self.tab_count = 0
        else:
            if len(matches) == 1:
                if matches[0]['name'][:len(command_text)] == command_text:
                    new_cmd = matches[0]['name'] + ' '
                else:
                    new_cmd = matches[0]['alias'] + ' '
                self.tab_count = 0
                self.cmd_line.add(new_cmd[len(command_text):])

    def get_commands(self, cmd_prefix):
        """Get list of commands that match a prefix

        cmd_prefix[in]  prefix for name of command

        Returns dictionary entry for command based on matching first n chars
        """
        matches = []
        stop = len(cmd_prefix)
        start = 0
        for cmd in self.base_commands:
            if cmd['name'][start:stop] == cmd_prefix or \
               cmd['alias'][start:stop] == cmd_prefix:
                matches.append(cmd)

        return matches

    def show_command_help(self, commands):
        """Show the help for a list of commands.

        commands[in]       List of commands
        """
        if self.quiet:
            return
        print
        print_dictionary_list(['Command', 'Description'],
                              ['name', 'text', 'alias'], commands, self.width,
                              True)
        print

    def _do_command(self, command):
        """Execute a command

        This method routes the command to the appropriate methods for
        execution.

        command[in]        Command to execute

        Returns bool True - exit utility, False - do not exit
        """
        # do variable replacement
        command = self._replace_variables(command.strip(' '))
        if self.options.get('verbosity', False):
            print "\nExecuting command:", command
        # process simple commands
        if command.lower().startswith('set '):
            self._add_variable(command[4:])
            if not self.quiet:
                print
        elif command[0:11].lower() == 'show errors':
            self.show_errors()
        elif command[0:12].lower() == 'clear errors':
            self.clear_errors()
        elif command[0:15].lower() == 'show last error':
            self.show_last_error()
        elif command[0:14].lower() == 'show variables':
            self.variables.show_variables()
        elif self.custom_commands and command[0:12].lower() == 'show options':
            self.show_custom_options()
        else:
            cmd, parameters = self._get_util_parameters(command)
            if cmd is None:
                return False
            else:
                if cmd.lower() == 'help':
                    token = parameters[0] if parameters else ''
                    self.show_help(token)
                    self.cmd_line.clear()
                    self.tab_count = 0
                elif cmd == '':
                    print
                elif cmd.lower() in ['exit', 'quit']:
                    print
                    return True
                elif self.custom_commands:
                    if not self.is_valid_custom_command(cmd):
                        print("\n\nUnknown command: {0} {1}\n"
                              "".format(cmd, ' '.join(parameters)))
                    else:
                        try:
                            self.execute_custom_command(cmd, parameters)
                            print
                        except UtilError as err:
                            print err.errmsg

        self.cmd_line.clear()
        self.tab_count = 0
        return False

    def _process_command_keys(self, cmd_key):
        """Do the action associated with a command key.

        This method will act on the recognized command keys and execute the
        effect for each.

        cmd_key[in]        Key pressed
        """
        if cmd_key in ['ESCAPE']:
            self.cmd_line.erase_command()
        elif cmd_key in ['DELETE_POSIX', 'DELETE_WIN', 'DELETE_MAC']:
            self.cmd_line.delete_keypress()
            self.tab_count = 0
        elif cmd_key == 'ARROW_UP':
            self.cmd_line.replace_command(self.history.previous())
        elif cmd_key == 'ARROW_DN':
            self.cmd_line.replace_command(self.history.next())
        elif cmd_key == 'ARROW_LT':
            self.cmd_line.left_arrow_keypress()
        elif cmd_key == 'ARROW_RT':
            self.cmd_line.right_arrow_keypress()
        elif cmd_key in ['BACKSPACE_POSIX', 'BACKSPACE_WIN']:
            self.cmd_line.backspace_keypress()
        elif cmd_key == 'HOME':
            self.cmd_line.home_keypress()
        elif cmd_key == 'END':
            self.cmd_line.end_keypress()
        else:  # 'TAB'
            segment = self._set_complete_mode()
            self.tab_count += 1
            if self.type_complete_mode == _COMMAND_COMPLETE:
                self.do_command_tab(self.cmd_line.get_command())
            elif self.type_complete_mode == _OPTION_COMPLETE:
                self.do_option_tab(segment)
            else:  # _VARIABLE_COMPLETE
                self.do_variable_tab(segment)
        cmd_key = ''

    def _add_variable(self, set_command):
        """Add a variable to the list of variables.

        This method adds the user-defined variable to the internal list.

        set_command[in]    Set command from the user
        """
        if set_command.find('=') <= 0:
            print "\n\nSET command invalid. Syntax: SET <NAME> = <value>"
            return

        # get name and value
        name, value = set_command.split('=')
        name = name.strip().strip('$')
        value = value.strip()
        self.variables.add_variable(name, value)

    def _replace_variables(self, cmd_string):
        """Replace user-defined variables with values from the internal list.

        This method replaces $VARNAME with the value stored when the set
        command was issued.

        cmd_string[in]     Command from the user

        Returns string - command string with replacements
        """
        i = 1
        new_cmd = cmd_string
        while i > 0:
            i = new_cmd.find('$', i)
            if i > 0:
                j = new_cmd.find(' ', i)
                if j == -1:
                    j = len(new_cmd)
                if j > i:
                    var_name = new_cmd[i + 1:j]
                    var = self.variables.find_variable(var_name)
                    if var is not None:
                        new_cmd = new_cmd[0:i] + var[var_name] + new_cmd[j:]
                    else:
                        i = j

        return new_cmd

    @staticmethod
    def _get_util_parameters(cmd_string):
        """Split the command name from the command and return balance as
        parameters.

        cmd_string[in]     Command

        Returns tuple - command, list of parameters
        """
        try:
            tokens = shlex.split(cmd_string)
        except ValueError as err:
            print
            print("WARNING: Unable to execute command, reason: {0}"
                  "".format(str(err)))
            return None, None
        else:
            if len(tokens) > 1:
                return tokens[0], tokens[1:]
        return cmd_string.strip(' '), []

    def get_user_command(self):
        """Get a command from the user.

        This method displays a prompt to the user and returns when one of
        the command keys is pressed.
        """
        self.cmd_line.display_command()
        cmd_string = ''
        cmd_key = None
        self.tab_count = 0
        while cmd_key not in ['ENTER_POSIX', 'ENTER_WIN']:
            key = getch()
            # If a special key, act on it
            if key in _COMMAND_KEY:
                cmd_key = _COMMAND_KEY[key]
                # Windows does things oddly for some keys
                if not os.name == 'posix' and cmd_key == 'SPECIAL_WIN':
                    key = getch()
                    cmd_key = _WIN_COMMAND_KEY.get(key)
                    if cmd_key is None:
                        continue
                self._process_command_keys(cmd_key)
                cmd_string = self.cmd_line.get_command()
            # else add key to command buffer
            else:
                cmd_string = self.cmd_line.get_command()
                self.cmd_line.add(key)
                cmd_string = self.cmd_line.get_command()
            sys.stdout.flush()

        self.position = 0
        return cmd_string

    def run_console(self, lines=None):
        """Run the console.

        This method is the main loop for executing commands. For all subclassed
        classes, the user need only call this method to execute an interactive
        shell or execute commands and exit. It can be used in three modes:

        1) it can process commands passed via lines list
        2) it can process commands passed via a pipe to the python exec
        3) it can prompt for commands and execute them as entered

        Modes (1) and (2) execute all commands then exit.

        lines[in]          If not empty, execute the list of commands.
        """
        if not lines:
            lines = []
        # If we have commands issued by the command line, execute and exit.
        if self.commands is not None:
            command_list = self.commands.split(';')
            for command in command_list:
                command = command.strip('\n').strip(' ')
                if os.name == 'nt':
                    command = command.strip('"')
                if self._do_command(command.strip('"')):
                    break

        # If we have piped input, read the input by line and execute
        elif not os.isatty(sys.stdin.fileno()) or len(lines) > 0:
            for command in sys.stdin.readlines():
                command_list = command.split(';')
                for cmd in command_list:
                    cmd = cmd.strip('\n').strip(' ')
                    if os.name == 'nt':
                        cmd = cmd.strip('"')
                    if self._do_command(cmd.strip('"')):
                        break

        # Otherwise, we are in an interactive mode where we get a command
        # from the user and execute
        else:
            cmd = ''
            if not self.quiet:
                print self.options.get('welcome', 'Welcome to the console!\n')
            while cmd.lower() not in ['exit', 'quit']:
                command = self.get_user_command()
                self.history.add(command)
                if self._do_command(command):
                    break
            if not self.quiet:
                print self.options.get('goodbye',
                                       'Thanks for using the console.\n')
Exemplo n.º 3
0
class Console(object):
    """Console class
    """
    def __init__(self, new_base_commands, options):
        """Constructor

        new_base_commands  Additions to the base commands
        options[in]        Options for the class member variables
        """
        self.options = options
        self.tab_count = 0
        self.base_commands = []
        self.base_commands.extend(new_base_commands)
        self.base_commands.extend(_BASE_COMMANDS)
        self.type_complete_mode = _COMMAND_COMPLETE
        self.cmd_line = _Command(self.options.get('prompt', '> '))
        self.width = self.options.get('width', 80)
        self.commands = self.options.get("commands", None)
        self.custom_commands = self.options.get("custom", False)
        self.quiet = self.options.get("quiet", False)
        self.variables = Variables(options)
        self.history = _CommandHistory({'max_size': 20})
        self.position = 0
        self.errors = []
        var_list = self.options.get('variables', [])
        for var in var_list:
            self.variables.add_variable(var['name'], var['value'])

    def show_errors(self):
        """Show errors

        Displays the errors captured when executing an utility.
        """
        if self.quiet:
            return
        if not self.errors:
            print
            print("No errors to display.\n")
        for error in self.errors:
            print
            print("{0}\n".format(error))

    def clear_errors(self):
        """Clear errors

        Clears captured errors occurring while executing an utility.
        """
        if self.quiet:
            return
        self.errors = []
        print

    def show_last_error(self):
        """Show errors

        Displays the last error occurred when executing an utility.
        """
        if self.quiet:
            return
        if not self.errors:
            print
            print("No error to display.\n")
        else:
            print
            print("{0}\n".format(self.errors[-1]))

    def show_custom_command_help(self, arg):
        """Display the help for a custom command.

        Note: Override this method for help on custom commands.

        arg[in]            Help command argument
        """
        if self.quiet:
            return
        print "\nNo commands like '%s' exist.\n" % arg

    def do_custom_tab(self, prefix):
        """Do custom tab key processing

        Note: Override this method for tab completion for custom commands.

        prefix[in]        Prefix of the custom command
        """
        pass

    def do_custom_option_tab(self, prefix):
        """Do custom command option tab key processing

        Note: Override this method for tab completion for options for custom
        commands.

        prefix[in]        Prefix of the custom command
        """
        if self.quiet:
            return
        print "\n\nNo custom commands found.\n"

    @staticmethod
    def is_valid_custom_command(command_text):
        """Is command a valid custom command?

        This method evaluates the custom command for validity.

        Note: Override this command to determine if command_text is a valid
        custom command.

        command_text[in]   The complete command as entered by user

        Returns bool - True if valid, False if not recognized
        """
        return False  # return False by default if method not overridden

    def execute_custom_command(self, command, parameters):
        """Execute a custom command.
        Note: Override this method to execute a custom command.
        """
        pass

    def show_custom_options(self):
        """Show custom options

        Note: Override this for 'show options' functionality.
        """
        if self.quiet:
            return

    def do_option_tab(self, prefix):
        """Do tab completion for options

        This method will search for an option using the prefix passed. It
        first searches the console commands defined at instantiation (the
        general commands for the shell) and if not found, checks the
        options for a custom command.

        prefix[in]        Prefix of the option
        """
        full_command = self.cmd_line.get_command()
        matches = self.get_commands(full_command.strip(' '))
        if len(matches) > 0:
            self.do_base_command_tab(full_command, matches)
        elif self.custom_commands:
            # if prefix is 'help', try command complete for custom commands
            if full_command[0:4].lower() == 'help':
                self.do_custom_tab(prefix)
            else:
                self.do_custom_option_tab(prefix)

    def _set_complete_mode(self):
        """Set the tab completion mode

        If the command buffer is only 1 part (command and no options),
        we are in _COMMAND_COMPLETE mode.

        Else if the nearest option contains a $ at the start, we are in
        _VARIABLE_COMPLETE mode.

        Else we are in _OPTION_COMPLETE mode.

        _COMMAND_COMPLETE = tab complete for base and custom commands
        _VARIABLE_COMPLETE = tab complete for user-defined variables
        _OPTION_COMPLETE = tab complete for base or custom command options
        """
        buf = self.cmd_line.get_command()
        parts = buf.split(' ')
        segment = ''
        if (len(buf) > 0 and len(parts) == 1):
            self.type_complete_mode = _COMMAND_COMPLETE
        else:
            segment = self.cmd_line.get_nearest_option()
            if segment.find('$') > 0:
                self.type_complete_mode = _VARIABLE_COMPLETE
            else:
                self.type_complete_mode = _OPTION_COMPLETE
        return segment

    def show_help(self, parameter):
        """Display the help for either all commands or the help for a
        custom command.

        parameter[in]      Any parameters for the help command.
                           For example, 'help commands'
        """
        if self.quiet:
            return
        if not parameter or (parameter and parameter.lower() == 'commands'):
            print
            print_dictionary_list(['Command', 'Description'],
                                  ['name', 'text', 'alias'],
                                  self.base_commands, self.width, True)
            print
        else:
            matches = self.get_commands(parameter)
            if len(matches) > 0:
                self.show_command_help(matches)
            elif self.custom_commands:
                self.show_custom_command_help(parameter)

    def do_variable_tab(self, segment):
        """Do the tab completion for a variable

        This method will attempt to find a variable in the list of user-
        defined variables and complete the name of variable. If the user
        types 'TAB' twice, it will display a list of all possible matches.
        """
        #find the last $
        variable = ''
        start_var = 0
        new_var = ''
        stop = len(segment)
        for i in range(stop - 1, 0, -1):
            if segment[i] == ' ':
                break
            elif segment[i] == '$':
                variable = segment[i + 1:]
                start_var = i

        if start_var == stop:
            # show all of the variables
            matches = self.variables.get_matches({})
        else:
            matches = self.variables.get_matches(variable)

        if self.tab_count == 2:
            if len(matches) > 0:
                self.variables.show_variables(matches)
            else:
                self.variables.show_variables({})
            self.cmd_line.display_command()
            self.tab_count = 0
        else:
            # Do command completion here
            if len(matches) == 1:
                new_var = matches[0].items()[0][0] + ' '
                self.cmd_line.add(new_var[len(variable):])
                self.tab_count = 0

    def do_command_tab(self, command_text):
        """Do the tab completion for a command

        If the command is in the base commands, complete it there. If not,
        attempt to perform tab completion for custom commands (if defined).
        """
        # See if command is in the base command list first
        matches = self.get_commands(command_text)
        if len(matches) > 0:
            self.do_base_command_tab(command_text, matches)
        # Ok, not in command list, now check custom commands
        elif self.custom_commands:
            self.do_custom_tab(command_text)

    def do_base_command_tab(self, command_text, matches):
        """Do the tab completion for a base command.

        This method prints the list of base commands that match the
        command. If the user pressed TAB twice, it displays the list of all
        matches. If a single match is found, it returns the balance of the
        command.

        Note: this method gets its matches from do_command_tab.

        command_text[in]   Command
        matches[in]        Known matches (from do_command_tab)
        """
        if self.tab_count == 2:
            print "\n"
            print_dictionary_list(['Command', 'Description'],
                                  ['name', 'text', 'alias'],
                                  matches, self.width, True)
            print
            self.cmd_line.display_command()
            self.tab_count = 0
        else:
            if len(matches) == 1:
                new_cmd = matches[0]['name'] + ' '
                self.tab_count = 0
                self.cmd_line.add(new_cmd[len(command_text):])

    def get_commands(self, cmd_prefix):
        """Get list of commands that match a prefix

        cmd_prefix[in]  prefix for name of command

        Returns dictionary entry for command based on matching first n chars
        """
        matches = []
        stop = len(cmd_prefix)
        start = 0
        for cmd in self.base_commands:
            if cmd['name'][start:stop] == cmd_prefix or \
               cmd['alias'][start:stop] == cmd_prefix:
                matches.append(cmd)

        return matches

    def show_command_help(self, commands):
        """Show the help for a list of commands.

        commands[in]       List of commands
        """
        if self.quiet:
            return
        print
        print_dictionary_list(['Command', 'Description'],
                              ['name', 'text', 'alias'],
                              commands, self.width, True)
        print

    def _do_command(self, command):
        """Execute a command

        This method routes the command to the appropriate methods for
        execution.

        command[in]        Command to execute

        Returns bool True - exit utility, False - do not exit
        """
        # do variable replacement
        command = self._replace_variables(command.strip(' '))
        if self.options.get('verbosity', False):
            print "\nExecuting command:", command
        # process simple commands
        if command.lower().startswith('set '):
            self._add_variable(command[4:])
            if not self.quiet:
                print
        elif command[0:11].lower() == 'show errors':
            self.show_errors()
        elif command[0:12].lower() == 'clear errors':
            self.clear_errors()
        elif command[0:15].lower() == 'show last error':
            self.show_last_error()
        elif command[0:14].lower() == 'show variables':
            self.variables.show_variables()
        elif self.custom_commands and command[0:12].lower() == 'show options':
            self.show_custom_options()
        else:
            cmd, parameters = self._get_util_parameters(command)
            cmd = cmd.strip()
            parameters = parameters.strip()
            if cmd.lower() == 'help':
                self.show_help(parameters)
                self.cmd_line.clear()
                self.tab_count = 0
            elif cmd == '':
                print
            elif cmd.lower() in ['exit', 'quit']:
                print
                return True
            elif self.custom_commands:
                if not self.is_valid_custom_command(cmd):
                    print "\n\nUnknown command: %s %s\n" % (cmd, parameters)
                else:
                    try:
                        self.execute_custom_command(cmd, parameters)
                        print
                    except UtilError, err:
                        print err.errmsg

        self.cmd_line.clear()
        self.tab_count = 0
        return False
Exemplo n.º 4
0
class Console(object):
    """Console class
    """
    def __init__(self, new_base_commands, options):
        """Constructor

        new_base_commands  Additions to the base commands
        options[in]        Options for the class member variables
        """
        self.options = options
        self.tab_count = 0
        self.base_commands = []
        self.base_commands.extend(new_base_commands)
        self.base_commands.extend(_BASE_COMMANDS)
        self.type_complete_mode = _COMMAND_COMPLETE
        self.cmd_line = _Command(self.options.get('prompt', '> '))
        self.width = self.options.get('width', 80)
        self.commands = self.options.get("commands", None)
        self.custom_commands = self.options.get("custom", False)
        self.quiet = self.options.get("quiet", False)
        self.variables = Variables(options)
        self.history = _CommandHistory({'max_size': 20})
        self.position = 0
        self.errors = []
        var_list = self.options.get('variables', [])
        for var in var_list:
            self.variables.add_variable(var['name'], var['value'])

    def show_errors(self):
        """Show errors

        Displays the errors captured when executing an utility.
        """
        if self.quiet:
            return
        if not self.errors:
            print
            print("No errors to display.\n")
        for error in self.errors:
            print
            print("{0}\n".format(error))

    def clear_errors(self):
        """Clear errors

        Clears captured errors occurring while executing an utility.
        """
        if self.quiet:
            return
        self.errors = []
        print

    def show_last_error(self):
        """Show errors

        Displays the last error occurred when executing an utility.
        """
        if self.quiet:
            return
        if not self.errors:
            print
            print("No error to display.\n")
        else:
            print
            print("{0}\n".format(self.errors[-1]))

    def show_custom_command_help(self, arg):
        """Display the help for a custom command.

        Note: Override this method for help on custom commands.

        arg[in]            Help command argument
        """
        if self.quiet:
            return
        print "\nNo commands like '%s' exist.\n" % arg

    def do_custom_tab(self, prefix):
        """Do custom tab key processing

        Note: Override this method for tab completion for custom commands.

        prefix[in]        Prefix of the custom command
        """
        pass

    def do_custom_option_tab(self, prefix):
        """Do custom command option tab key processing

        Note: Override this method for tab completion for options for custom
        commands.

        prefix[in]        Prefix of the custom command
        """
        if self.quiet:
            return
        print "\n\nNo custom commands found.\n"

    @staticmethod
    def is_valid_custom_command(command_text):
        """Is command a valid custom command?

        This method evaluates the custom command for validity.

        Note: Override this command to determine if command_text is a valid
        custom command.

        command_text[in]   The complete command as entered by user

        Returns bool - True if valid, False if not recognized
        """
        return False  # return False by default if method not overridden

    def execute_custom_command(self, command, parameters):
        """Execute a custom command.
        Note: Override this method to execute a custom command.
        """
        pass

    def show_custom_options(self):
        """Show custom options

        Note: Override this for 'show options' functionality.
        """
        if self.quiet:
            return

    def do_option_tab(self, prefix):
        """Do tab completion for options

        This method will search for an option using the prefix passed. It
        first searches the console commands defined at instantiation (the
        general commands for the shell) and if not found, checks the
        options for a custom command.

        prefix[in]        Prefix of the option
        """
        full_command = self.cmd_line.get_command()
        matches = self.get_commands(full_command.strip(' '))
        if len(matches) > 0:
            self.do_base_command_tab(full_command, matches)
        elif self.custom_commands:
            # if prefix is 'help', try command complete for custom commands
            if full_command[0:4].lower() == 'help':
                self.do_custom_tab(prefix)
            else:
                self.do_custom_option_tab(prefix)

    def _set_complete_mode(self):
        """Set the tab completion mode

        If the command buffer is only 1 part (command and no options),
        we are in _COMMAND_COMPLETE mode.

        Else if the nearest option contains a $ at the start, we are in
        _VARIABLE_COMPLETE mode.

        Else we are in _OPTION_COMPLETE mode.

        _COMMAND_COMPLETE = tab complete for base and custom commands
        _VARIABLE_COMPLETE = tab complete for user-defined variables
        _OPTION_COMPLETE = tab complete for base or custom command options
        """
        buf = self.cmd_line.get_command()
        parts = buf.split(' ')
        segment = ''
        if (len(buf) > 0 and len(parts) == 1):
            self.type_complete_mode = _COMMAND_COMPLETE
        else:
            segment = self.cmd_line.get_nearest_option()
            if segment.find('$') > 0:
                self.type_complete_mode = _VARIABLE_COMPLETE
            else:
                self.type_complete_mode = _OPTION_COMPLETE
        return segment

    def show_help(self, parameter):
        """Display the help for either all commands or the help for a
        custom command.

        parameter[in]      Any parameter for the help command.
                           For example, 'help commands'
        """
        if self.quiet:
            return
        if not parameter or (parameter and parameter.lower() == 'commands'):
            print
            print_dictionary_list(['Command', 'Description'],
                                  ['name', 'text', 'alias'],
                                  self.base_commands, self.width, True)
            print
        else:
            matches = self.get_commands(parameter)
            if len(matches) > 0:
                self.show_command_help(matches)
            elif self.custom_commands:
                self.show_custom_command_help(parameter)

    def do_variable_tab(self, segment):
        """Do the tab completion for a variable

        This method will attempt to find a variable in the list of user-
        defined variables and complete the name of variable. If the user
        types 'TAB' twice, it will display a list of all possible matches.
        """
        # find the last $
        variable = ''
        start_var = 0
        new_var = ''
        stop = len(segment)
        for i in range(stop - 1, 0, -1):
            if segment[i] == ' ':
                break
            elif segment[i] == '$':
                variable = segment[i + 1:]
                start_var = i

        if start_var == stop:
            # show all of the variables
            matches = self.variables.get_matches({})
        else:
            matches = self.variables.get_matches(variable)

        if self.tab_count == 2:
            if len(matches) > 0:
                self.variables.show_variables(matches)
            else:
                self.variables.show_variables({})
            self.cmd_line.display_command()
            self.tab_count = 0
        else:
            # Do command completion here
            if len(matches) == 1:
                new_var = matches[0].items()[0][0] + ' '
                self.cmd_line.add(new_var[len(variable):])
                self.tab_count = 0

    def do_command_tab(self, command_text):
        """Do the tab completion for a command

        If the command is in the base commands, complete it there. If not,
        attempt to perform tab completion for custom commands (if defined).
        """
        # See if command is in the base command list first
        matches = self.get_commands(command_text)
        if len(matches) > 0:
            self.do_base_command_tab(command_text, matches)
        # Ok, not in command list, now check custom commands
        elif self.custom_commands:
            self.do_custom_tab(command_text)

    def do_base_command_tab(self, command_text, matches):
        """Do the tab completion for a base command.

        This method prints the list of base commands that match the
        command. If the user pressed TAB twice, it displays the list of all
        matches. If a single match is found, it returns the balance of the
        command.

        Note: this method gets its matches from do_command_tab.

        command_text[in]   Command
        matches[in]        Known matches (from do_command_tab)
        """
        if self.tab_count == 2:
            print "\n"
            print_dictionary_list(['Command', 'Description'],
                                  ['name', 'text', 'alias'],
                                  matches, self.width, True)
            print
            self.cmd_line.display_command()
            self.tab_count = 0
        else:
            if len(matches) == 1:
                if matches[0]['name'][:len(command_text)] == command_text:
                    new_cmd = matches[0]['name'] + ' '
                else:
                    new_cmd = matches[0]['alias'] + ' '
                self.tab_count = 0
                self.cmd_line.add(new_cmd[len(command_text):])

    def get_commands(self, cmd_prefix):
        """Get list of commands that match a prefix

        cmd_prefix[in]  prefix for name of command

        Returns dictionary entry for command based on matching first n chars
        """
        matches = []
        stop = len(cmd_prefix)
        start = 0
        for cmd in self.base_commands:
            if cmd['name'][start:stop] == cmd_prefix or \
               cmd['alias'][start:stop] == cmd_prefix:
                matches.append(cmd)

        return matches

    def show_command_help(self, commands):
        """Show the help for a list of commands.

        commands[in]       List of commands
        """
        if self.quiet:
            return
        print
        print_dictionary_list(['Command', 'Description'],
                              ['name', 'text', 'alias'],
                              commands, self.width, True)
        print

    def _do_command(self, command):
        """Execute a command

        This method routes the command to the appropriate methods for
        execution.

        command[in]        Command to execute

        Returns bool True - exit utility, False - do not exit
        """
        # do variable replacement
        command = self._replace_variables(command.strip(' '))
        if self.options.get('verbosity', False):
            print "\nExecuting command:", command
        # process simple commands
        if command.lower().startswith('set '):
            self._add_variable(command[4:])
            if not self.quiet:
                print
        elif command[0:11].lower() == 'show errors':
            self.show_errors()
        elif command[0:12].lower() == 'clear errors':
            self.clear_errors()
        elif command[0:15].lower() == 'show last error':
            self.show_last_error()
        elif command[0:14].lower() == 'show variables':
            self.variables.show_variables()
        elif self.custom_commands and command[0:12].lower() == 'show options':
            self.show_custom_options()
        else:
            cmd, parameters = self._get_util_parameters(command)
            if cmd is None:
                return False
            else:
                if cmd.lower() == 'help':
                    token = parameters[0] if parameters else ''
                    self.show_help(token)
                    self.cmd_line.clear()
                    self.tab_count = 0
                elif cmd == '':
                    print
                elif cmd.lower() in ['exit', 'quit']:
                    print
                    return True
                elif self.custom_commands:
                    if not self.is_valid_custom_command(cmd):
                        print("\n\nUnknown command: {0} {1}\n"
                              "".format(cmd, ' '.join(parameters)))
                    else:
                        try:
                            self.execute_custom_command(cmd, parameters)
                            print
                        except UtilError as err:
                            print err.errmsg

        self.cmd_line.clear()
        self.tab_count = 0
        return False

    def _process_command_keys(self, cmd_key):
        """Do the action associated with a command key.

        This method will act on the recognized command keys and execute the
        effect for each.

        cmd_key[in]        Key pressed
        """
        if cmd_key in ['ESCAPE']:
            self.cmd_line.erase_command()
        elif cmd_key in ['DELETE_POSIX', 'DELETE_WIN', 'DELETE_MAC']:
            self.cmd_line.delete_keypress()
            self.tab_count = 0
        elif cmd_key == 'ARROW_UP':
            self.cmd_line.replace_command(self.history.previous())
        elif cmd_key == 'ARROW_DN':
            self.cmd_line.replace_command(self.history.next())
        elif cmd_key == 'ARROW_LT':
            self.cmd_line.left_arrow_keypress()
        elif cmd_key == 'ARROW_RT':
            self.cmd_line.right_arrow_keypress()
        elif cmd_key in ['BACKSPACE_POSIX', 'BACKSPACE_WIN']:
            self.cmd_line.backspace_keypress()
        elif cmd_key == 'HOME':
            self.cmd_line.home_keypress()
        elif cmd_key == 'END':
            self.cmd_line.end_keypress()
        else:  # 'TAB'
            segment = self._set_complete_mode()
            self.tab_count += 1
            if self.type_complete_mode == _COMMAND_COMPLETE:
                self.do_command_tab(self.cmd_line.get_command())
            elif self.type_complete_mode == _OPTION_COMPLETE:
                self.do_option_tab(segment)
            else:  # _VARIABLE_COMPLETE
                self.do_variable_tab(segment)
        cmd_key = ''

    def _add_variable(self, set_command):
        """Add a variable to the list of variables.

        This method adds the user-defined variable to the internal list.

        set_command[in]    Set command from the user
        """
        if set_command.find('=') <= 0:
            print "\n\nSET command invalid. Syntax: SET <NAME> = <value>"
            return

        # get name and value
        name, value = set_command.split('=')
        name = name.strip().strip('$')
        value = value.strip()
        self.variables.add_variable(name, value)

    def _replace_variables(self, cmd_string):
        """Replace user-defined variables with values from the internal list.

        This method replaces $VARNAME with the value stored when the set
        command was issued.

        cmd_string[in]     Command from the user

        Returns string - command string with replacements
        """
        i = 1
        new_cmd = cmd_string
        while i > 0:
            i = new_cmd.find('$', i)
            if i > 0:
                j = new_cmd.find(' ', i)
                if j == -1:
                    j = len(new_cmd)
                if j > i:
                    var_name = new_cmd[i + 1:j]
                    var = self.variables.find_variable(var_name)
                    if var is not None:
                        new_cmd = new_cmd[0:i] + var[var_name] + new_cmd[j:]
                    else:
                        i = j

        return new_cmd

    @staticmethod
    def _get_util_parameters(cmd_string):
        """Split the command name from the command and return balance as
        parameters.

        cmd_string[in]     Command

        Returns tuple - command, list of parameters
        """
        try:
            tokens = shlex.split(cmd_string)
        except ValueError as err:
            print
            print("WARNING: Unable to execute command, reason: {0}"
                  "".format(str(err)))
            return None, None
        else:
            if len(tokens) > 1:
                return tokens[0], tokens[1:]
        return cmd_string.strip(' '), []

    def get_user_command(self):
        """Get a command from the user.

        This method displays a prompt to the user and returns when one of
        the command keys is pressed.
        """
        self.cmd_line.display_command()
        cmd_string = ''
        cmd_key = None
        self.tab_count = 0
        while cmd_key not in ['ENTER_POSIX', 'ENTER_WIN']:
            key = getch()
            # If a special key, act on it
            if key in _COMMAND_KEY:
                cmd_key = _COMMAND_KEY[key]
                # Windows does things oddly for some keys
                if not os.name == 'posix' and cmd_key == 'SPECIAL_WIN':
                    key = getch()
                    cmd_key = _WIN_COMMAND_KEY.get(key)
                    if cmd_key is None:
                        continue
                self._process_command_keys(cmd_key)
                cmd_string = self.cmd_line.get_command()
            # else add key to command buffer
            else:
                cmd_string = self.cmd_line.get_command()
                self.cmd_line.add(key)
                cmd_string = self.cmd_line.get_command()
            sys.stdout.flush()

        self.position = 0
        return cmd_string

    def run_console(self, lines=None):
        """Run the console.

        This method is the main loop for executing commands. For all subclassed
        classes, the user need only call this method to execute an interactive
        shell or execute commands and exit. It can be used in three modes:

        1) it can process commands passed via lines list
        2) it can process commands passed via a pipe to the python exec
        3) it can prompt for commands and execute them as entered

        Modes (1) and (2) execute all commands then exit.

        lines[in]          If not empty, execute the list of commands.
        """
        if not lines:
            lines = []
        # If we have commands issued by the command line, execute and exit.
        if self.commands is not None:
            command_list = self.commands.split(';')
            for command in command_list:
                command = command.strip('\n').strip(' ')
                if os.name == 'nt':
                    command = command.strip('"')
                if self._do_command(command.strip('"')):
                    break

        # If we have piped input, read the input by line and execute
        elif not os.isatty(sys.stdin.fileno()) or len(lines) > 0:
            for command in sys.stdin.readlines():
                command_list = command.split(';')
                for cmd in command_list:
                    cmd = cmd.strip('\n').strip(' ')
                    if os.name == 'nt':
                        cmd = cmd.strip('"')
                    if self._do_command(cmd.strip('"')):
                        break

        # Otherwise, we are in an interactive mode where we get a command
        # from the user and execute
        else:
            cmd = ''
            if not self.quiet:
                print self.options.get('welcome', 'Welcome to the console!\n')
            while cmd.lower() not in ['exit', 'quit']:
                command = self.get_user_command()
                self.history.add(command)
                if self._do_command(command):
                    break
            if not self.quiet:
                print self.options.get('goodbye',
                                       'Thanks for using the console.\n')