Logo Search packages:      
Sourcecode: falcon version File versions  Download package

plugin.py

# This file is part of the Falcon repository manager
# Copyright (C) 2005-2008 Dennis Kaarsemaker
# See the file named COPYING in the root of the source tree for license details
#
# plugin.py - Plugin base class and plugin hook functions/decorators

import falcon
import sys, os, types, snack
from gettext import gettext as _

loaded_plugins = {}
enabled_plugins = []

def load_plugins():
    """Load all available plugins"""
    # Global plugins
    try:
        import falcon.plugins
    except:
        raise
        # Extra import is needed here
        import falcon
        falcon.util.debug_exception()
        falcon.util.error(_("Failed to load global plugins"))

    # Homedir plugins
    if os.path.exists(os.path.join(os.getenv('HOME'), '.falcon', 'plugins','__init__.py')):
        os.path.insert(0,os.path.join(os.getenv('HOME'), '.falcon'))
        try:
            import plugins as homedir_plugins
        except:
            falcon.util.error(_("Failed to load plugins in your .falcon"))
        os.path = os.path[1:]

    # Repo plugins
    if os.path.exists(os.path.join('.falcon', 'plugins','__init__.py')):
        os.path.insert(0,os.path.join('.falcon'))
        try:
            import plugins as repo_plugins
        except:
            falcon.util.error(_("Failed to load plugins in your repositories .falcon"))
        os.path = os.path[1:]

00044 class PluginBase(type):
    """Metaclass for automatic plugin registration"""
    def __new__(cls, name, bases, attrs):
        # Only do magic on subclasses of the base plugin
        if not bases or bases == (object,):
            return type.__new__(cls, name, bases, attrs)

        new_class = type.__new__(cls, name, bases, attrs)

        # Add a configuration
        new_class.conf = falcon.config.Configuration(c_prefix = 'plugin_%s_' % name)
        new_class.conf.register('enabled', False, falcon.questions.Boolean(_("Enable this plugin")))
        new_class.__file__ = sys.modules[new_class.__module__].__file__

        # Register the plugin if the api version matches
        try:
            api = new_class.api
            major, minor = int(api[0]), int(api[1])
        except (AttributeError, ValueError, TypeError):
            falcon.util.warning(_("Plugin %s from %s is broken: it doesn't define an API version") % (name, new_class.__file__))
            falcon.util.debug_exception()
            return new_class

        if major != falcon.conf.plugin_api[0] or minor > falcon.conf.plugin_api[1]:
            falcon.util.warning(_("Plugin %s from %s is broken: it is made for a different version of falcon") % (name, new_class.__file__))
            return new_class
        if minor < falcon.conf.plugin_api[1]:
            falcon.util.warning(_("Plugin %s from %s should be upgraded but will still work") % (name, new_class.__file__))
            
        loaded_plugins[name] = new_class
        if new_class.conf.enabled:
            enabled_plugins.append(new_class())
        return new_class

00078 class FalconPlugin(object):
    """Base class for falcon plugins"""
    
    __metaclass__ = PluginBase

    # These 3 should be overridden in actual plugins
    name = "Plugin Interface - you need to change this in your plugin"
    desc = "Badly maintained plugin"
    api  = (0,0)

    # Configuration hook
    @classmethod
00090     def configure(cls):
        """Configure this plugin"""
        while True:
            current = dict([(x.key, cls.conf[x.key]) for x in cls.conf.questions])
            was_enabled = cls.conf.enabled
            form = falcon.questions.QuestionForm(cls.name, cls.conf.questions)
            answers = form.run(current)
            if not answers:
                break
            for k in answers:
                cls.conf[k] = answers[k]

            if cls.conf.enabled and not was_enabled:
                # Plugin was just enabled, run its constructor and config
                enabled_plugins.append(cls())
                current = dict([(x.key, cls.conf[x.key]) for x in cls.conf.questions])
            else:
                break

    # Before anything is done, right after argument parsing
    def pre_action(self, action, args): pass
    # After everything is done, before quiting
    def post_action(self, action, args): pass

    # When scanning a component
    def pre_scan(self, component): pass
    def post_scan(self, result, component): pass

    # When exporting a component, metacomponent or pocket
    def pre_export(self, component_or_pocket): pass
    def post_export(self, result, component_or_pocket): pass

    # When adding packages to a component (pocket.py)
    def pre_install(self, component, package): pass
    def post_install(self, result, component, package): pass

    # When morgueing a file
    def pre_morgue(self, file): pass
    def post_morgue(self, result, file): pass

    # When syncing to a mirror
    def pre_sync(self, mirror): pass
    def pre_rsync(self, mirror): pass # After syncing contents to the base-mirror dir
                                      # but before the rsync
    def post_sync(self, result, mirror): pass

    # When building
    def pre_run(self, queueitem, firstrun): pass
    def post_run(self, result, queueitem, firstrun): pass
    def pre_build(self, builder, queueitem): pass
    def post_build(self, result, builder, queueitem): pass

00142 class DontRun(Exception):
    """Prevent the wrapped command from being run"""
    pass

# Decorator chain for plugin hooks
def wrap_plugin(func, name=None):
    """Wrap a command and let plugin hooks run around it"""
    if name:
        func.wrapped_name = name
        return wrap_plugin
    def wrapped_func(*args, **kwargs):
        name = func.func_name
        try:
            name = func.wrapped_name
        except AttributeError:
            pass
        res = run_plugins('pre_' + name, *args, **kwargs)
        if not res:
            return
        result = func(*args, **kwargs)
        run_plugins('post_' + name, result, *args, **kwargs)
        return result
    return wrapped_func

def run_plugins(name, *args, **kwargs):
    """Run plugin functions for sections of code that cannot be wrapped"""
    for p in enabled_plugins[:]:
        if name in p.__class__.__dict__:
            try:
                p.__class__.__dict__[name](p, *args, **kwargs)
            except DontRun, e:
                return False
            except Exception, e:
                falcon.util.warning(_("The %s plugin generated an exception, it will be disabled") % p.name)
                falcon.util.debug_exception()
                enabled_plugins.remove(p)
    return True

Generated by  Doxygen 1.6.0   Back to index