1#  _________________________________________________________________________
2#
3#  PyUtilib: A Python utility library.
4#  Copyright (c) 2008 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  _________________________________________________________________________
9
10# This software is adapted from the Trac software (specifically, the trac.core
11# module.  The Trac copyright statement is included below.
12
13__all__ = ['EggLoader']
14
15import os
16import sys
17import logging
18from pyutilib.component.config import ManagedPlugin
19from pyutilib.component.core import implements, ExtensionPoint, IPluginLoader
20
21logger = logging.getLogger('pyutilib.component.core.pca')
22pkg_resources_avail = None
23
24def _check_pkg_resources():
25    # Defer import of pkg_resources until the EggLoader actually needs
26    # it: loading pkg_resources is relatively slow, so this avoids the
27    # time penalty every time pyutilib is imported.
28    global pkg_resources_avail
29    global pkg_resources
30    try:
31        if 'pkg_resources' not in sys.modules:
32            #
33            # Avoid a re-import, which causes setup.py warnings...
34            #
35            import pkg_resources
36        else:
37            pkg_resources = sys.modules['pkg_resources']
38        pkg_resources_avail = True
39    except ImportError:
40        pkg_resources_avail = False
41
42def pkg_environment(path):
43    if pkg_resources_avail is None:
44        _check_pkg_resources()
45    return pkg_resources.Environment(path) if pkg_resources_avail else None
46
47class EggLoader(ManagedPlugin):
48    """
49    Loader that looks for Python egg files in the plugins directories.
50    These files get exampled with the pkg_resources package, and
51    Plugin classes are loaded.
52
53    Note: this plugin should not be directly constructed.  Instead,
54    the user should employ the PluginFactory_EggLoader function.
55    """
56
57    implements(IPluginLoader, service=True)
58
59    def __init__(self, **kwds):
60        """EggLoader constructor.  The 'namespace' keyword option is
61        required."""
62        if 'name' not in kwds:
63            kwds['name'] = "EggLoader." + kwds['namespace']
64        super(EggLoader, self).__init__(**kwds)
65        self.entry_point_name = kwds['namespace'] + ".plugins"
66        if pkg_resources_avail is None:
67            _check_pkg_resources()
68        if not pkg_resources_avail:
69            logger.warning(
70                'A dummy EggLoader service is being constructed, because the pkg_resources package is not available on this machine.')
71
72    def load(self, env, search_path, disable_re, name_re):
73        generate_debug_messages = __debug__ and env.log.isEnabledFor(
74            logging.DEBUG)
75        if not pkg_resources_avail:
76            if generate_debug_messages:
77                env.log.debug(
78                    'The EggLoader service is terminating early because the pkg_resources package is not available on this machine.')
79            return
80
81        working_set = pkg_resources.working_set
82
83        env.log.info('BEGIN -  Loading plugins with an EggLoader service')
84        distributions, errors = working_set.find_plugins(
85            pkg_resources.Environment(search_path))
86        for dist in distributions:
87            if name_re.match(str(dist)):
88                if generate_debug_messages:
89                    env.log.debug('Adding plugin %r from %r', dist,
90                                  dist.location)
91                working_set.add(dist)
92            else:
93                if generate_debug_messages:
94                    env.log.debug('Ignoring plugin %r from %r', dist,
95                                  dist.location)
96
97        def _log_error(item, e):
98            gen_debug = __debug__ and env.log.isEnabledFor(logging.DEBUG)
99            if isinstance(e, pkg_resources.DistributionNotFound):
100                if gen_debug:
101                    env.log.debug('Skipping "%s": ("%s" not found)', item, e)
102            elif isinstance(e, pkg_resources.VersionConflict):
103                if gen_debug:
104                    env.log.debug('Skipping "%s": (version conflict "%s")',
105                                  item, e)
106            elif isinstance(e, pkg_resources.UnknownExtra):
107                env.log.error('Skipping "%s": (unknown extra "%s")', item, e)
108            elif isinstance(e, ImportError):
109                env.log.error('Skipping "%s": (can\'t import "%s")', item, e)
110            else:
111                env.log.error('Skipping "%s": (error "%s")', item, e)
112
113        for dist, e in errors.items():
114            _log_error(dist, e)
115
116        for entry in working_set.iter_entry_points(self.entry_point_name):
117            if generate_debug_messages:
118                env.log.debug('Loading %r from %r', entry.name,
119                              entry.dist.location)
120            try:
121                entry.load(require=True)
122            except (ImportError,
123                    pkg_resources.DistributionNotFound,
124                    pkg_resources.VersionConflict,
125                    pkg_resources.UnknownExtra):
126                e = sys.exc_info()[1]
127                _log_error(entry, e)
128            else:
129                if not disable_re.match(os.path.dirname(
130                        entry.module_name)) is None:
131                    #_enable_plugin(env, entry.module_name)
132                    pass
133
134        env.log.info('END -    Loading plugins with an EggLoader service')
135
136# Copyright (C) 2005-2008 Edgewall Software
137# Copyright (C) 2005-2006 Christopher Lenz <cmlenz@gmx.de>
138# All rights reserved.
139#
140# This software is licensed as described in the file COPYING, which
141# you should have received as part of this distribution. The terms
142# are also available at http://trac.edgewall.org/wiki/TracLicense.
143#
144# This software consists of voluntary contributions made by many
145# individuals. For the exact contribution history, see the revision
146# history and logs, available at http://trac.edgewall.org/log/.
147#
148# Author: Christopher Lenz <cmlenz@gmx.de>
149