From e3b933445fe4b18af6ec462fc40da5f482e447a0 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 23 Sep 2011 17:43:01 +0200 Subject: [teisenbe] first attempt at a plugin system. --- src/plugin_manager.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/plugin_manager.py (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py new file mode 100644 index 00000000..3f900e39 --- /dev/null +++ b/src/plugin_manager.py @@ -0,0 +1,25 @@ +class PluginManager(object): + def __init__(self, core): + self.core = core + self.plugins = {} + + def load(self, name): + if name in self.plugins: + self.plugins[name].unload() + + try: + code = compile(open(name).read(), name, 'exec') + from plugin import BasePlugin + globals = { 'BasePlugin' : BasePlugin } + exec(code, globals) + self.plugins[name] = globals['Plugin'](self.core) + except Exception as e: + self.core.information("Could not load plugin: %s" % (e,)) + + def unload(self, name): + if name in self.plugins: + try: + self.plugins[name].unload() + del self.plugins[name] + except Exception as e: + self.core.information("Could not unload plugin (may not be safe to try again): %s" % (e,)) -- cgit v1.2.3 From f27556747896aeb891ce71cfdd0ac349d68c5b3d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 24 Sep 2011 22:26:31 +0200 Subject: [teisenbe] Use the imp module to import modules. Also add a simple translator module --- src/plugin_manager.py | 77 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 8 deletions(-) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 3f900e39..8301f5f8 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -1,25 +1,86 @@ +import imp +import os +import sys +from config import config +from gettext import gettext as _ + +plugins_dir = config.get('plugins_dir', '') +plugins_dir = plugins_dir or\ + os.path.join(os.environ.get('XDG_DATA_HOME') or\ + os.path.join(os.environ.get('HOME'), '.local', 'share'), + 'poezio', 'plugins') +try: + os.makedirs(plugins_dir) +except OSError: + pass + +sys.path.append(plugins_dir) + class PluginManager(object): def __init__(self, core): self.core = core - self.plugins = {} + self.modules = {} # module name -> module object + self.plugins = {} # module name -> plugin object + self.commands = {} # module name -> dict of commands loaded for the module + self.event_handlers = {} # module name -> list of event_name/handler pairs loaded for the module def load(self, name): if name in self.plugins: self.plugins[name].unload() try: - code = compile(open(name).read(), name, 'exec') - from plugin import BasePlugin - globals = { 'BasePlugin' : BasePlugin } - exec(code, globals) - self.plugins[name] = globals['Plugin'](self.core) + if name in self.modules: + imp.acquire_lock() + module = imp.reload(self.modules[name]) + imp.release_lock() + else: + file, filename, info = imp.find_module(name, [plugins_dir]) + imp.acquire_lock() + module = imp.load_module(name, file, filename, info) + imp.release_lock() except Exception as e: - self.core.information("Could not load plugin: %s" % (e,)) + import traceback + self.core.information(_("Could not load plugin: ") + traceback.format_exc()) + return + finally: + if imp.lock_held(): + imp.release_lock() + + self.modules[name] = module + self.commands[name] = {} + self.event_handlers[name] = [] + self.plugins[name] = module.Plugin(self, self.core) def unload(self, name): if name in self.plugins: try: + for command in self.commands[name].keys(): + del self.core.commands[command] + for event_name, handler in self.event_handlers[name]: + self.core.xmpp.del_event_handler(event_name, handler) + self.plugins[name].unload() del self.plugins[name] + del self.commands[name] + del self.event_handlers[name] except Exception as e: - self.core.information("Could not unload plugin (may not be safe to try again): %s" % (e,)) + import traceback + self.core.information(_("Could not unload plugin (may not be safe to try again): ") + traceback.format_exc()) + + def add_command(self, module_name, name, handler, help, completion=None): + if name in self.core.commands: + raise Exception(_("Command '%s' already exists") % (name,)) + + commands = self.commands[module_name] + commands[name] = (handler, help, completion) + self.core.commands[name] = (handler, help, completion) + + def add_event_handler(self, module_name, event_name, handler): + eh = self.event_handlers[module_name] + eh.append((event_name, handler)) + self.core.xmpp.add_event_handler(event_name, handler) + + def del_event_handler(self, module_name, event_name, handler): + self.core.xmpp.del_event_handler(event_name, handler) + eh = self.event_handlers[module_name] + eh = list(filter(lambda e : e != (event_name, handler), eh)) -- cgit v1.2.3 From eb096892a9ab3429ba0dcb9654a356afcd01932d Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Sat, 24 Sep 2011 23:10:55 +0200 Subject: Completion for load and unload commands --- src/plugin_manager.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 8301f5f8..2a7a116f 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -40,7 +40,7 @@ class PluginManager(object): imp.release_lock() except Exception as e: import traceback - self.core.information(_("Could not load plugin: ") + traceback.format_exc()) + self.core.information(_("Could not load plugin: ") + traceback.format_exc(), 'Error') return finally: if imp.lock_held(): @@ -84,3 +84,22 @@ class PluginManager(object): self.core.xmpp.del_event_handler(event_name, handler) eh = self.event_handlers[module_name] eh = list(filter(lambda e : e != (event_name, handler), eh)) + + def completion_load(self, the_input): + """ + completion function that completes the name of the plugins, from + all .py files in plugins_dir + """ + try: + names = os.listdir(plugins_dir) + except OSError as e: + self.core.information(_('Completion failed: %s' % e), 'Error') + return + plugins_files = [name[:-3] for name in names if name.endswith('.py')] + return the_input.auto_completion(plugins_files, '') + + def completion_unload(self, the_input): + """ + completion function that completes the name of the plugins that are loaded + """ + return the_input.auto_completion(list(self.plugins.keys()), '') -- cgit v1.2.3 From 1a6d903e34d505005836f6b8aee3552073a2397e Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 25 Sep 2011 02:39:00 +0200 Subject: Add a config file to the plugins by default --- src/plugin_manager.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 2a7a116f..0ffee7ee 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -9,11 +9,21 @@ plugins_dir = plugins_dir or\ os.path.join(os.environ.get('XDG_DATA_HOME') or\ os.path.join(os.environ.get('HOME'), '.local', 'share'), 'poezio', 'plugins') + +plugins_conf_dir = os.path.join(os.environ.get('XDG_CONFIG_HOME'), 'poezio',\ + 'plugins') + try: os.makedirs(plugins_dir) except OSError: pass +try: + os.makedirs(plugins_conf_dir) +except OSError: + pass + + sys.path.append(plugins_dir) class PluginManager(object): @@ -49,7 +59,7 @@ class PluginManager(object): self.modules[name] = module self.commands[name] = {} self.event_handlers[name] = [] - self.plugins[name] = module.Plugin(self, self.core) + self.plugins[name] = module.Plugin(self, self.core, plugins_conf_dir) def unload(self, name): if name in self.plugins: -- cgit v1.2.3 From 00ed9b4842169111238b86d0bfc1465176b7d2d8 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 25 Sep 2011 03:01:32 +0200 Subject: [teisenbe] Fix a bug in case of XDG_CONFIG_HOME not set --- src/plugin_manager.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 0ffee7ee..1f0e89eb 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -10,8 +10,10 @@ plugins_dir = plugins_dir or\ os.path.join(os.environ.get('HOME'), '.local', 'share'), 'poezio', 'plugins') -plugins_conf_dir = os.path.join(os.environ.get('XDG_CONFIG_HOME'), 'poezio',\ - 'plugins') +config_home = os.environ.get("XDG_CONFIG_HOME") +if not config_home: + config_home = os.path.join(os.environ.get('HOME'), '.config') +plugins_conf_dir = os.path.join(config_home, 'poezio', 'plugins') try: os.makedirs(plugins_dir) @@ -23,7 +25,6 @@ try: except OSError: pass - sys.path.append(plugins_dir) class PluginManager(object): -- cgit v1.2.3 From 7b8a860de95f2af6855b1ba270e677a0eb4c044c Mon Sep 17 00:00:00 2001 From: Todd Eisenberger Date: Tue, 27 Sep 2011 10:14:18 -0700 Subject: Fix loading already loaded plugins --- src/plugin_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 1f0e89eb..df96e9ab 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -37,7 +37,7 @@ class PluginManager(object): def load(self, name): if name in self.plugins: - self.plugins[name].unload() + self.unload(name) try: if name in self.modules: -- cgit v1.2.3 From ed87f26db763432505072eb5a2875f30fc4061d1 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sat, 1 Oct 2011 23:48:42 +0200 Subject: Added a connect() function to the plugins API, for internal event --- src/plugin_manager.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index df96e9ab..82be8632 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -69,6 +69,9 @@ class PluginManager(object): del self.core.commands[command] for event_name, handler in self.event_handlers[name]: self.core.xmpp.del_event_handler(event_name, handler) + for event_name in self.core.internal_events: + if name in event_name: + del event_name[name] self.plugins[name].unload() del self.plugins[name] -- cgit v1.2.3 From d5898965993b63ee719df48cca5d48b0a0402f85 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 2 Oct 2011 13:21:51 +0200 Subject: Adds a way to delete the commands without reloading the plugin --- src/plugin_manager.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 82be8632..5bd6d75b 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -81,6 +81,12 @@ class PluginManager(object): import traceback self.core.information(_("Could not unload plugin (may not be safe to try again): ") + traceback.format_exc()) + def del_command(self, module_name, name): + if name in self.commands[module_name]: + del self.commands[module_name][name] + if name in self.core.commands: + del self.core.commands[name] + def add_command(self, module_name, name, handler, help, completion=None): if name in self.core.commands: raise Exception(_("Command '%s' already exists") % (name,)) -- cgit v1.2.3 From 961cf5df8548ec0985f2755d21af933d8c023ee4 Mon Sep 17 00:00:00 2001 From: mathieui Date: Sun, 6 Nov 2011 23:46:00 +0100 Subject: New type of events to be used with the plugins --- src/plugin_manager.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 5bd6d75b..37db3d13 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -34,6 +34,7 @@ class PluginManager(object): self.plugins = {} # module name -> plugin object self.commands = {} # module name -> dict of commands loaded for the module self.event_handlers = {} # module name -> list of event_name/handler pairs loaded for the module + self.poezio_event_handlers = {} def load(self, name): if name in self.plugins: @@ -60,6 +61,7 @@ class PluginManager(object): self.modules[name] = module self.commands[name] = {} self.event_handlers[name] = [] + self.poezio_event_handlers[name] = [] self.plugins[name] = module.Plugin(self, self.core, plugins_conf_dir) def unload(self, name): @@ -69,14 +71,14 @@ class PluginManager(object): del self.core.commands[command] for event_name, handler in self.event_handlers[name]: self.core.xmpp.del_event_handler(event_name, handler) - for event_name in self.core.internal_events: - if name in event_name: - del event_name[name] + for handler in self.poezio_event_handlers[name]: + self.core.events.del_event_handler(None, handler) self.plugins[name].unload() del self.plugins[name] del self.commands[name] del self.event_handlers[name] + del self.poezio_event_handlers[name] except Exception as e: import traceback self.core.information(_("Could not unload plugin (may not be safe to try again): ") + traceback.format_exc()) @@ -105,6 +107,16 @@ class PluginManager(object): eh = self.event_handlers[module_name] eh = list(filter(lambda e : e != (event_name, handler), eh)) + def add_poezio_event_handler(self, module_name, event_name, handler, first, last, position): + eh = self.poezio_event_handlers[module_name] + eh.append(handler) + self.core.events.add_event_handler(event_name, handler, first, last, position) + + def del_poezio_event_handler(self, module_name, event_name, handler): + self.core.events.del_event_handler(None, handler) + eh = self.poezio_event_handlers[module_name] + eh = list(filter(lambda e : e != handler, eh)) + def completion_load(self, the_input): """ completion function that completes the name of the plugins, from -- cgit v1.2.3 From d6b8ca50f2c046aa1248173f453b3804f40c479a Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 7 Nov 2011 15:09:39 +0100 Subject: Remove first&last and only use "position" in plugins events --- src/plugin_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/plugin_manager.py') diff --git a/src/plugin_manager.py b/src/plugin_manager.py index 37db3d13..bdf94a5b 100644 --- a/src/plugin_manager.py +++ b/src/plugin_manager.py @@ -107,10 +107,10 @@ class PluginManager(object): eh = self.event_handlers[module_name] eh = list(filter(lambda e : e != (event_name, handler), eh)) - def add_poezio_event_handler(self, module_name, event_name, handler, first, last, position): + def add_poezio_event_handler(self, module_name, event_name, handler, position): eh = self.poezio_event_handlers[module_name] eh.append(handler) - self.core.events.add_event_handler(event_name, handler, first, last, position) + self.core.events.add_event_handler(event_name, handler, position) def del_poezio_event_handler(self, module_name, event_name, handler): self.core.events.del_event_handler(None, handler) -- cgit v1.2.3