Esempio n. 1
0
 def reload(self, configuration):
     cmd.Cmd.__init__(self)
     self.conf = configuration
     # use this instead of plain `print`
     self.io = InOut()
     self.io.colorize.colors.mono = not self.conf.use_colors == "True"
     # load as plugins all classes that name starts with class_prefix
     self.class_prefix = "Plugin_"
     # use all methods that name stasts with method_prefix
     self.method_prefix = "do_"
     self.prompt = self.io.colorize(self.conf.shell_prompt)
     self.intro = self.io.colorize(self.conf.shell_intro)
     # load plugins
     self.commands = self.load_plugins(self.conf.plugins_path)
     # load history
     self.load_history(os.path.expanduser(self.conf.history_file),
             int(self.conf.history_length))
     # create build_dir if doesn't exist
     if not os.path.isdir(os.path.expanduser(self.conf.build_dir)):
         os.mkdir(os.path.expanduser(self.conf.build_dir))
Esempio n. 2
0
class Shell(cmd.Cmd):
    """Interactive shell framework.
    To use it, write some modules, becouse by default it's very poor shell.
    """
    def __init__(self, configuration):
        self.reload(configuration)

    def reload(self, configuration):
        cmd.Cmd.__init__(self)
        self.conf = configuration
        # use this instead of plain `print`
        self.io = InOut()
        self.io.colorize.colors.mono = not self.conf.use_colors == "True"
        # load as plugins all classes that name starts with class_prefix
        self.class_prefix = "Plugin_"
        # use all methods that name stasts with method_prefix
        self.method_prefix = "do_"
        self.prompt = self.io.colorize(self.conf.shell_prompt)
        self.intro = self.io.colorize(self.conf.shell_intro)
        # load plugins
        self.commands = self.load_plugins(self.conf.plugins_path)
        # load history
        self.load_history(os.path.expanduser(self.conf.history_file),
                int(self.conf.history_length))
        # create build_dir if doesn't exist
        if not os.path.isdir(os.path.expanduser(self.conf.build_dir)):
            os.mkdir(os.path.expanduser(self.conf.build_dir))

    def do_reload(self, *ignore):
        self.reload(self.conf)

    def load_history(self, hfile, hlength):
        """load history, create empty file if history doesn't exist"""
        if not os.path.isfile(hfile):
            open(hfile, "w").close()
        readline.read_history_file(hfile)
        readline.set_history_length(hlength)

    def load_plugins(self, modules_path):
        """Load all commands modules from modules_path direcotory."""
        command_modules = []
        # adding plugins path to sys.path
        if modules_path not in sys.path:
            sys.path.append(modules_path)
        # importing all modules from modules_path
        for module_name in os.listdir(modules_path):
            module_path = os.path.abspath(
                    string.join(modules_path, module_name))
            (module_name, module_extension) = os.path.splitext(module_name)
            # if it shouldn't be loaded
            if os.path.islink(module_path) or  \
                    module_path == __file__ or \
                    module_extension != ".py":
                        continue
            for key in sys.modules.keys():
                if key == module_name:
                    del sys.modules[key]
            module = __import__(module_name)
            command_modules.append({"obj": module_name, "name": module,})
        # search for class in each module
        module_objs = {}
        for module in command_modules:
            for obj in dir(module["name"]):
                if obj.startswith(self.class_prefix):
                    try:
                        # create instance for each class
                        module_objs[obj[len(self.class_prefix):]] = \
                            getattr(module['name'], obj)(self.io, self.conf)
                    except TypeError:
                        pass
        return module_objs

    def do_shell(self, cmd):
        """System shell command, for commads which starts with !"""
        os.system(cmd)

    def emptyline(self):
        """If no commad was given"""
        pass

    def replace_alias(self, cmd):
        """check if alias exists and if so, replace command"""
        for alias in self.conf.alias:
            if cmd.startswith(alias) and \
                    (len(cmd) == len(alias) or cmd[len(alias)] == " "):
                cmd = cmd.replace(alias, self.conf.alias[alias], 1)
        return cmd

    def run_single_command(self, cmd):
        """Run single command."""
        # alias first
        cmd = self.replace_alias(cmd)
        cmd = cmd.split()
        # no such command
        if not cmd[0] in self.commands:
            self.io.put("%s : command not found." % cmd[0])
            return False
        elif len(cmd) == 1:
            # try to run __call__() method
            try:
                return getattr(self.commands[cmd[0]], "__call__")()
            except (TypeError, AttributeError):
                self.io.put("%s : bad usege. Try to run help." % cmd[0])
                return False
        else:
            argmethod = self.method_prefix + cmd[1]
            # if cmd[1] is class method
            if argmethod in dir(self.commands[cmd[0]]):
                try:
                    return getattr(self.commands[cmd[0]], argmethod)(*cmd[2:])
                except TypeError:
                    self.io.put("#{BOLD}%s #{NONE}: bad usage" % cmd[1])
                    return False
            else:
                # try tu run __call__() method
                try:
                    return getattr(self.commands[cmd[0]], "__call__")(*cmd[1:])
                except (TypeError, AttributeError):
                    self.io.put("  %s  : #{RED}bad usage#{NONE}" % cmd[0])
                    return False

    def run_command(self, cmd):
        """Split multicommand and each one separated"""
        arg_list = ''
        if self.conf.arguments_pipe in cmd:
            cmd, arg_list = cmd.split(self.conf.arguments_pipe, 1)
        # split command by the conf.cmd_separator
        cmd_list = cmd.split(self.conf.cmd_separator)
        # split the cmd_list into cmd and arg_list
        for c in cmd_list:
            c = c.strip()
            c = " ".join([c, arg_list])
            if not self.run_single_command(c):
                break

    def default(self, cmd, *ignore):
        """When commad was given"""
        cmd = self.replace_alias(cmd)
        self.run_command(cmd)

    def completenames(self, text, *ignored):
        """Complete commands"""
        dotext = self.method_prefix + text
        # local methods
        local_cmd_list = \
                [a[3:] + " " for a in self.get_names() if a.startswith(dotext)]
        # + all metrods from modules
        module_cmd_list = \
                [a + " " for a in self.commands.keys() if a.startswith(text)]
        # + all aliases
        aliases_cmd_list = \
                [a + " " for a in self.conf.alias.keys() if a.startswith(text)]
        return local_cmd_list + module_cmd_list + aliases_cmd_list

    def completedefault(self, text, line, begidx, endidx):
        """Complete commands argument"""
        dotext = self.method_prefix + text
        line_list = line.split()
        # if only commands was given
        if len(line_list) == 1:
            cmds = [a[3:] + " " for a in dir(self.commands[line_list[0]]) \
                    if a.startswith(dotext)]
        # second word completition
        elif len(line_list) == 2 and not line[-1] == " ":
            cmds = [a[3:] + " " for a in dir(self.commands[line_list[0]]) \
                    if a.startswith(dotext)]
        else:
            try:
                cmds = getattr(self.commands[line_list[0]],
                        "complete")(line)
            except AttributeError:
                cmds = []
        return cmds

    def get_help(self, arg):
        """Return __doc__ or None if doesn't exist"""
        arg = arg.split()
        if arg[0] in self.conf.alias:
            self.io.put("#{BOLD}%s#{NONE} is alias for #{BOLD}%s#{NONE}" % \
                    (arg[0], self.conf.alias[arg[0]]))
            arg = self.conf.alias[arg[0]].split()
        if len(arg) == 1:
            # first - search in build-in methods
            method = self.method_prefix + arg[0]
            if method in dir(self):
                doc = getattr(self, method).__doc__
                if doc:
                    return doc.replace(' ' * 4, '')
            elif arg[0] in self.commands and self.commands[arg[0]].__doc__:
                    return self.commands[arg[0]].__doc__.replace(' ' * 4, '')
        elif len(arg) == 2:
            method = self.method_prefix + arg[1]
            if arg[0] in self.commands and \
                    method in dir(self.commands[arg[0]]):
                doc = getattr(self.commands[arg[0]], method).__doc__
                if doc:
                    return doc.replace(' ' * 4, '')
        return None

    def do_help(self, arg):
        """Show help for commands
        Usage: help <command> [<argument>]
        """
        if not arg:
            self.do_help('help')
            for (name, command) in self.commands.iteritems():
                self.io.put('#{BLUE}%s#{NONE}' % name)
                for cmd in dir(command):
                    if cmd.startswith(self.method_prefix):
                        cmd_name = cmd[len(self.method_prefix):]
                        helptext = getattr(command, cmd).__doc__ \
                                or 'no documentation'
                        helptext = helptext.replace('\n', ' ')
                        helptext = re.sub('\s{2,}', ' ', helptext)
                        self.io.put(' #{BOLD}%s#{NONE} - %s' % \
                                (cmd_name.ljust(16), helptext))
        else:
            doc = self.get_help(arg)
            if doc:
                self.io.put("%s" % doc)
            else:
                self.io.put("No help found.")

    def do_history(self, hnumb=None, *ignored):
        """Show the history"""
        # TODO 
        # better history listing 
        # print history
        if not hnumb:
            for n in range(1, int(self.conf.history_length)):
                cmd = readline.get_history_item(n)
                if not cmd:
                    break
                self.io.put("%6d  %s" % (n, cmd))
        # for history range 12-22 or -22 or 22- 
        else:
            try:
                if "-" in hnumb:
                    if hnumb[-1] == "-" or hnumb[0] == "-":
                        start = int(hnumb.replace("-", " "))
                        end = int(self.conf.history_length)
                    else:
                        start, end = hnumb.split("-")
                        start = int(start)
                        end = int(end) + 1
                    for n in range(start, end):
                        cmd = readline.get_history_item(n)
                        if not cmd:
                            break
                        self.io.put("%6d  %s" % (n, cmd))
                else:
                    hnumb = int(hnumb)
                    self.io.put(readline.get_history_item(hnumb))
            except ValueError:
                self.io.put("""#{RED}Bad value. #{NONE}
#{BOLD}Usage: history <number or range>#{NONE}
    history  11-20      from 11 to 20
    history  22-        from 22 fo the end of history file
    history  -22        same as 22-""")

    def do_clear(self, *ignored):
        # TODO [ 21:13 - 16.03.2008 ] 
        os.system('clear')

    def do_quit(self, *ignored):
        """Quit from shell"""
        if int(self.conf.history_length):
            readline.write_history_file(os.path.expanduser(self.conf.history_file))
        self.io.put('#{BLUE}quit..#{NONE}')
        sys.exit(1)

    # method aliases
    do_EOF = do_quit
    do_exit = do_quit