from typing import Dict, List from plugins import AbstractPlugin, AbstractCommandCompiler import logging class ConflictingPlugins(BaseException): pass class PluginRepository: def __init__(self): self._registered_plugins: Dict[str, type(AbstractPlugin)] = {} self._loaded_plugins: Dict[str, AbstractPlugin] = {} self._command_compilers: Dict[str, AbstractCommandCompiler] = {} self._logger = logging.getLogger("plugin_repository") def register_plugin(self, plugin_class: type(AbstractPlugin)): self._registered_plugins[plugin_class.plugin_name] = plugin_class self._logger.debug(f"Registered plugin: {plugin_class.plugin_name}") def load_plugin(self, plugin: str): if plugin in self._loaded_plugins.keys(): self._logger.warning(f"Plugin {plugin} already loaded!") return # create instance plugin_instance = self._registered_plugins[plugin]() # config is statically loaded # load compilers compilers = plugin_instance.load_compilers() if set(compilers.keys()).intersection(self._command_compilers.keys()): plugin_instance.close() # The program should stop at this point anyways raise ConflictingPlugins(f"Conflicting plugin is tried to be loaded: {plugin}") # Store commands self._command_compilers.update(compilers) # store instance self._loaded_plugins[plugin] = plugin_instance # log stuff self._logger.info(f"Loaded plugin: {plugin}") self._logger.debug(f"Plugin {plugin} loaded the following commands: {', '.join(compilers.keys())}") def get_compiler(self, command: str) -> AbstractCommandCompiler: return self._command_compilers[command] def get_plugin_instance(self, plugin: str) -> AbstractPlugin: return self._loaded_plugins[plugin] def close(self): self._command_compilers = {} for plugin_name, plugin_instance in self._loaded_plugins.items(): plugin_instance.close() self._logger.info(f"Unloaded plugin: {plugin_name}")