~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/plugin.py

  • Committer: John Arbash Meinel
  • Date: 2009-03-06 20:42:40 UTC
  • mto: This revision was merged to the branch mainline in revision 4088.
  • Revision ID: john@arbash-meinel.com-20090306204240-mzjavv31z3gu1x7i
Fix a small bug in setup.py when an extension fails to build

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
18
"""bzr python plugin support.
41
41
import imp
42
42
import re
43
43
import types
 
44
import zipfile
44
45
 
45
46
from bzrlib import (
46
47
    _format_version_tuple,
52
53
from bzrlib import plugins as _mod_plugins
53
54
""")
54
55
 
55
 
from bzrlib.symbol_versioning import (
56
 
    deprecated_function,
57
 
    deprecated_in,
58
 
    )
 
56
from bzrlib.symbol_versioning import deprecated_function, one_three
59
57
 
60
58
 
61
59
DEFAULT_PLUGIN_PATH = None
62
60
_loaded = False
63
61
 
64
 
@deprecated_function(deprecated_in((2, 0, 0)))
65
62
def get_default_plugin_path():
66
63
    """Get the DEFAULT_PLUGIN_PATH"""
67
64
    global DEFAULT_PLUGIN_PATH
95
92
    return path
96
93
 
97
94
 
98
 
def _append_new_path(paths, new_path):
99
 
    """Append a new path if it set and not already known."""
100
 
    if new_path is not None and new_path not in paths:
101
 
        paths.append(new_path)
102
 
    return paths
103
 
 
104
 
 
105
 
def get_core_plugin_path():
106
 
    core_path = None
 
95
def get_standard_plugins_path():
 
96
    """Determine a plugin path suitable for general use."""
 
97
    path = os.environ.get('BZR_PLUGIN_PATH',
 
98
                          get_default_plugin_path()).split(os.pathsep)
 
99
    # Get rid of trailing slashes, since Python can't handle them when
 
100
    # it tries to import modules.
 
101
    path = map(_strip_trailing_sep, path)
107
102
    bzr_exe = bool(getattr(sys, 'frozen', None))
108
103
    if bzr_exe:    # expand path for bzr.exe
109
104
        # We need to use relative path to system-wide plugin
116
111
        # then plugins directory is
117
112
        # C:\Program Files\Bazaar\plugins
118
113
        # so relative path is ../../../plugins
119
 
        core_path = osutils.abspath(osutils.pathjoin(
120
 
                osutils.dirname(__file__), '../../../plugins'))
121
 
    else:     # don't look inside library.zip
 
114
        path.append(osutils.abspath(osutils.pathjoin(
 
115
            osutils.dirname(__file__), '../../../plugins')))
 
116
    if not bzr_exe:     # don't look inside library.zip
122
117
        # search the plugin path before the bzrlib installed dir
123
 
        core_path = os.path.dirname(_mod_plugins.__file__)
124
 
    return core_path
125
 
 
126
 
 
127
 
def get_site_plugin_path():
128
 
    """Returns the path for the site installed plugins."""
129
 
    if sys.platform == 'win32':
130
 
        # We don't have (yet) a good answer for windows since that is certainly
131
 
        # related to the way we build the installers. -- vila20090821
132
 
        return None
133
 
    site_path = None
134
 
    try:
135
 
        from distutils.sysconfig import get_python_lib
136
 
    except ImportError:
137
 
        # If distutuils is not available, we just don't know where they are
138
 
        pass
139
 
    else:
140
 
        site_path = osutils.pathjoin(get_python_lib(), 'bzrlib', 'plugins')
141
 
    return site_path
142
 
 
143
 
 
144
 
def get_user_plugin_path():
145
 
    return osutils.pathjoin(config.config_dir(), 'plugins')
146
 
 
147
 
 
148
 
def get_standard_plugins_path():
149
 
    """Determine a plugin path suitable for general use."""
150
 
    # Ad-Hoc default: core is not overriden by site but user can overrides both
151
 
    # The rationale is that:
152
 
    # - 'site' comes last, because these plugins should always be available and
153
 
    #   are supposed to be in sync with the bzr installed on site.
154
 
    # - 'core' comes before 'site' so that running bzr from sources or a user
155
 
    #   installed version overrides the site version.
156
 
    # - 'user' comes first, because... user is always right.
157
 
    # - the above rules clearly defines which plugin version will be loaded if
158
 
    #   several exist. Yet, it is sometimes desirable to disable some directory
159
 
    #   so that a set of plugins is disabled as once. This can be done via
160
 
    #   -site, -core, -user.
161
 
 
162
 
    env_paths = os.environ.get('BZR_PLUGIN_PATH', '+user').split(os.pathsep)
163
 
    defaults = ['+core', '+site']
164
 
 
165
 
    # The predefined references
166
 
    refs = dict(core=get_core_plugin_path(),
167
 
                site=get_site_plugin_path(),
168
 
                user=get_user_plugin_path())
169
 
 
170
 
    # Unset paths that should be removed
171
 
    for k,v in refs.iteritems():
172
 
        removed = '-%s' % k
173
 
        # defaults can never mention removing paths as that will make it
174
 
        # impossible for the user to revoke these removals.
175
 
        if removed in env_paths:
176
 
            env_paths.remove(removed)
177
 
            refs[k] = None
178
 
 
179
 
    # Expand references
180
 
    paths = []
181
 
    for p in env_paths + defaults:
182
 
        if p.startswith('+'):
183
 
            # Resolve reference if they are known
184
 
            try:
185
 
                p = refs[p[1:]]
186
 
            except KeyError:
187
 
                # Leave them untouched otherwise, user may have paths starting
188
 
                # with '+'...
189
 
                pass
190
 
        _append_new_path(paths, p)
191
 
 
192
 
    # Get rid of trailing slashes, since Python can't handle them when
193
 
    # it tries to import modules.
194
 
    paths = map(_strip_trailing_sep, paths)
195
 
    return paths
 
118
        path.append(os.path.dirname(_mod_plugins.__file__))
 
119
    # search the arch independent path if we can determine that and
 
120
    # the plugin is found nowhere else
 
121
    if sys.platform != 'win32':
 
122
        try:
 
123
            from distutils.sysconfig import get_python_lib
 
124
        except ImportError:
 
125
            # If distutuils is not available, we just won't add that path
 
126
            pass
 
127
        else:
 
128
            archless_path = osutils.pathjoin(get_python_lib(), 'bzrlib',
 
129
                    'plugins')
 
130
            if archless_path not in path:
 
131
                path.append(archless_path)
 
132
    return path
196
133
 
197
134
 
198
135
def load_plugins(path=None):
317
254
                trace.print_exception(sys.exc_info(), sys.stderr)
318
255
 
319
256
 
 
257
@deprecated_function(one_three)
 
258
def load_from_zip(zip_name):
 
259
    """Load all the plugins in a zip."""
 
260
    valid_suffixes = ('.py', '.pyc', '.pyo')    # only python modules/packages
 
261
                                                # is allowed
 
262
    try:
 
263
        index = zip_name.rindex('.zip')
 
264
    except ValueError:
 
265
        return
 
266
    archive = zip_name[:index+4]
 
267
    prefix = zip_name[index+5:]
 
268
 
 
269
    trace.mutter('Looking for plugins in %r', zip_name)
 
270
 
 
271
    # use zipfile to get list of files/dirs inside zip
 
272
    try:
 
273
        z = zipfile.ZipFile(archive)
 
274
        namelist = z.namelist()
 
275
        z.close()
 
276
    except zipfile.error:
 
277
        # not a valid zip
 
278
        return
 
279
 
 
280
    if prefix:
 
281
        prefix = prefix.replace('\\','/')
 
282
        if prefix[-1] != '/':
 
283
            prefix += '/'
 
284
        ix = len(prefix)
 
285
        namelist = [name[ix:]
 
286
                    for name in namelist
 
287
                    if name.startswith(prefix)]
 
288
 
 
289
    trace.mutter('Names in archive: %r', namelist)
 
290
 
 
291
    for name in namelist:
 
292
        if not name or name.endswith('/'):
 
293
            continue
 
294
 
 
295
        # '/' is used to separate pathname components inside zip archives
 
296
        ix = name.rfind('/')
 
297
        if ix == -1:
 
298
            head, tail = '', name
 
299
        else:
 
300
            head, tail = name.rsplit('/',1)
 
301
        if '/' in head:
 
302
            # we don't need looking in subdirectories
 
303
            continue
 
304
 
 
305
        base, suffix = osutils.splitext(tail)
 
306
        if suffix not in valid_suffixes:
 
307
            continue
 
308
 
 
309
        if base == '__init__':
 
310
            # package
 
311
            plugin_name = head
 
312
        elif head == '':
 
313
            # module
 
314
            plugin_name = base
 
315
        else:
 
316
            continue
 
317
 
 
318
        if not plugin_name:
 
319
            continue
 
320
        if getattr(_mod_plugins, plugin_name, None):
 
321
            trace.mutter('Plugin name %s already loaded', plugin_name)
 
322
            continue
 
323
 
 
324
        try:
 
325
            exec "import bzrlib.plugins.%s" % plugin_name in {}
 
326
            trace.mutter('Load plugin %s from zip %r', plugin_name, zip_name)
 
327
        except KeyboardInterrupt:
 
328
            raise
 
329
        except Exception, e:
 
330
            ## import pdb; pdb.set_trace()
 
331
            trace.warning('Unable to load plugin %r from %r'
 
332
                    % (name, zip_name))
 
333
            trace.log_exception_quietly()
 
334
            if 'error' in debug.debug_flags:
 
335
                trace.print_exception(sys.exc_info(), sys.stderr)
 
336
 
 
337
 
320
338
def plugins():
321
339
    """Return a dictionary of the plugins.
322
340
 
367
385
        """
368
386
        self.module = module
369
387
 
370
 
    def get_help_text(self, additional_see_also=None, verbose=True):
 
388
    def get_help_text(self, additional_see_also=None):
371
389
        """Return a string with the help for this topic.
372
390
 
373
391
        :param additional_see_also: Additional help topics to be