Ejemplo n.º 1
0
	def __init__(self, dirs=None, blacklist=[]):
		if dirs:
			self.dirs.extend(dirs)
		self.blacklist.extend(blacklist)
		self.messaging = PluginMessageSystem()
Ejemplo n.º 2
0
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