From 59fdc5b3555ec98b476f8ecc10fe0f48497139e2 Mon Sep 17 00:00:00 2001 From: Jaculabilis Date: Sat, 13 Aug 2022 00:57:05 +0000 Subject: [PATCH] Add a basic reflection-powered cli framework --- server/intake/cli.py | 56 +++++++++++++++++++++++++++++++++++++++++++ server/pyproject.toml | 3 +++ 2 files changed, 59 insertions(+) create mode 100644 server/intake/cli.py diff --git a/server/intake/cli.py b/server/intake/cli.py new file mode 100644 index 0000000..74ed515 --- /dev/null +++ b/server/intake/cli.py @@ -0,0 +1,56 @@ +from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER +import argparse +from signal import signal, SIGPIPE, SIG_DFL +import sys + + +def command_help(args): + """Print this help message and exit.""" + print_usage() + return 0 + + +def main(): + """CLI entry point""" + # Enable piping + signal(SIGPIPE, SIG_DFL) + + # Get the available commands by reflection + cli = sys.modules[__name__] + commands = { + name[8:]: func + for name, func in vars(cli).items() + if name.startswith("command_") + } + descriptions = "\n".join([ + f" {name} - {func.__doc__}" + for name, func in commands.items()]) + + # Set up the top-level parser + parser = ArgumentParser( + description=f"Available commands:\n{descriptions}\n", + formatter_class=RawDescriptionHelpFormatter, + add_help=False) + parser.add_argument("command", + nargs="?", + default="help", + help="The command to execute", + choices=commands, + metavar="command") + parser.add_argument("args", + nargs=argparse.REMAINDER, + help="Command arguments", + metavar="args") + + # Pass the parser's help printer to command_help via global + global print_usage + print_usage = parser.print_help + + args = parser.parse_args() + + # Execute command + if args.command: + sys.exit(commands[args.command](args.args)) + else: + parser.print_usage() + sys.exit(0) diff --git a/server/pyproject.toml b/server/pyproject.toml index 52f4845..7b1bdcb 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -12,6 +12,9 @@ feedparser = "^6.0.10" [tool.poetry.dev-dependencies] +[tool.poetry.scripts] +intake = "intake.cli:main" + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api"