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

Source Code for Module logilab.common.cli

  1  # copyright 2003-2010 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   
 46   
 47  """ 
 48  __docformat__ = "restructuredtext en" 
 49   
 50  import __builtin__ 
 51  if not hasattr(__builtin__, '_'): 
 52      __builtin__._ = str 
 53   
 54   
55 -def init_readline(complete_method, histfile=None):
56 """Init the readline library if available.""" 57 try: 58 import readline 59 readline.parse_and_bind("tab: complete") 60 readline.set_completer(complete_method) 61 string = readline.get_completer_delims().replace(':', '') 62 readline.set_completer_delims(string) 63 if histfile is not None: 64 try: 65 readline.read_history_file(histfile) 66 except IOError: 67 pass 68 import atexit 69 atexit.register(readline.write_history_file, histfile) 70 except: 71 print 'readline is not available :-('
72 73
74 -class Completer :
75 """Readline completer.""" 76
77 - def __init__(self, commands):
78 self.list = commands
79
80 - def complete(self, text, state):
81 """Hook called by readline when <tab> is pressed.""" 82 n = len(text) 83 matches = [] 84 for cmd in self.list : 85 if cmd[:n] == text : 86 matches.append(cmd) 87 try: 88 return matches[state] 89 except IndexError: 90 return None
91 92
93 -class CLIHelper:
94 """An abstract command line interface client which recognize commands 95 and provide an help system. 96 """ 97 98 CMD_MAP = {'help' : _("Others"), 99 'quit' : _("Others"), 100 } 101 CMD_PREFIX = '' 102
103 - def __init__(self, histfile=None) :
104 self._topics = {} 105 self.commands = None 106 self._completer = Completer(self._register_commands()) 107 init_readline(self._completer.complete, histfile)
108
109 - def run(self):
110 """loop on user input, exit on EOF""" 111 while 1: 112 try: 113 line = raw_input('>>> ') 114 except EOFError: 115 print 116 break 117 s_line = line.strip() 118 if not s_line: 119 continue 120 args = s_line.split() 121 if args[0] in self.commands: 122 try: 123 cmd = 'do_%s' % self.commands[args[0]] 124 getattr(self, cmd)(*args[1:]) 125 except EOFError: 126 break 127 except: 128 import traceback 129 traceback.print_exc() 130 else: 131 try: 132 self.handle_line(s_line) 133 except: 134 import traceback 135 traceback.print_exc()
136
137 - def handle_line(self, stripped_line):
138 """Method to overload in the concrete class (should handle 139 lines which are not commands). 140 """ 141 raise NotImplementedError()
142 143 144 # private methods ######################################################### 145
146 - def _register_commands(self):
147 """ register available commands method and return the list of 148 commands name 149 """ 150 self.commands = {} 151 self._command_help = {} 152 commands = [attr[3:] for attr in dir(self) if attr[:3] == 'do_'] 153 for command in commands: 154 topic = self.CMD_MAP[command] 155 help_method = getattr(self, 'help_do_%s' % command) 156 self._topics.setdefault(topic, []).append(help_method) 157 self.commands[self.CMD_PREFIX + command] = command 158 self._command_help[command] = help_method 159 return self.commands.keys()
160
161 - def _print_help(self, cmd, syntax, explanation):
162 print _('Command %s') % cmd 163 print _('Syntax: %s') % syntax 164 print '\t', explanation 165 print
166 167 168 # predefined commands ##################################################### 169
170 - def do_help(self, command=None) :
171 """base input of the help system""" 172 if command in self._command_help: 173 self._print_help(*self._command_help[command]) 174 elif command is None or command not in self._topics: 175 print _("Use help <topic> or help <command>.") 176 print _("Available topics are:") 177 topics = self._topics.keys() 178 topics.sort() 179 for topic in topics: 180 print '\t', topic 181 print 182 print _("Available commands are:") 183 commands = self.commands.keys() 184 commands.sort() 185 for command in commands: 186 print '\t', command[len(self.CMD_PREFIX):] 187 188 else: 189 print _('Available commands about %s:') % command 190 print 191 for command_help_method in self._topics[command]: 192 try: 193 if callable(command_help_method): 194 self._print_help(*command_help_method()) 195 else: 196 self._print_help(*command_help_method) 197 except: 198 import traceback 199 traceback.print_exc() 200 print 'ERROR in help method %s'% ( 201 command_help_method.func_name)
202 203 help_do_help = ("help", "help [topic|command]", 204 _("print help message for the given topic/command or \ 205 available topics when no argument")) 206
207 - def do_quit(self):
208 """quit the CLI""" 209 raise EOFError()
210
211 - def help_do_quit(self):
212 return ("quit", "quit", _("quit the application"))
213