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:
parent
7b9bce8e46
commit
5e3ca820b3
20
kas/kas.py
20
kas/kas.py
@ -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()
|
||||
|
||||
|
@ -23,13 +23,37 @@
|
||||
This module contains and manages kas plugins
|
||||
"""
|
||||
|
||||
PLUGINS = {}
|
||||
|
||||
def kasplugin(plugin_class):
|
||||
|
||||
def register_plugins(mod):
|
||||
"""
|
||||
A decorator that registers kas plugins
|
||||
Register all kas plugins found in a module
|
||||
"""
|
||||
if not hasattr(kasplugin, 'plugins'):
|
||||
setattr(kasplugin, 'plugins', {})
|
||||
getattr(kasplugin, 'plugins').update({
|
||||
plugin_class.name: plugin_class
|
||||
})
|
||||
for plugin in getattr(mod, '__KAS_PLUGINS__', []):
|
||||
PLUGINS[plugin.name] = plugin
|
||||
|
||||
|
||||
def load():
|
||||
"""
|
||||
Import all kas plugins
|
||||
"""
|
||||
from . import build
|
||||
from . import shell
|
||||
|
||||
register_plugins(build)
|
||||
register_plugins(shell)
|
||||
|
||||
|
||||
def get(name):
|
||||
"""
|
||||
Lookup a kas plugin class by name
|
||||
"""
|
||||
return PLUGINS.get(name, None)
|
||||
|
||||
|
||||
def all():
|
||||
"""
|
||||
Get a list of all loaded kas plugin classes
|
||||
"""
|
||||
return PLUGINS.values()
|
||||
|
@ -35,13 +35,11 @@ from kas.libcmds import (Macro, Command, SetupDir, CleanupSSHAgent,
|
||||
WriteBBConfig, SetupHome, ReposApplyPatches,
|
||||
Loop, InitSetupRepos, FinishSetupRepos,
|
||||
SetupReposStep)
|
||||
from kas.plugins import kasplugin
|
||||
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) Siemens AG, 2017-2018'
|
||||
|
||||
|
||||
@kasplugin
|
||||
class Build:
|
||||
"""
|
||||
This class implements the build plugin for kas.
|
||||
@ -135,3 +133,6 @@ class BuildCommand(Command):
|
||||
sys.exit(ret)
|
||||
else:
|
||||
run_cmd(cmd, cwd=ctx.build_dir)
|
||||
|
||||
|
||||
__KAS_PLUGINS__ = [Build]
|
||||
|
@ -35,13 +35,11 @@ from kas.libcmds import (Macro, Command, SetupDir, SetupEnviron,
|
||||
CleanupSSHAgent, SetupSSHAgent,
|
||||
Loop, InitSetupRepos, FinishSetupRepos,
|
||||
SetupReposStep)
|
||||
from kas.plugins import kasplugin
|
||||
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) Siemens AG, 2017-2018'
|
||||
|
||||
|
||||
@kasplugin
|
||||
class Shell:
|
||||
"""
|
||||
Implements a kas plugin that opens a shell within the kas environment.
|
||||
@ -129,3 +127,6 @@ class ShellCommand(Command):
|
||||
if ret != 0:
|
||||
logging.error('Shell returned non-zero exit status %d', ret)
|
||||
sys.exit(ret)
|
||||
|
||||
|
||||
__KAS_PLUGINS__ = [Shell]
|
||||
|
Loading…
Reference in New Issue
Block a user