Added support for loading extensions

This patch adds support for loading extenions
to APRSD!!

You can create another separate aprsd project, and register
your extension in your setup.cfg as a new entry point for aprsd
like

[entry_points]
aprsd.extension =
    cool = my_project.extension

in your my_project/extension.py file
import your commmands and away you go.
This commit is contained in:
Hemna 2024-02-23 16:53:42 -05:00
parent ebee8e1439
commit b14307270c
3 changed files with 65 additions and 4 deletions

View File

@ -50,6 +50,43 @@ common_options = [
]
import click
class AliasedGroup(click.Group):
def command(self, *args, **kwargs):
"""A shortcut decorator for declaring and attaching a command to
the group. This takes the same arguments as :func:`command` but
immediately registers the created command with this instance by
calling into :meth:`add_command`.
Copied from `click` and extended for `aliases`.
"""
def decorator(f):
aliases = kwargs.pop('aliases', [])
cmd = click.decorators.command(*args, **kwargs)(f)
self.add_command(cmd)
for alias in aliases:
self.add_command(cmd, name=alias)
return cmd
return decorator
def group(self, *args, **kwargs):
"""A shortcut decorator for declaring and attaching a group to
the group. This takes the same arguments as :func:`group` but
immediately registers the created command with this instance by
calling into :meth:`add_command`.
Copied from `click` and extended for `aliases`.
"""
def decorator(f):
aliases = kwargs.pop('aliases', [])
cmd = click.decorators.group(*args, **kwargs)(f)
self.add_command(cmd)
for alias in aliases:
self.add_command(cmd, name=alias)
return cmd
return decorator
def add_options(options):
def _add_options(func):
for option in reversed(options):

View File

@ -59,20 +59,25 @@ click_completion.core.startswith = custom_startswith
click_completion.init()
@click.group(context_settings=CONTEXT_SETTINGS)
@click.group(cls=cli_helper.AliasedGroup, context_settings=CONTEXT_SETTINGS)
@click.version_option()
@click.pass_context
def cli(ctx):
pass
def main():
# First import all the possible commands for the CLI
# The commands themselves live in the cmds directory
def load_commands():
from .cmds import ( # noqa
completion, dev, fetch_stats, healthcheck, list_plugins, listen,
send_message, server, webchat,
)
def main():
# First import all the possible commands for the CLI
# The commands themselves live in the cmds directory
load_commands()
utils.load_entry_points("aprsd.extension")
cli(auto_envvar_prefix="APRSD")

View File

@ -4,6 +4,7 @@ import errno
import os
import re
import sys
import traceback
import update_checker
@ -131,3 +132,21 @@ def parse_delta_str(s):
return {key: float(val) for key, val in m.groupdict().items()}
else:
return {}
def load_entry_points(group):
"""Load all extensions registered to the given entry point group"""
print(f"Loading extensions for group {group}")
try:
import importlib_metadata
except ImportError:
# For python 3.10 and later
import importlib.metadata as importlib_metadata
eps = importlib_metadata.entry_points(group=group)
for ep in eps:
try:
ep.load()
except Exception as e:
print(f"Extension {ep.name} of group {group} failed to load with {e}", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)