2022-08-19 17:53:59 +00:00
|
|
|
import inspect
|
2022-08-19 11:02:37 +00:00
|
|
|
import os
|
|
|
|
import vultron.api
|
2022-08-19 17:53:59 +00:00
|
|
|
import vultron.display
|
|
|
|
import vultron.err
|
2022-08-19 11:02:37 +00:00
|
|
|
|
2022-08-19 17:53:59 +00:00
|
|
|
class CmdNotFound(vultron.err.Error):
|
2022-08-19 11:02:37 +00:00
|
|
|
def __str__(self):
|
2022-08-19 17:53:59 +00:00
|
|
|
return f"command not found: {self.args[0]}"
|
2022-08-18 09:55:13 +00:00
|
|
|
|
2022-08-19 17:53:59 +00:00
|
|
|
class FeatureMissing(vultron.err.Error):
|
|
|
|
def __str__(self):
|
|
|
|
return f"feature not yet implemented: {self.args[0]}"
|
|
|
|
|
|
|
|
class NoApiKey(vultron.err.Error):
|
|
|
|
def __str__(self):
|
|
|
|
return f"no api key provided"
|
2022-08-18 09:55:13 +00:00
|
|
|
|
2022-08-19 17:53:59 +00:00
|
|
|
class NotEnoughArgs(vultron.err.Error):
|
|
|
|
def __str__(self):
|
|
|
|
name = self.args[0]
|
|
|
|
more = self.args[1]
|
2022-08-18 09:55:13 +00:00
|
|
|
|
2022-08-19 17:53:59 +00:00
|
|
|
if self.args[1] > 1:
|
|
|
|
return f"sub-command requires {more} more arguments: {name}"
|
|
|
|
else:
|
|
|
|
return f"sub-command requires 1 more argument: {name}"
|
|
|
|
|
|
|
|
# FIXME: Handle paging
|
2022-08-18 09:55:13 +00:00
|
|
|
class Command:
|
2022-08-19 11:02:37 +00:00
|
|
|
"""A nop Vultron command. This feature is not implemented yet."""
|
|
|
|
|
2022-08-18 09:55:13 +00:00
|
|
|
FTR_PRFX = "vultron_"
|
|
|
|
|
2022-08-19 11:02:37 +00:00
|
|
|
def __init__(self, prog, api_key, out):
|
|
|
|
self.prog = prog
|
|
|
|
self.out = out
|
2022-08-20 02:02:51 +00:00
|
|
|
self.needs_api_key = True
|
2022-08-18 09:55:13 +00:00
|
|
|
self.default = "help"
|
|
|
|
|
2022-08-20 09:54:41 +00:00
|
|
|
# FIXME: add support for argument parsing
|
|
|
|
|
2022-08-18 09:55:13 +00:00
|
|
|
self.init()
|
|
|
|
|
2022-08-20 02:02:51 +00:00
|
|
|
if self.needs_api_key and api_key is None:
|
2022-08-18 09:55:13 +00:00
|
|
|
raise NoApiKey()
|
|
|
|
|
2022-08-19 11:02:37 +00:00
|
|
|
self.api = vultron.api.Client(api_key)
|
|
|
|
|
2022-08-19 17:53:59 +00:00
|
|
|
def exec_shortcut(self, shortcut, *args):
|
|
|
|
fn = self.find(shortcut)
|
|
|
|
sig = inspect.signature(fn)
|
2022-08-20 09:54:41 +00:00
|
|
|
parity = len(sig.parameters)
|
2022-08-19 17:53:59 +00:00
|
|
|
|
2022-08-20 09:54:41 +00:00
|
|
|
if len(args) < parity:
|
2022-08-19 17:53:59 +00:00
|
|
|
name = fn.__name__[len(self.FTR_PRFX):].lower()
|
2022-08-20 09:54:41 +00:00
|
|
|
raise NotEnoughArgs(name, parity - len(args))
|
2022-08-19 17:53:59 +00:00
|
|
|
|
2022-08-20 09:54:41 +00:00
|
|
|
data = fn(*args[:parity])
|
2022-08-19 17:53:59 +00:00
|
|
|
|
2022-08-20 02:02:51 +00:00
|
|
|
# FIXME: Let functions choose the output format. This will allow help
|
|
|
|
# functions to still return a rendering.
|
2022-08-19 17:53:59 +00:00
|
|
|
if data is not None:
|
|
|
|
display = vultron.display.FORMATS[self.out](data)
|
|
|
|
print(display.render())
|
2022-08-18 09:55:13 +00:00
|
|
|
|
|
|
|
def find(self, name):
|
2022-08-19 11:02:37 +00:00
|
|
|
needle = f"{self.FTR_PRFX}{name}".lower()
|
2022-08-18 09:55:13 +00:00
|
|
|
haystack = dir(self)
|
|
|
|
|
|
|
|
for legume in haystack:
|
|
|
|
if legume.lower().startswith(needle):
|
|
|
|
fn = getattr(self, legume)
|
|
|
|
|
|
|
|
if callable(fn):
|
|
|
|
return fn
|
|
|
|
else:
|
|
|
|
raise FeatureMissing(legume)
|
|
|
|
|
|
|
|
raise CmdNotFound(name)
|
|
|
|
|
2022-08-19 17:53:59 +00:00
|
|
|
def init(self):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def vultron_help(self):
|
2022-08-19 11:02:37 +00:00
|
|
|
"""This help message."""
|
|
|
|
|
|
|
|
prog = os.path.basename(self.prog)
|
|
|
|
cmd = type(self).__name__.lower()
|
|
|
|
subs = dir(self)
|
|
|
|
|
|
|
|
print(f"usage: {prog} [options] {cmd} <sub-command>")
|
|
|
|
print()
|
|
|
|
print("About:")
|
|
|
|
|
|
|
|
if self.__doc__ is None:
|
|
|
|
print(Command.__doc__)
|
|
|
|
else:
|
|
|
|
print(self.__doc__)
|
|
|
|
|
|
|
|
print()
|
|
|
|
# FIXME: print global options here
|
|
|
|
print("Sub-commands:")
|
|
|
|
|
|
|
|
for sub in subs:
|
|
|
|
name = sub.lower()
|
|
|
|
|
|
|
|
if name.startswith(self.FTR_PRFX):
|
|
|
|
name = name[len(self.FTR_PRFX):]
|
|
|
|
fn = getattr(self, sub)
|
|
|
|
|
|
|
|
if callable(fn):
|
|
|
|
desc = name
|
|
|
|
|
|
|
|
if fn.__doc__ is not None:
|
|
|
|
desc += f" - {fn.__doc__}"
|
|
|
|
|
|
|
|
print(f"\t{desc}")
|
2022-08-18 09:55:13 +00:00
|
|
|
|
|
|
|
def find_cmd(needle):
|
|
|
|
needle = needle.lower()
|
|
|
|
haystack = Command.__subclasses__()
|
|
|
|
|
|
|
|
for legume in haystack:
|
|
|
|
if legume.__name__.lower().startswith(needle):
|
|
|
|
return legume
|
|
|
|
|
|
|
|
raise CmdNotFound(needle)
|