X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ipsilon%2Futil%2Fplugin.py;h=978e4701f143cb1c8569bea8cb34ec4a4484b3dc;hb=ba59365931a4e35226b3d9be216d867ff1549846;hp=919a28d6383d437066e828408fce70de76ed8d7d;hpb=dcc545ed447feadb1ed6d53ab70311ed0d2123c3;p=cascardo%2Fipsilon.git diff --git a/ipsilon/util/plugin.py b/ipsilon/util/plugin.py old mode 100755 new mode 100644 index 919a28d..978e470 --- a/ipsilon/util/plugin.py +++ b/ipsilon/util/plugin.py @@ -1,27 +1,11 @@ -#!/usr/bin/python -# -# Copyright (C) 2013 Simo Sorce -# -# see file 'COPYING' for use and warranty information -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# Copyright (C) 2013 Ipsilon project Contributors, for license see COPYING import os import imp import cherrypy import inspect -from ipsilon.util.data import AdminStore +import logging +from ipsilon.util.data import AdminStore, Store from ipsilon.util.log import Log @@ -30,9 +14,9 @@ class Plugins(object): def __init__(self): self._providers_tree = None - def _load_class(self, tree, class_type, file_name): + def _load_class(self, tree, class_type, file_name, *pargs): cherrypy.log.error('Check module %s for class %s' % (file_name, - class_type)) + class_type), severity=logging.DEBUG) name, ext = os.path.splitext(os.path.split(file_name)[-1]) try: if ext.lower() == '.py': @@ -42,154 +26,172 @@ class Plugins(object): else: return except Exception, e: # pylint: disable=broad-except - cherrypy.log.error('Failed to load "%s" module: [%s]' % (name, e)) + cherrypy.log.error('Failed to load "%s" module: [%s]' % (name, e), + severity=logging.ERROR) return if hasattr(mod, class_type): - instance = getattr(mod, class_type)() + instance = getattr(mod, class_type)(*pargs) public_name = getattr(instance, 'name', name) tree[public_name] = instance - cherrypy.log.error('Added module %s as %s' % (name, public_name)) + cherrypy.log.error('Added module %s as %s' % (name, public_name), + severity=logging.DEBUG) - def _load_classes(self, tree, path, class_type): + def _load_classes(self, tree, path, class_type, *pargs): files = None try: files = os.listdir(path) except Exception, e: # pylint: disable=broad-except - cherrypy.log.error('No modules in %s: [%s]' % (path, e)) + cherrypy.log.error('No modules in %s: [%s]' % (path, e), + severity=logging.ERROR) return for name in files: filename = os.path.join(path, name) - self._load_class(tree, class_type, filename) + self._load_class(tree, class_type, filename, *pargs) - def get_plugins(self, path, class_type): + def get_plugins(self, path, class_type, *pargs): plugins = dict() - self._load_classes(plugins, path, class_type) + self._load_classes(plugins, path, class_type, *pargs) return plugins -class PluginLoader(object): +class PluginLoader(Log): def __init__(self, baseobj, facility, plugin_type): - config = AdminStore().load_options(facility) - cherrypy.log('LOAD: %s\n' % repr(config)) - whitelist = [] - if 'global' in config: - sec = config['global'] - if 'order' in sec: - whitelist = sec['order'].split(',') - if cherrypy.config.get('debug', False): - cherrypy.log('[%s] %s: %s' % (facility, whitelist, config)) - if config is None: - config = dict() + self._pathname, _ = os.path.split(inspect.getfile(baseobj)) + self.facility = facility + self._plugin_type = plugin_type + self.available = dict() + self.enabled = list() + self.__data = None + + # Defer initialization or instantiating the store will fail at load + # time when used with Installer plugins as the cherrypy config context + # is created after all Installer plugins are loaded. + @property + def _data(self): + if not self.__data: + self.__data = AdminStore() + return self.__data + + @property + def is_readonly(self): + return self._data.is_readonly + def get_plugins(self): p = Plugins() - (pathname, dummy) = os.path.split(inspect.getfile(baseobj)) - self._plugins = { - 'config': config, - 'available': p.get_plugins(pathname, plugin_type), - 'whitelist': whitelist, - 'enabled': [] - } + return p.get_plugins(self._pathname, self._plugin_type, self) + + def refresh_enabled(self): + config = self._data.load_options(self.facility, name='global') + self.enabled = [] + if config: + if 'enabled' in config: + self.enabled = config['enabled'].split(',') def get_plugin_data(self): - return self._plugins + self.available = self.get_plugins() + self.refresh_enabled() + def save_enabled(self, enabled): + if enabled: + self._data.save_options(self.facility, 'global', + {'enabled': ','.join(enabled)}) + else: + self._data.delete_options(self.facility, 'global', + {'enabled': '*'}) + self.debug('Plugin enabled state saved: %s' % enabled) + self.refresh_enabled() -class PluginInstaller(object): - def __init__(self, baseobj): - (pathname, dummy) = os.path.split(inspect.getfile(baseobj)) - self._pathname = pathname - def get_plugins(self): - p = Plugins() - return p.get_plugins(self._pathname, 'Installer') +class PluginInstaller(PluginLoader): + def __init__(self, baseobj, facility): + super(PluginInstaller, self).__init__(baseobj, facility, 'Installer') class PluginObject(Log): - def __init__(self): + def __init__(self, plugins): self.name = None self._config = None - self._options = None self._data = AdminStore() - - def get_config_desc(self, name=None): - """ The configuration description is a dictionary that provides - A description of the supported configuration options, as well - as the default configuration option values. - The key is the option name, the value is an array of 3 elements: - - description - - option type - - default value - """ - if name is None: - return self._options - - opt = self._options.get(name, None) - if opt is None: - return '' - return opt[0] - - def _value_to_list(self, name): - if name not in self._config: + self._plugins = plugins + self.is_enabled = False + + @property + def is_readonly(self): + return self._data.is_readonly + + def on_enable(self): + return + + def on_disable(self): + return + + def save_enabled_state(self): + enabled = [] + self._plugins.refresh_enabled() + enabled.extend(self._plugins.enabled) + if self.is_enabled: + if self.name not in enabled: + enabled.append(self.name) + else: + if self.name in enabled: + enabled.remove(self.name) + self._plugins.save_enabled(enabled) + + def enable(self): + if self.is_enabled: return - value = self._config[name] - if type(value) is list: + + self.refresh_plugin_config() + is_upgrade = Store._is_upgrade # pylint: disable=protected-access + try: + Store._is_upgrade = True # pylint: disable=protected-access + self.on_enable() + for store in self.used_datastores(): + store.upgrade_database() + finally: + Store._is_upgrade = is_upgrade # pylint: disable=protected-access + self.is_enabled = True + self.debug('Plugin enabled: %s' % self.name) + + def disable(self): + if not self.is_enabled: return - vlist = [x.strip() for x in value.split(',')] - self._config[name] = vlist - def set_config(self, config): + self.on_disable() + + self.is_enabled = False + self.debug('Plugin disabled: %s' % self.name) + + def used_datastores(self): + return [] + + def import_config(self, config): self._config = config - if self._config is None: - return - if self._options: - for name, opt in self._options.iteritems(): - if opt[1] == 'list': - self._value_to_list(name) - - def get_config_value(self, name): - value = None - if self._config: - value = self._config.get(name, None) - if value is None: - if self._options: - opt = self._options.get(name, None) - if opt: - value = opt[2] - - if cherrypy.config.get('debug', False): - cherrypy.log('[%s] %s: %s' % (self.name, name, value)) - - return value - - def set_config_value(self, option, value): - if not self._config: - self._config = dict() - self._config[option] = value - if self._options and option in self._options: - if self._options[option][1] == 'list': - self._value_to_list(option) - - def get_plugin_config(self, facility): - return self._data.load_options(facility, self.name) - - def refresh_plugin_config(self, facility): - config = self.get_plugin_config(facility) - self.set_config(config) - - def save_plugin_config(self, facility, config=None): - if config is None: - config = self._config - config = config.copy() - for key, value in config.items(): - if type(value) is list: - config[key] = ','.join(value) + def export_config(self): + return self._config + + def get_plugin_config(self): + return self._data.load_options(self._plugins.facility, self.name) + + def refresh_plugin_config(self): + config = self.get_plugin_config() + if config: + try: + self.import_config(config) + except Exception, e: # pylint: disable=broad-except + self.error('Failed to refresh config for %s (%s)' % + (self.name, e)) + + def save_plugin_config(self, config=None): + if config is None: + config = self.export_config() - self._data.save_options(facility, self.name, config) + self._data.save_options(self._plugins.facility, self.name, config) def get_data(self, idval=None, name=None, value=None): return self._data.get_data(self.name, idval=idval, name=name, @@ -204,8 +206,8 @@ class PluginObject(Log): def del_datum(self, idval): self._data.del_datum(self.name, idval) - def wipe_config_values(self, facility): - self._data.delete_options(facility, self.name, None) + def wipe_config_values(self): + self._data.delete_options(self._plugins.facility, self.name, None) def wipe_data(self): self._data.wipe_data(self.name)