def __init__(self, dirs=None, blacklist=[]): if dirs: self.dirs.extend(dirs) self.blacklist.extend(blacklist) self.messaging = PluginMessageSystem()
class PluginManager: dirs = [] messaging = None blacklist = [] _plugins = [] _active = {} def __init__(self, dirs=None, blacklist=[]): if dirs: self.dirs.extend(dirs) self.blacklist.extend(blacklist) self.messaging = PluginMessageSystem() def get_plugins(self): ''' returns list of plugins that can be loaded ''' if not self._plugins: self.refresh_plugins_list() return self._plugins def load(self, plugin_data, register_channels=True): ''' loads a plugin ''' logger.debug('Attempting to load plugin: ' + plugin_data.name) if plugin_data.name in self.blacklist: logger.info('Plugin is blacklisted: ' + plugin_data.name) return None loaded = False if plugin_data.name in self._active: logger.warning(plugin_data.name + ' is already loaded!') loaded = True try: if loaded: plugin = self._active[plugin_data.name] else: logger.debug('Loading module: ' + plugin_data.module); module = imp.load_module(plugin_data.module, *imp.find_module(plugin_data.module, [plugin_data.location])) logger.debug('Loading dependencies...'); depend = plugin_data.dependencies if depend: for p in depend: logger.debug(plugin_data.name + ' depends on ' + p) if not self.load_by_name(p): logger.warning('Unable to satisfy the dependencies for ' + plugin_data.name) logger.warning('Unable to load plugin: ' + plugin_data.name) return None logger.debug('Initializing plugin ' + plugin_data.name + '...'); plugin = module.Plugin() logger.debug('Starting plugin ' + plugin_data.name + '...'); plugin.__thread = Thread(target=lambda: self._start(plugin, plugin_data.name)) plugin.__thread.start() self._active[plugin_data.name] = plugin logger.debug('Registering ' + plugin_data.name + ' to channels...'); if register_channels: for c in plugin_data.channels: self.messaging.register_plugin(plugin, c) except Exception as e: logger.warning('Unable to load plugin: ' + plugin_data.name) logger.warning(e) return None return plugin def unload(self, name): ''' unloads a plugin ''' logger.debug('Attempting to unload plugin: ' + name + '...') if not name in self._active: logger.error('Plugin ' + name + ' nonexistent or inactive!') return plugin = self._active[name] del self._active[name] self.messaging.unregister_plugin(plugin) plugin.plugin_destroy() plugin.__thread.join(1) plugin.context = None logger.info('Unloaded plugin') def load_by_role(self, role): ''' loads a plugin ''' logger.debug('Finding plugin for role: ' + role) # Get plugins that satisfy this role candidate_plugins = [] for p in self.get_plugins(): if role in p.channels: candidate_plugins.append(p) if not candidate_plugins: logger.error('No plugin loaded for role: ' + role) return None logger.debug('Found: ' + ', '.join(map((lambda p: p.name), candidate_plugins))) # Sort by descending priority candidate_plugins.sort(key=lambda p: p.channels[role], reverse=True) # Try to load all starting from the highest for p in candidate_plugins: loaded = self.load(p, False) if loaded: for c in p.channels: self.messaging.register_plugin(loaded, c) return loaded return None def load_by_name(self, name): ''' loads a plugin ''' for p in self.get_plugins(): if p.name == name: return self.load(p) logger.error('No plugin found with name: ' + name) return None def load_all(self): ''' loads all plugins ''' for p in self.get_plugins(): self.load(p) def unload_all(self): ''' unloads all plugins ''' active = [] for n in self._active: active.append(n) for n in reversed(active): self.unload(n) def refresh_plugins_list(self): ''' refreshes the list of PluginData from plugins found ''' del self._plugins[:] plugin_matcher = re.compile(r'^(.*\.plugin)$', re.IGNORECASE) for directory in self.dirs: if not os.path.isdir(directory): continue lst = os.listdir(directory) for name in lst: # Find subdirectories in the 'plugins' directory location = os.path.join(directory, name) if not os.path.isdir(location): continue # Find the '.plugin' file plugin_file_path = None for f in os.listdir(location): match = plugin_matcher.match(f) if match: plugin_file_path = os.path.join(location, match.group(1)) break if not plugin_file_path: continue # Get plugin metadata cp = ConfigParser.ConfigParser() cp.read(plugin_file_path) module = cp.get('plugin', 'module').strip() dependencies = [x.strip() for x in cp.get('plugin', 'dependencies').strip().split(',') if x] channels = {} for c in cp.get('plugin', 'channels').strip().split(','): if not c: continue channel,priority = c.strip().split(':') channels[channel.strip()] = int(priority) try: info = imp.find_module(module, [location]) info[0].close() plugin_data = PluginData(name, module, dependencies, channels, location) self._plugins.append(plugin_data) except ImportError: continue def _start(self, plugin, name): ''' starts a plugin directly ''' try: plugin.plugin_init() except Exception as e: logger.error('Plugin ' + name + ' failed with the following:'); logger.error(traceback.format_exc()) pass