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)
|
|
|