Package logilab :: Package common :: Module cli
[frames] | no frames]

Source Code for Module logilab.common.cli

  1  # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 
  2  # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 
  3  # 
  4  # This file is part of logilab-common. 
  5  # 
  6  # logilab-common is free software: you can redistribute it and/or modify it under 
  7  # the terms of the GNU Lesser General Public License as published by the Free 
  8  # Software Foundation, either version 2.1 of the License, or (at your option) any 
  9  # later version. 
 10  # 
 11  # logilab-common is distributed in the hope that it will be useful, but WITHOUT 
 12  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 
 13  # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 14  # details. 
 15  # 
 16  # You should have received a copy of the GNU Lesser General Public License along 
 17  # with logilab-common.  If not, see <http://www.gnu.org/licenses/>. 
 18  """Command line interface helper classes. 
 19   
 20  It provides some default commands, a help system, a default readline 
 21  configuration with completion and persistent history. 
 22   
 23  Example:: 
 24   
 25      class BookShell(CLIHelper): 
 26   
 27          def __init__(self): 
 28              # quit and help are builtins 
 29              # CMD_MAP keys are commands, values are topics 
 30              self.CMD_MAP['pionce'] = _("Sommeil") 
 31              self.CMD_MAP['ronfle'] = _("Sommeil") 
 32              CLIHelper.__init__(self) 
 33   
 34          help_do_pionce = ("pionce", "pionce duree", _("met ton corps en veille")) 
 35          def do_pionce(self): 
 36              print 'nap is good' 
 37   
 38          help_do_ronfle = ("ronfle", "ronfle volume", _("met les autres en veille")) 
 39          def do_ronfle(self): 
 40              print 'fuuuuuuuuuuuu rhhhhhrhrhrrh' 
 41   
 42      cl = BookShell() 
 43  """ 
 44   
 45  __docformat__ = "restructuredtext en" 
 46   
 47  from logilab.common.compat import raw_input, builtins 
 48  if not hasattr(builtins, '_'): 
 49      builtins._ = str 
 50   
 51   
52 -def init_readline(complete_method, histfile=None):
53 """Init the readline library if available.""" 54 try: 55 import readline 56 readline.parse_and_bind("tab: complete") 57 readline.set_completer(complete_method) 58 string = readline.get_completer_delims().replace(':', '') 59 readline.set_completer_delims(string) 60 if histfile is not None: 61 try: 62 readline.read_history_file(histfile) 63 except IOError: 64 pass 65 import atexit 66 atexit.register(readline.write_history_file, histfile) 67 except: 68 print 'readline is not available :-('
69 70
71 -class Completer :
72 """Readline completer.""" 73
74 - def __init__(self, commands):
75 self.list = commands
76
77 - def complete(self, text, state):
78 """Hook called by readline when <tab> is pressed.""" 79 n = len(text) 80 matches = [] 81 for cmd in self.list : 82 if cmd[:n] == text : 83 matches.append(cmd) 84 try: 85 return matches[state] 86 except IndexError: 87 return None
88 89
90 -class CLIHelper:
91 """An abstract command line interface client which recognize commands 92 and provide an help system. 93 """ 94 95 CMD_MAP = {'help': _("Others"), 96 'quit': _("Others"), 97 } 98 CMD_PREFIX = '' 99
100 - def __init__(self, histfile=None) :
101 self._topics = {} 102 self.commands = None 103 self._completer = Completer(self._register_commands()) 104 init_readline(self._completer.complete, histfile)
105
106 - def run(self):
107 """loop on user input, exit on EOF""" 108 while True: 109 try: 110 line = raw_input('>>> ') 111 except EOFError: 112 print 113 break 114 s_line = line.strip() 115 if not s_line: 116 continue 117 args = s_line.split() 118 if args[0] in self.commands: 119 try: 120 cmd = 'do_%s' % self.commands[args[0]] 121 getattr(self, cmd)(*args[1:]) 122 except EOFError: 123 break 124 except: 125 import traceback 126 traceback.print_exc() 127 else: 128 try: 129 self.handle_line(s_line) 130 except: 131 import traceback 132 traceback.print_exc()
133
134 - def handle_line(self, stripped_line):
135 """Method to overload in the concrete class (should handle 136 lines which are not commands). 137 """ 138 raise NotImplementedError()
139 140 141 # private methods ######################################################### 142
143 - def _register_commands(self):
144 """ register available commands method and return the list of 145 commands name 146 """ 147 self.commands = {} 148 self._command_help = {} 149 commands = [attr[3:] for attr in dir(self) if attr[:3] == 'do_'] 150 for command in commands: 151 topic = self.CMD_MAP[command] 152 help_method = getattr(self, 'help_do_%s' % command) 153 self._topics.setdefault(topic, []).append(help_method) 154 self.commands[self.CMD_PREFIX + command] = command 155 self._command_help[command] = help_method 156 return self.commands.keys()
157
158 - def _print_help(self, cmd, syntax, explanation):
159 print _('Command %s') % cmd 160 print _('Syntax: %s') % syntax 161 print '\t', explanation 162 print
163 164 165 # predefined commands ##################################################### 166
167 - def do_help(self, command=None) :
168 """base input of the help system""" 169 if command in self._command_help: 170 self._print_help(*self._command_help[command]) 171 elif command is None or command not in self._topics: 172 print _("Use help <topic> or help <command>.") 173 print _("Available topics are:") 174 topics = sorted(self._topics.keys()) 175 for topic in topics: 176 print '\t', topic 177 print 178 print _("Available commands are:") 179 commands = self.commands.keys() 180 commands.sort() 181 for command in commands: 182 print '\t', command[len(self.CMD_PREFIX):] 183 184 else: 185 print _('Available commands about %s:') % command 186 print 187 for command_help_method in self._topics[command]: 188 try: 189 if callable(command_help_method): 190 self._print_help(*command_help_method()) 191 else: 192 self._print_help(*command_help_method) 193 except: 194 import traceback 195 traceback.print_exc() 196 print 'ERROR in help method %s'% ( 197 command_help_method.func_name)
198 199 help_do_help = ("help", "help [topic|command]", 200 _("print help message for the given topic/command or \ 201 available topics when no argument")) 202
203 - def do_quit(self):
204 """quit the CLI""" 205 raise EOFError()
206
207 - def help_do_quit(self):
208 return ("quit", "quit", _("quit the application"))
209