RPKI Engine 1.0
|
00001 """ 00002 Utilities for writing command line tools. 00003 00004 $Id: cli.py 3255 2010-05-20 03:03:48Z sra $ 00005 00006 Copyright (C) 2010 Internet Systems Consortium ("ISC") 00007 00008 Permission to use, copy, modify, and distribute this software for any 00009 purpose with or without fee is hereby granted, provided that the above 00010 copyright notice and this permission notice appear in all copies. 00011 00012 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 00013 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00014 AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 00015 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00016 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00017 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00018 PERFORMANCE OF THIS SOFTWARE. 00019 """ 00020 00021 import cmd, glob, os.path, traceback 00022 00023 try: 00024 import readline 00025 have_readline = True 00026 except ImportError: 00027 have_readline = False 00028 00029 class Cmd(cmd.Cmd): 00030 """ 00031 Customized subclass of Python cmd module. 00032 """ 00033 00034 emptyline_repeats_last_command = False 00035 00036 EOF_exits_command_loop = True 00037 00038 identchars = cmd.IDENTCHARS + "/-." 00039 00040 histfile = None 00041 00042 def __init__(self, argv = None): 00043 cmd.Cmd.__init__(self) 00044 if argv: 00045 self.onecmd(" ".join(argv)) 00046 else: 00047 self.cmdloop_with_history() 00048 00049 def onecmd(self, line): 00050 """ 00051 Wrap error handling around cmd.Cmd.onecmd(). Might want to do 00052 something kinder than showing a traceback, eventually. 00053 """ 00054 try: 00055 return cmd.Cmd.onecmd(self, line) 00056 except SystemExit: 00057 raise 00058 except: 00059 traceback.print_exc() 00060 00061 def do_EOF(self, arg): 00062 """ 00063 Exit program. 00064 """ 00065 if self.EOF_exits_command_loop and self.prompt: 00066 print 00067 return self.EOF_exits_command_loop 00068 00069 def do_exit(self, arg): 00070 """ 00071 Exit program. 00072 """ 00073 return True 00074 00075 do_quit = do_exit 00076 00077 def emptyline(self): 00078 """ 00079 Handle an empty line. cmd module default is to repeat the last 00080 command, which I find to be violation of the principal of least 00081 astonishment, so my preference is that an empty line does nothing. 00082 """ 00083 if self.emptyline_repeats_last_command: 00084 cmd.Cmd.emptyline(self) 00085 00086 def filename_complete(self, text, line, begidx, endidx): 00087 """ 00088 Filename completion handler, with hack to restore what I consider 00089 the normal (bash-like) behavior when one hits the completion key 00090 and there's only one match. 00091 """ 00092 result = glob.glob(text + "*") 00093 if len(result) == 1: 00094 path = result.pop() 00095 if os.path.isdir(path) or (os.path.islink(path) and os.path.isdir(os.path.join(path, "."))): 00096 result.append(path + os.path.sep) 00097 else: 00098 result.append(path + " ") 00099 return result 00100 00101 def completenames(self, text, *ignored): 00102 """ 00103 Command name completion handler, with hack to restore what I 00104 consider the normal (bash-like) behavior when one hits the 00105 completion key and there's only one match. 00106 """ 00107 result = set(cmd.Cmd.completenames(self, text, *ignored)) 00108 if len(result) == 1: 00109 result.add(result.pop() + " ") 00110 return list(result) 00111 00112 def help_help(self): 00113 """ 00114 Type "help [topic]" for help on a command, 00115 or just "help" for a list of commands. 00116 """ 00117 self.stdout.write(self.help_help.__doc__ + "\n") 00118 00119 def complete_help(self, *args): 00120 """ 00121 Better completion function for help command arguments. 00122 """ 00123 text = args[0] 00124 names = self.get_names() 00125 result = [] 00126 for prefix in ("do_", "help_"): 00127 result.extend(s[len(prefix):] for s in names if s.startswith(prefix + text)) 00128 return result 00129 00130 if have_readline: 00131 00132 def cmdloop_with_history(self): 00133 """ 00134 Better command loop, with history file and tweaked readline 00135 completion delimiters. 00136 """ 00137 old_completer_delims = readline.get_completer_delims() 00138 if self.histfile is not None: 00139 try: 00140 readline.read_history_file(self.histfile) 00141 except IOError: 00142 pass 00143 try: 00144 readline.set_completer_delims("".join(set(old_completer_delims) - set(self.identchars))) 00145 self.cmdloop() 00146 finally: 00147 if self.histfile is not None and readline.get_current_history_length(): 00148 readline.write_history_file(self.histfile) 00149 readline.set_completer_delims(old_completer_delims) 00150 00151 else: 00152 00153 cmdloop_with_history = cmd.Cmd.cmdloop 00154 00155 00156 00157 def yes_or_no(prompt, default = None, require_full_word = False): 00158 """ 00159 Ask a yes-or-no question. 00160 """ 00161 prompt = prompt.rstrip() + _yes_or_no_prompts[default] 00162 while True: 00163 answer = raw_input(prompt).strip().lower() 00164 if not answer and default is not None: 00165 return default 00166 if answer == "yes" or (not require_full_word and answer.startswith("y")): 00167 return True 00168 if answer == "no" or (not require_full_word and answer.startswith("n")): 00169 return False 00170 print 'Please answer "yes" or "no"' 00171 00172 _yes_or_no_prompts = { 00173 True : ' ("yes" or "no" ["yes"]) ', 00174 False : ' ("yes" or "no" ["no"]) ', 00175 None : ' ("yes" or "no") ' } 00176