plugins: Refactor plugin identification and access

This change moves all plugin handling code into the kas.plugins module.
New accessor functions `plugins.get(name)` and `plugins.all()` are
provided to wrap the plugins dictionary so that the kas main function
doesn't need to worry about how this is accessed. Plugins are loaded at
runtime rather than at parse time by calling `plugins.load()` which
gives us an improved ability to handle errors.

The `@kasplugin` decorator is removed as it modified and attribute on
the kasplugin function itself when a plugin module was loaded. Importing
a module should not result in changes to a variable in a different
module as it leads to an initialization code flow which is difficult to
reason about. Instead, plugin modules should now list the plugins which
they introduce in a `__KAS_PLUGINS__` list which will be walked at
runtime by `plugins.load()`.

Signed-off-by: Paul Barker <pbarker@konsulko.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
This commit is contained in:
Paul Barker
2020-10-16 19:31:47 +02:00
committed by Jan Kiszka
parent 7b9bce8e46
commit 5e3ca820b3
4 changed files with 44 additions and 24 deletions

View File

@@ -42,15 +42,7 @@ except ImportError:
HAVE_COLORLOG = False
from . import __version__, __file_version__, __compatible_file_version__
# Import kas plugins
# Since they are added by decorators, they don't need to be called,
# just imported.
from .plugins import kasplugin
from .plugins import build
from .plugins import shell
__all__ = ['build', 'shell']
from . import plugins
__license__ = 'MIT'
__copyright__ = 'Copyright (c) Siemens AG, 2017-2018'
@@ -131,7 +123,7 @@ def kas_get_argparser():
subparser = parser.add_subparsers(help='sub command help', dest='cmd')
for plugin in getattr(kasplugin, 'plugins', {}).values():
for plugin in plugins.all():
plugin_parser = subparser.add_parser(plugin.name, help=plugin.helpmsg)
setup_parser_common_args(plugin_parser)
plugin.setup_parser(plugin_parser)
@@ -144,6 +136,7 @@ def kas(argv):
The actual main entry point of kas.
"""
create_logger()
plugins.load()
parser = kas_get_argparser()
args = parser.parse_args(argv)
@@ -159,9 +152,10 @@ def kas(argv):
loop.add_signal_handler(sig, interruption)
atexit.register(_atexit_handler)
if args.cmd:
plugin = getattr(kasplugin, 'plugins', {})[args.cmd]
plugin().run(args)
plugin_class = plugins.get(args.cmd)
if plugin_class:
plugin = plugin_class()
plugin.run(args)
else:
parser.print_help()