diff --git a/soypak/cli/command.py b/soypak/cli/command.py new file mode 100644 index 0000000..531241b --- /dev/null +++ b/soypak/cli/command.py @@ -0,0 +1,58 @@ +import argparse +import sys +import soypak.cli.parser as parser + + +class RegisterCommand(type): + """Register a new command to soypak and add help information to the parser. + + This class is to be used as metaclass for commands. + """ + def __init__(cls, name, bases, _dict): + super().__init__(name, bases, _dict) + # get the name of the command + name = getattr(cls, "__cmd_name__", None) + if name is None: + raise Exception("Command has no registered name.") + + # check if the command already exists (means we have duplicate registered name) + if name in Command.registered_cmds: + raise Exception("Duplicate command, already exists.") + + # add the command to the registered list, with `name` and class object + Command.registered_cmds[name] = cls + # fetch the documentation for the command + _help = cls.__doc__ + if not _help: + raise Exception("Command does not provide a __doc__ attribute for usage.") + # add the command to the argparse._action_groups list (will appear as a positional in help message) + parser.SoypakParser.add_action_command(cmd=name, help=_help.split('\n')[0]) + + +class Command: + """Class for creating a new type of command. Keep record of the registered commands for soypak.""" + # store all registered commands. Those are commands which soypak implements + registered_cmds: dict[str, RegisterCommand] = {} + + def __init__(self) -> None: + # get/create the parser instance + self.parser = parser.SoypakParser() + + + @staticmethod + def get_command(name, *, args: list[str]) -> RegisterCommand | None: + """Fetch and initialise a registered command, or return `None` is command cannot be found.""" + return ( + Command.registered_cmds[name](data=parser.SoypakParser().namespace, args=args) if name in + Command.registered_cmds else None + ) + + + def die(self): + """System exit with status code 0""" + sys.exit(0) + + + def run(self): + """Virtual method which must be overridden by a new implementation in the child class.""" + raise RuntimeError("Virtual method must be overridden by child class.")