예제 #1
0
    def __post_plugin_process(self,
                              load_result=None,
                              unload_result=None,
                              reload_result=None):
        """
		When returns, all events / operations are finished processing
		"""
        if load_result is None:
            load_result = SingleOperationResult()
        if unload_result is None:
            unload_result = SingleOperationResult()
        if reload_result is None:
            reload_result = SingleOperationResult()

        dependency_check_result = self.__check_plugin_dependencies()
        self.last_operation_result.record(load_result, unload_result,
                                          reload_result,
                                          dependency_check_result)

        # Expected plugin states:
        # 					success_list		fail_list
        # load_result		LOADED				N/A
        # unload_result		UNLOADING			UNLOADING
        # reload_result		READY				UNLOADING
        # dep_chk_result	LOADED / READY		UNLOADING

        self.registry_storage.clear(
        )  # in case plugin invokes dispatch_event during on_load. dont let them trigger listeners

        newly_loaded_plugins = {
            *load_result.success_list, *reload_result.success_list
        }
        for plugin in dependency_check_result.success_list:
            if plugin in newly_loaded_plugins:
                plugin.ready()

        for plugin in dependency_check_result.success_list:
            if plugin in newly_loaded_plugins:
                if isinstance(plugin, RegularPlugin):
                    plugin.receive_event(MCDRPluginEvents.PLUGIN_LOADED,
                                         (plugin.old_entry_module_instance, ))

        for plugin in unload_result.success_list + unload_result.failed_list + reload_result.failed_list + dependency_check_result.failed_list:
            plugin.assert_state({PluginState.UNLOADING})
            # plugins might just be newly loaded but failed on dependency check, dont dispatch event to them
            if plugin not in newly_loaded_plugins:
                plugin.receive_event(MCDRPluginEvents.PLUGIN_UNLOADED, ())
            # plugin.receive_event(MCDRPluginEvents.PLUGIN_REMOVED, ())
            plugin.remove()

        # they should be
        for plugin in self.get_regular_plugins():
            plugin.assert_state({PluginState.READY})

        self.__update_registry()
        self.__sort_plugins_by_id()
예제 #2
0
 def __reload_ready_plugins(
         self,
         filter: Callable[[RegularPlugin], bool],
         specific: Optional[RegularPlugin] = None) -> SingleOperationResult:
     result = SingleOperationResult()
     plugin_list = self.get_regular_plugins() if specific is None else [
         specific
     ]
     for plugin in plugin_list:
         if plugin.in_states({PluginState.READY}) and filter(plugin):
             result.record(plugin, self.__reload_plugin(plugin))
     return result
예제 #3
0
 def __collect_and_remove_plugins(
         self,
         filter: Callable[[RegularPlugin], bool],
         specific: Optional[RegularPlugin] = None) -> SingleOperationResult:
     result = SingleOperationResult()
     plugin_list = self.get_regular_plugins() if specific is None else [
         specific
     ]
     for plugin in plugin_list:
         if filter(plugin):
             result.record(plugin, self.__unload_plugin(plugin))
     return result
예제 #4
0
    def __post_plugin_process(self,
                              load_result=None,
                              unload_result=None,
                              reload_result=None):
        if load_result is None:
            load_result = SingleOperationResult()
        if unload_result is None:
            unload_result = SingleOperationResult()
        if reload_result is None:
            reload_result = SingleOperationResult()

        dependency_check_result = self.check_plugin_dependencies()
        self.last_operation_result.record(load_result, unload_result,
                                          reload_result,
                                          dependency_check_result)

        # Expected plugin states:
        # 					success_list		fail_list
        # load_result		LOADED				N/A
        # unload_result		UNLOADING			UNLOADING
        # reload_result		READY				UNLOADING
        # dep_chk_result	LOADED / READY		UNLOADING

        for plugin in load_result.success_list + reload_result.success_list:
            if plugin in dependency_check_result.success_list:
                plugin.ready()

        newly_loaded_plugins = {
            *load_result.success_list, *reload_result.success_list
        }
        for plugin in dependency_check_result.success_list:
            if plugin in newly_loaded_plugins:
                if isinstance(plugin, RegularPlugin):
                    plugin.receive_event(MCDRPluginEvents.PLUGIN_LOAD,
                                         (plugin.old_module_instance, ))

        for plugin in unload_result.success_list + unload_result.failed_list + reload_result.failed_list + dependency_check_result.failed_list:
            plugin.assert_state({PluginState.UNLOADING})
            # plugins might just be newly loaded but failed on dependency check, dont dispatch event to them
            if plugin not in load_result.success_list:
                plugin.receive_event(MCDRPluginEvents.PLUGIN_UNLOAD, ())
            plugin.remove()

        # they should be
        for plugin in self.get_regular_plugins():
            plugin.assert_state({PluginState.READY})

        self.__update_registry()
예제 #5
0
 def check_plugin_dependencies(self) -> SingleOperationResult:
     result = SingleOperationResult()
     walker = DependencyWalker(self)
     for item in walker.walk():
         plugin = self.plugins.get(item.plugin_id)  # should be not None
         result.record(plugin, item.success)
         if not item.success:
             self.logger.error(
                 self.mcdr_server.tr(
                     'plugin_manager.check_plugin_dependencies.item_failed',
                     plugin, item.reason))
             self.__unload_plugin(plugin)
     self.logger.debug(self.mcdr_server.tr(
         'plugin_manager.check_plugin_dependencies.topo_order'),
                       option=DebugOption.PLUGIN)
     for plugin in result.success_list:
         self.logger.debug('- {}'.format(plugin), option=DebugOption.PLUGIN)
     # the success list order matches the dependency topo order
     return result
예제 #6
0
    def __check_if_success(self, operation_result: SingleOperationResult,
                           check_loaded: bool) -> bool:
        """
		Check if there's any plugin inside the given operation result (load result / reload result etc.)
		Then check if the plugin passed the dependency check if param check_loaded is True
		"""
        success = operation_result.has_success()
        if success and check_loaded:
            plugin = operation_result.success_list[0]
            success = plugin in self.__mcdr_server.plugin_manager.last_operation_result.dependency_check_result.success_list
        return success
예제 #7
0
 def __collect_and_process_new_plugins(
         self, filter: Callable[[str], bool]) -> SingleOperationResult:
     result = SingleOperationResult()
     for plugin_directory in self.plugin_directories:
         file_list = file_util.list_file_with_suffix(
             plugin_directory, constant.PLUGIN_FILE_SUFFIX)
         for file_path in file_list:
             if not self.contains_plugin_file(file_path) and filter(
                     file_path):
                 plugin = self.__load_plugin(file_path)
                 if plugin is None:
                     result.fail(file_path)
                 else:
                     result.succeed(plugin)
     return result
예제 #8
0
 def __collect_and_process_new_plugins(
         self, filter: Callable[[str], bool]) -> SingleOperationResult:
     result = SingleOperationResult()
     for plugin_directory in self.plugin_directories:
         if os.path.isdir(plugin_directory):
             for file in os.listdir(plugin_directory):
                 file_path = os.path.join(plugin_directory, file)
                 if plugin_factory.maybe_plugin(file_path):
                     if not self.contains_plugin_file(file_path) and filter(
                             file_path):
                         plugin = self.__load_plugin(file_path)
                         if plugin is None:
                             result.fail(file_path)
                         else:
                             result.succeed(plugin)
         else:
             self.logger.warning(
                 'Plugin directory "{}" not found'.format(plugin_directory))
     return result
예제 #9
0
    def __collect_and_process_new_plugins(
            self,
            filter: Callable[[str], bool],
            *,
            possible_paths: Optional[List[str]] = None
    ) -> SingleOperationResult:
        """
		:param filter: A str predicate function for testing if the plugin file path is acceptable
		:param possible_paths: Optional. If you have already done self.__collect_possible_plugin_file_paths() before,
		you can pass the previous result as the argument to reuse that, so less time cost
		"""
        if possible_paths is None:
            possible_paths = self.__collect_possible_plugin_file_paths()

        result = SingleOperationResult()
        for file_path in possible_paths:
            if not self.contains_plugin_file(file_path) and filter(file_path):
                plugin = self.__load_plugin(file_path)
                if plugin is None:
                    result.fail(file_path)
                else:
                    result.succeed(plugin)
        return result