/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/plugin.py

  • Committer: Ian Clatworthy
  • Date: 2008-12-15 06:18:29 UTC
  • mfrom: (3905 +trunk)
  • mto: (3586.1.23 views-ui)
  • mto: This revision was merged to the branch mainline in revision 4030.
  • Revision ID: ian.clatworthy@canonical.com-20081215061829-c8qwa93g71u9fsh5
merge bzr.dev 3905

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2007 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2007, 2008 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
When load_plugins() is invoked, any python module in any directory in
21
21
$BZR_PLUGIN_PATH will be imported.  The module will be imported as
22
22
'bzrlib.plugins.$BASENAME(PLUGIN)'.  In the plugin's main body, it should
23
 
update any bzrlib registries it wants to extend; for example, to add new
24
 
commands, import bzrlib.commands and add your new command to the plugin_cmds
25
 
variable.
 
23
update any bzrlib registries it wants to extend.
 
24
 
 
25
See the plugin-api developer documentation for information about writing
 
26
plugins.
26
27
 
27
28
BZR_PLUGIN_PATH is also honoured for any plugins imported via
28
29
'import bzrlib.plugins.PLUGINNAME', as long as set_plugins_path has been 
32
33
import os
33
34
import sys
34
35
 
 
36
from bzrlib import osutils
 
37
 
35
38
from bzrlib.lazy_import import lazy_import
 
39
 
36
40
lazy_import(globals(), """
37
41
import imp
38
42
import re
40
44
import zipfile
41
45
 
42
46
from bzrlib import (
 
47
    _format_version_tuple,
43
48
    config,
44
49
    debug,
45
 
    osutils,
 
50
    errors,
46
51
    trace,
47
52
    )
48
53
from bzrlib import plugins as _mod_plugins
49
54
""")
50
55
 
51
56
from bzrlib.symbol_versioning import deprecated_function, one_three
52
 
from bzrlib.trace import mutter, warning, log_exception_quietly
53
57
 
54
58
 
55
59
DEFAULT_PLUGIN_PATH = None
68
72
 
69
73
    Future calls to load_plugins() will be ignored.
70
74
    """
71
 
    # TODO: jam 20060131 This should probably also disable
72
 
    #       load_from_dirs()
73
 
    global _loaded
74
 
    _loaded = True
 
75
    load_plugins([])
75
76
 
76
77
 
77
78
def _strip_trailing_sep(path):
78
79
    return path.rstrip("\\/")
79
80
 
80
81
 
81
 
def set_plugins_path():
82
 
    """Set the path for plugins to be loaded from."""
 
82
def set_plugins_path(path=None):
 
83
    """Set the path for plugins to be loaded from.
 
84
 
 
85
    :param path: The list of paths to search for plugins.  By default,
 
86
        path will be determined using get_standard_plugins_path.
 
87
        if path is [], no plugins can be loaded.
 
88
    """
 
89
    if path is None:
 
90
        path = get_standard_plugins_path()
 
91
    _mod_plugins.__path__ = path
 
92
    return path
 
93
 
 
94
 
 
95
def get_standard_plugins_path():
 
96
    """Determine a plugin path suitable for general use."""
83
97
    path = os.environ.get('BZR_PLUGIN_PATH',
84
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)
85
102
    bzr_exe = bool(getattr(sys, 'frozen', None))
86
103
    if bzr_exe:    # expand path for bzr.exe
87
104
        # We need to use relative path to system-wide plugin
96
113
        # so relative path is ../../../plugins
97
114
        path.append(osutils.abspath(osutils.pathjoin(
98
115
            osutils.dirname(__file__), '../../../plugins')))
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)
102
116
    if not bzr_exe:     # don't look inside library.zip
103
117
        # search the plugin path before the bzrlib installed dir
104
118
        path.append(os.path.dirname(_mod_plugins.__file__))
115
129
                    'plugins')
116
130
            if archless_path not in path:
117
131
                path.append(archless_path)
118
 
    _mod_plugins.__path__ = path
119
132
    return path
120
133
 
121
134
 
122
 
def load_plugins():
 
135
def load_plugins(path=None):
123
136
    """Load bzrlib plugins.
124
137
 
125
138
    The environment variable BZR_PLUGIN_PATH is considered a delimited
129
142
 
130
143
    load_from_dirs() provides the underlying mechanism and is called with
131
144
    the default directory list to provide the normal behaviour.
 
145
 
 
146
    :param path: The list of paths to search for plugins.  By default,
 
147
        path will be determined using get_standard_plugins_path.
 
148
        if path is [], no plugins can be loaded.
132
149
    """
133
150
    global _loaded
134
151
    if _loaded:
137
154
    _loaded = True
138
155
 
139
156
    # scan for all plugins in the path.
140
 
    load_from_path(set_plugins_path())
 
157
    load_from_path(set_plugins_path(path))
141
158
 
142
159
 
143
160
def load_from_path(dirs):
161
178
    for d in dirs:
162
179
        if not d:
163
180
            continue
164
 
        mutter('looking for plugins in %s', d)
 
181
        trace.mutter('looking for plugins in %s', d)
165
182
        if os.path.isdir(d):
166
183
            load_from_dir(d)
167
184
 
172
189
 
173
190
 
174
191
def load_from_dir(d):
175
 
    """Load the plugins in directory d."""
 
192
    """Load the plugins in directory d.
 
193
    
 
194
    d must be in the plugins module path already.
 
195
    """
176
196
    # Get the list of valid python suffixes for __init__.py?
177
197
    # this includes .py, .pyc, and .pyo (depending on if we are running -O)
178
198
    # but it doesn't include compiled modules (.so, .dll, etc)
199
219
                    break
200
220
            else:
201
221
                continue
202
 
        if getattr(_mod_plugins, f, None):
203
 
            mutter('Plugin name %s already loaded', f)
 
222
        if f == '__init__':
 
223
            continue # We don't load __init__.py again in the plugin dir
 
224
        elif getattr(_mod_plugins, f, None):
 
225
            trace.mutter('Plugin name %s already loaded', f)
204
226
        else:
205
 
            # mutter('add plugin name %s', f)
 
227
            # trace.mutter('add plugin name %s', f)
206
228
            plugin_names.add(f)
207
229
    
208
230
    for name in plugin_names:
210
232
            exec "import bzrlib.plugins.%s" % name in {}
211
233
        except KeyboardInterrupt:
212
234
            raise
 
235
        except errors.IncompatibleAPI, e:
 
236
            trace.warning("Unable to load plugin %r. It requested API version "
 
237
                "%s of module %s but the minimum exported version is %s, and "
 
238
                "the maximum is %s" %
 
239
                (name, e.wanted, e.api, e.minimum, e.current))
213
240
        except Exception, e:
 
241
            trace.warning("%s" % e)
214
242
            ## import pdb; pdb.set_trace()
215
243
            if re.search('\.|-| ', name):
216
244
                sanitised_name = re.sub('[-. ]', '_', name)
217
245
                if sanitised_name.startswith('bzr_'):
218
246
                    sanitised_name = sanitised_name[len('bzr_'):]
219
 
                warning("Unable to load %r in %r as a plugin because the "
 
247
                trace.warning("Unable to load %r in %r as a plugin because the "
220
248
                        "file path isn't a valid module name; try renaming "
221
249
                        "it to %r." % (name, d, sanitised_name))
222
250
            else:
223
 
                warning('Unable to load plugin %r from %r' % (name, d))
224
 
            log_exception_quietly()
 
251
                trace.warning('Unable to load plugin %r from %r' % (name, d))
 
252
            trace.log_exception_quietly()
225
253
            if 'error' in debug.debug_flags:
226
254
                trace.print_exception(sys.exc_info(), sys.stderr)
227
255
 
238
266
    archive = zip_name[:index+4]
239
267
    prefix = zip_name[index+5:]
240
268
 
241
 
    mutter('Looking for plugins in %r', zip_name)
 
269
    trace.mutter('Looking for plugins in %r', zip_name)
242
270
 
243
271
    # use zipfile to get list of files/dirs inside zip
244
272
    try:
258
286
                    for name in namelist
259
287
                    if name.startswith(prefix)]
260
288
 
261
 
    mutter('Names in archive: %r', namelist)
 
289
    trace.mutter('Names in archive: %r', namelist)
262
290
    
263
291
    for name in namelist:
264
292
        if not name or name.endswith('/'):
290
318
        if not plugin_name:
291
319
            continue
292
320
        if getattr(_mod_plugins, plugin_name, None):
293
 
            mutter('Plugin name %s already loaded', plugin_name)
 
321
            trace.mutter('Plugin name %s already loaded', plugin_name)
294
322
            continue
295
323
    
296
324
        try:
297
325
            exec "import bzrlib.plugins.%s" % plugin_name in {}
298
 
            mutter('Load plugin %s from zip %r', plugin_name, zip_name)
 
326
            trace.mutter('Load plugin %s from zip %r', plugin_name, zip_name)
299
327
        except KeyboardInterrupt:
300
328
            raise
301
329
        except Exception, e:
302
330
            ## import pdb; pdb.set_trace()
303
 
            warning('Unable to load plugin %r from %r'
 
331
            trace.warning('Unable to load plugin %r from %r'
304
332
                    % (name, zip_name))
305
 
            log_exception_quietly()
 
333
            trace.log_exception_quietly()
306
334
            if 'error' in debug.debug_flags:
307
335
                trace.print_exception(sys.exc_info(), sys.stderr)
308
336
 
441
469
    def version_info(self):
442
470
        """Return the plugin's version_tuple or None if unknown."""
443
471
        version_info = getattr(self.module, 'version_info', None)
444
 
        if version_info is not None and len(version_info) == 3:
445
 
            version_info = tuple(version_info) + ('final', 0)
 
472
        if version_info is not None:
 
473
            try:
 
474
                if isinstance(version_info, types.StringType):
 
475
                    version_info = version_info.split('.')
 
476
                elif len(version_info) == 3:
 
477
                    version_info = tuple(version_info) + ('final', 0)
 
478
            except TypeError, e:
 
479
                # The given version_info isn't even iteratible
 
480
                trace.log_exception_quietly()
 
481
                version_info = (version_info,)
446
482
        return version_info
447
483
 
448
484
    def _get__version__(self):
449
485
        version_info = self.version_info()
450
 
        if version_info is None:
 
486
        if version_info is None or len(version_info) == 0:
451
487
            return "unknown"
452
 
        if version_info[3] == 'final':
453
 
            version_string = '%d.%d.%d' % version_info[:3]
454
 
        else:
455
 
            version_string = '%d.%d.%d%s%d' % version_info
 
488
        try:
 
489
            version_string = _format_version_tuple(version_info)
 
490
        except (ValueError, TypeError, IndexError), e:
 
491
            trace.log_exception_quietly()
 
492
            # try to return something usefull for bad plugins, in stead of
 
493
            # stack tracing.
 
494
            version_string = '.'.join(map(str, version_info))
456
495
        return version_string
457
496
 
458
497
    __version__ = property(_get__version__)