98 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import shlex
 | |
| import inspect
 | |
| import sys
 | |
| import importlib
 | |
| import logging
 | |
| 
 | |
| def func_supports_argcount(f, cnt):
 | |
|   argspec = inspect.getargspec(f)
 | |
|   posargs = 0 if argspec.args is None else len(argspec.args) 
 | |
|   if argspec.args[0] == 'self':
 | |
|     posargs = posargs - 1
 | |
|   defargs = 0 if argspec.defaults is None else len(argspec.defaults)
 | |
|   varargs = 0 if argspec.varargs is None else len(argspec.varargs)
 | |
|   minargs = posargs - defargs
 | |
|   maxargs = posargs
 | |
|   if cnt < minargs:
 | |
|     return False
 | |
|   if cnt > maxargs:
 | |
|     return varargs > 0
 | |
|   return True
 | |
|     
 | |
| 
 | |
| class CommandLine:
 | |
|   def __init__(self):
 | |
|     self.reloading = False
 | |
|     self.stopping = False
 | |
|   
 | |
|   def ask_multichoice(self, choices, prompt):
 | |
|     choice = None
 | |
|     while choice not in choices:
 | |
|       choice = input(prompt).lower()
 | |
|     return choice
 | |
|     
 | |
|   def stop(self):
 | |
|     self.stopping = True
 | |
|   
 | |
|   def prompt(self):
 | |
|     return '> '
 | |
|   
 | |
|   def handle_not_found(self, c, args):
 | |
|     print(f'command not found; {c}')
 | |
|   
 | |
|   def handle_error(self, cmd, args, e):
 | |
|     logging.error(e, exc_info=type(e).__name__ not in ['ApiError','CommandError', 'CentralCommandError'])
 | |
|   
 | |
|   def handle_empty(self):
 | |
|     pass
 | |
|   
 | |
|   def after_cmd(self):
 | |
|     pass
 | |
|   
 | |
|   def handle_eof(self):
 | |
|     print('EOF')
 | |
|     
 | |
|   def do_quit(self):
 | |
|     print('byebye!')
 | |
|     self.stopping = True
 | |
|     
 | |
|   def do_reload(self):
 | |
|     self.reloading = True
 | |
|       
 | |
|   def handle_cmd(self, c):
 | |
|     if c == '':
 | |
|       return self.handle_empty()
 | |
|     args = shlex.split(c)
 | |
|     cmd = args.pop(0)
 | |
|     str_handler = f'do_{cmd}'
 | |
|     if not hasattr(self, str_handler):
 | |
|       try:
 | |
|         self.handle_not_found(cmd, args)
 | |
|         return
 | |
|       except Exception as e:
 | |
|         self.handle_error(cmd, args, e)
 | |
|     handler = getattr(self, str_handler)
 | |
|     if not func_supports_argcount(handler, len(args)):
 | |
|       expect_args = ', '.join(inspect.getargspec(handler).args[1:])
 | |
|       print('expected args: ' + expect_args)
 | |
|       return
 | |
|     try:
 | |
|       handler(*args)
 | |
|     except Exception as e:
 | |
|       self.handle_error(cmd, args, e)
 | |
|     self.after_cmd()
 | |
|     
 | |
|   def run(self):
 | |
|     while not self.stopping and not self.reloading:
 | |
|       p = self.prompt()
 | |
|       try:
 | |
|         c = input(p)
 | |
|       except EOFError:
 | |
|         self.handle_eof()
 | |
|         break
 | |
|       try:
 | |
|         self.handle_cmd(c)
 | |
|       except Exception as e:
 | |
|         logging.error(e, exc_info=True)
 | |
|       
 | 
