Example #1
0
class Environment(Component, ComponentManager):
    """The environment loads plugins """

    commands = ExtensionPoint(IShellCommandProvider)
    console_objects = ExtensionPoint(IShellConsoleObjectProvider)
    env_objects = ExtensionPoint(IEnvObjectProvider)

    def __init__(self, config=None, entry_point=None, plugins=None,
                logger=None, locals=None):
        """Initialize the Dustbowl environment.

        @param config: the absolute path to a configuration file.
        @param entry_point: The entry point used to locate plugins.
        @param plugins: a list of tuples containing paths in which to look for
                        plugins and a boolean indicating whether or not
                        plugins loaded from the specified path should be
                        auto-enabled.
        @param logger: a Python logger instance.

        ``sys.path`` will be automatically added to the list of plugin
        directories.  All entries of ``sys.path`` will not be auto-enabled.
        """
        ComponentManager.__init__(self)


        self.setup_config(config)
        self.setup_log(logger)

        # Load plugins
        self.plugin_data = dict()
        if not plugins:
            plugins = list()
        self.load_modules(plugins, entry_point=entry_point)

        if locals:
            self.parent_locals = locals

        for provider in self.console_objects:
            for key, value in provider.get_console_objects():
                self.add_console_object(key, value, provider.__class__.__name__)
                continue
            continue

        for provider in self.env_objects:
            for key, value in provider.get_env_objects():
                self.add_env_object(key, value, provider.__class__.__name__)
                continue
            continue


    def component_activated(self, component):
        """Initialize additional member variables for components.

        Every component activated through the `Environment` object gets three
        member variables: `env` (the environment object), `config` (the
        environment configuration) and `log` (a logger object)."""
        component.env = self
        component.config = self.config
        component.log = self.log

    def is_component_enabled(self, cls):
        """Implemented to only allow activation of components that are not
        disabled in the configuration.

        This is called by the `ComponentManager` base class when a component is
        about to be activated. If this method returns false, the component does
        not get activated."""
        if not isinstance(cls, basestring):
            component_name = (cls.__module__ + '.' + cls.__name__).lower()
        else:
            component_name = cls.lower()

        for key, value in self.plugin_data.iteritems():
            if component_name == key or component_name.startswith(key + '.'):
                value['activated'] = True
                return value['loaded']
        return False

    def setup_config(self, configpath):
        """Load the configuration file."""
        self.config = Configuration(configpath)

    def setup_log(self, logger):
        """Initialize the logging sub-system."""
        if logger:
            self.log = logger
        else:
            self.log = NullLogger()

    def is_enabled(self, module_name):
        """ Return whether a module is enabled in the config.
        """
        for key, value in self.config.options('components'):
            k = key.lower()
            mod = module_name.lower()
            if mod == k or k.endswith('*') and mod.startswith(k[:-1]):
                return self.config.getbool('components', key)
        return False

    def load_modules(self, plugins=None, entry_point='dustbowl.modules'):
        """ Load plugins """
        def _log_error(item, e):
            ue = format_exception(e)
            if isinstance(e, DistributionNotFound):
                self.log.debug('Skipping "%s": ("%s" not found)', item, ue)
            elif isinstance(e, VersionConflict):
                self.log.error('Skipping "%s": (version conflict "%s")',
                              item, ue)
            elif isinstance(e, UnknownExtra):
                self.log.error('Skipping "%s": (unknown extra "%s")', item, ue)
            elif isinstance(e, ImportError):
                self.log.error('Skipping "%s": (can\'t import "%s")', item, ue)
            else:
                self.log.error('Skipping "%s": (error "%s")', item, ue)

        ws = pkg_resources.WorkingSet(sys.path)

        # Look for core modules
        ws.add_entry(os.path.dirname(
                        pkg_resources.resource_filename(__name__, '')))
        for entry in ws.iter_entry_points(entry_point):
            if entry.name.startswith('dustbowl.plugins'):
                entry_data = {
                    'entry' : entry,
                    'loaded' : False,
                    'activated' : False,
                    'auto_enable' : True,
                }
                self.plugin_data.setdefault(entry.name, entry_data)

        # Look for modules in sys.path
        for p in sys.path:
            ws.add_entry(p)
        for entry in ws.iter_entry_points(entry_point):
            entry_data = {
                'entry' : entry,
                'loaded' : False,
                'activated' : False,
                'auto_enable' : False,
            }
            self.plugin_data.setdefault(entry.name, entry_data)

        # Look for modules from plugin dir specified in the config or on the
        # command line
        distributions, errors = ws.find_plugins(
                                        pkg_resources.Environment(plugins))
        for dist in distributions:
            self.log.debug('Found plugin %s at %s', dist, dist.location)
            ws.add(dist)

        for entry in ws.iter_entry_points(entry_point):
            entry_data = {
                'entry' : entry,
                'loaded' : False,
                'activated' : False,
                'auto_enable' : False,
                }
            self.plugin_data.setdefault(entry.name, entry_data)

        for entry_name, data in self.plugin_data.iteritems():
            if data['auto_enable'] or self.is_enabled(entry_name):
                try:
                    self.log.debug('Loading %s from %s', data['entry'].name,
                                  data['entry'].dist)
                    # We need to make sure the distribution is on the path
                    # before we can load it.
                    data['entry'].dist.activate()
                    data['entry'].load(require=True)
                    data['loaded'] = True
                except (ImportError, DistributionNotFound, VersionConflict,
                        UnknownExtra), e:
                    # Print the last traceback to the debug buffer
                    _log_error(data['entry'], e)
            continue


        for dist, e in errors.iteritems():
            _log_error(dist, e)
Example #2
0
 def setup_log(self, logger):
     """Initialize the logging sub-system."""
     if logger:
         self.log = logger
     else:
         self.log = NullLogger()