1
# Copyright (C) 2004, 2005, 2007 Canonical Ltd
1
# Copyright (C) 2004, 2005, 2007, 2008 Canonical Ltd
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
23
update any bzrlib registries it wants to extend.
25
See the plugin-api developer documentation for information about writing
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
42
46
from bzrlib import (
47
_format_version_tuple,
48
53
from bzrlib import plugins as _mod_plugins
51
56
from bzrlib.symbol_versioning import deprecated_function, one_three
52
from bzrlib.trace import mutter, warning, log_exception_quietly
55
59
DEFAULT_PLUGIN_PATH = None
69
73
Future calls to load_plugins() will be ignored.
71
# TODO: jam 20060131 This should probably also disable
77
78
def _strip_trailing_sep(path):
78
79
return path.rstrip("\\/")
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.
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.
90
path = get_standard_plugins_path()
91
_mod_plugins.__path__ = path
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__))
116
130
if archless_path not in path:
117
131
path.append(archless_path)
118
_mod_plugins.__path__ = path
135
def load_plugins(path=None):
123
136
"""Load bzrlib plugins.
125
138
The environment variable BZR_PLUGIN_PATH is considered a delimited
130
143
load_from_dirs() provides the underlying mechanism and is called with
131
144
the default directory list to provide the normal behaviour.
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.
174
191
def load_from_dir(d):
175
"""Load the plugins in directory d."""
192
"""Load the plugins in directory d.
194
d must be in the plugins module path already.
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)
202
if getattr(_mod_plugins, f, None):
203
mutter('Plugin name %s already loaded', f)
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)
205
# mutter('add plugin name %s', f)
227
# trace.mutter('add plugin name %s', f)
206
228
plugin_names.add(f)
208
230
for name in plugin_names:
210
232
exec "import bzrlib.plugins.%s" % name in {}
211
233
except KeyboardInterrupt:
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))
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)
238
266
archive = zip_name[:index+4]
239
267
prefix = zip_name[index+5:]
241
mutter('Looking for plugins in %r', zip_name)
269
trace.mutter('Looking for plugins in %r', zip_name)
243
271
# use zipfile to get list of files/dirs inside zip
258
286
for name in namelist
259
287
if name.startswith(prefix)]
261
mutter('Names in archive: %r', namelist)
289
trace.mutter('Names in archive: %r', namelist)
263
291
for name in namelist:
264
292
if not name or name.endswith('/'):
290
318
if not plugin_name:
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)
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:
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)
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:
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)
479
# The given version_info isn't even iteratible
480
trace.log_exception_quietly()
481
version_info = (version_info,)
446
482
return version_info
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:
452
if version_info[3] == 'final':
453
version_string = '%d.%d.%d' % version_info[:3]
455
version_string = '%d.%d.%d%s%d' % version_info
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
494
version_string = '.'.join(map(str, version_info))
456
495
return version_string
458
497
__version__ = property(_get__version__)