| Index: third_party/logilab/logilab/common/cli.py
|
| diff --git a/third_party/logilab/logilab/common/cli.py b/third_party/logilab/logilab/common/cli.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cdeef974f482eb8258625ed9b82db307dc24a677
|
| --- /dev/null
|
| +++ b/third_party/logilab/logilab/common/cli.py
|
| @@ -0,0 +1,211 @@
|
| +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
|
| +# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
| +#
|
| +# This file is part of logilab-common.
|
| +#
|
| +# logilab-common is free software: you can redistribute it and/or modify it under
|
| +# the terms of the GNU Lesser General Public License as published by the Free
|
| +# Software Foundation, either version 2.1 of the License, or (at your option) any
|
| +# later version.
|
| +#
|
| +# logilab-common is distributed in the hope that it will be useful, but WITHOUT
|
| +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
| +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
| +# details.
|
| +#
|
| +# You should have received a copy of the GNU Lesser General Public License along
|
| +# with logilab-common. If not, see <http://www.gnu.org/licenses/>.
|
| +"""Command line interface helper classes.
|
| +
|
| +It provides some default commands, a help system, a default readline
|
| +configuration with completion and persistent history.
|
| +
|
| +Example::
|
| +
|
| + class BookShell(CLIHelper):
|
| +
|
| + def __init__(self):
|
| + # quit and help are builtins
|
| + # CMD_MAP keys are commands, values are topics
|
| + self.CMD_MAP['pionce'] = _("Sommeil")
|
| + self.CMD_MAP['ronfle'] = _("Sommeil")
|
| + CLIHelper.__init__(self)
|
| +
|
| + help_do_pionce = ("pionce", "pionce duree", _("met ton corps en veille"))
|
| + def do_pionce(self):
|
| + print('nap is good')
|
| +
|
| + help_do_ronfle = ("ronfle", "ronfle volume", _("met les autres en veille"))
|
| + def do_ronfle(self):
|
| + print('fuuuuuuuuuuuu rhhhhhrhrhrrh')
|
| +
|
| + cl = BookShell()
|
| +"""
|
| +
|
| +from __future__ import print_function
|
| +
|
| +__docformat__ = "restructuredtext en"
|
| +
|
| +from six.moves import builtins, input
|
| +
|
| +if not hasattr(builtins, '_'):
|
| + builtins._ = str
|
| +
|
| +
|
| +def init_readline(complete_method, histfile=None):
|
| + """Init the readline library if available."""
|
| + try:
|
| + import readline
|
| + readline.parse_and_bind("tab: complete")
|
| + readline.set_completer(complete_method)
|
| + string = readline.get_completer_delims().replace(':', '')
|
| + readline.set_completer_delims(string)
|
| + if histfile is not None:
|
| + try:
|
| + readline.read_history_file(histfile)
|
| + except IOError:
|
| + pass
|
| + import atexit
|
| + atexit.register(readline.write_history_file, histfile)
|
| + except:
|
| + print('readline is not available :-(')
|
| +
|
| +
|
| +class Completer :
|
| + """Readline completer."""
|
| +
|
| + def __init__(self, commands):
|
| + self.list = commands
|
| +
|
| + def complete(self, text, state):
|
| + """Hook called by readline when <tab> is pressed."""
|
| + n = len(text)
|
| + matches = []
|
| + for cmd in self.list :
|
| + if cmd[:n] == text :
|
| + matches.append(cmd)
|
| + try:
|
| + return matches[state]
|
| + except IndexError:
|
| + return None
|
| +
|
| +
|
| +class CLIHelper:
|
| + """An abstract command line interface client which recognize commands
|
| + and provide an help system.
|
| + """
|
| +
|
| + CMD_MAP = {'help': _("Others"),
|
| + 'quit': _("Others"),
|
| + }
|
| + CMD_PREFIX = ''
|
| +
|
| + def __init__(self, histfile=None) :
|
| + self._topics = {}
|
| + self.commands = None
|
| + self._completer = Completer(self._register_commands())
|
| + init_readline(self._completer.complete, histfile)
|
| +
|
| + def run(self):
|
| + """loop on user input, exit on EOF"""
|
| + while True:
|
| + try:
|
| + line = input('>>> ')
|
| + except EOFError:
|
| + print
|
| + break
|
| + s_line = line.strip()
|
| + if not s_line:
|
| + continue
|
| + args = s_line.split()
|
| + if args[0] in self.commands:
|
| + try:
|
| + cmd = 'do_%s' % self.commands[args[0]]
|
| + getattr(self, cmd)(*args[1:])
|
| + except EOFError:
|
| + break
|
| + except:
|
| + import traceback
|
| + traceback.print_exc()
|
| + else:
|
| + try:
|
| + self.handle_line(s_line)
|
| + except:
|
| + import traceback
|
| + traceback.print_exc()
|
| +
|
| + def handle_line(self, stripped_line):
|
| + """Method to overload in the concrete class (should handle
|
| + lines which are not commands).
|
| + """
|
| + raise NotImplementedError()
|
| +
|
| +
|
| + # private methods #########################################################
|
| +
|
| + def _register_commands(self):
|
| + """ register available commands method and return the list of
|
| + commands name
|
| + """
|
| + self.commands = {}
|
| + self._command_help = {}
|
| + commands = [attr[3:] for attr in dir(self) if attr[:3] == 'do_']
|
| + for command in commands:
|
| + topic = self.CMD_MAP[command]
|
| + help_method = getattr(self, 'help_do_%s' % command)
|
| + self._topics.setdefault(topic, []).append(help_method)
|
| + self.commands[self.CMD_PREFIX + command] = command
|
| + self._command_help[command] = help_method
|
| + return self.commands.keys()
|
| +
|
| + def _print_help(self, cmd, syntax, explanation):
|
| + print(_('Command %s') % cmd)
|
| + print(_('Syntax: %s') % syntax)
|
| + print('\t', explanation)
|
| + print()
|
| +
|
| +
|
| + # predefined commands #####################################################
|
| +
|
| + def do_help(self, command=None) :
|
| + """base input of the help system"""
|
| + if command in self._command_help:
|
| + self._print_help(*self._command_help[command])
|
| + elif command is None or command not in self._topics:
|
| + print(_("Use help <topic> or help <command>."))
|
| + print(_("Available topics are:"))
|
| + topics = sorted(self._topics.keys())
|
| + for topic in topics:
|
| + print('\t', topic)
|
| + print()
|
| + print(_("Available commands are:"))
|
| + commands = self.commands.keys()
|
| + commands.sort()
|
| + for command in commands:
|
| + print('\t', command[len(self.CMD_PREFIX):])
|
| +
|
| + else:
|
| + print(_('Available commands about %s:') % command)
|
| + print
|
| + for command_help_method in self._topics[command]:
|
| + try:
|
| + if callable(command_help_method):
|
| + self._print_help(*command_help_method())
|
| + else:
|
| + self._print_help(*command_help_method)
|
| + except:
|
| + import traceback
|
| + traceback.print_exc()
|
| + print('ERROR in help method %s'% (
|
| + command_help_method.__name__))
|
| +
|
| + help_do_help = ("help", "help [topic|command]",
|
| + _("print help message for the given topic/command or \
|
| +available topics when no argument"))
|
| +
|
| + def do_quit(self):
|
| + """quit the CLI"""
|
| + raise EOFError()
|
| +
|
| + def help_do_quit(self):
|
| + return ("quit", "quit", _("quit the application"))
|
|
|