1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
# 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()
"""
__docformat__ = "restructuredtext en"
from logilab.common.compat import raw_input, builtins
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 = raw_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.func_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"))
|