1
# Copyright (C) 2004, 2005 Canonical Ltd
1
# Copyright (C) 2004, 2005, 2007 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
42
42
from bzrlib import (
46
from bzrlib import plugins as _mod_plugins
49
from bzrlib.symbol_versioning import deprecated_function, zero_ninetyone
49
50
from bzrlib.trace import mutter, warning, log_exception_quietly
56
57
"""Get the DEFAULT_PLUGIN_PATH"""
57
58
global DEFAULT_PLUGIN_PATH
58
59
if DEFAULT_PLUGIN_PATH is None:
59
DEFAULT_PLUGIN_PATH = osutils.pathjoin(config.config_dir(), 'plugins')
60
path = [osutils.pathjoin(config.config_dir(), 'plugins')]
61
if getattr(sys, 'frozen', None): # bzr.exe
62
# We need to use relative path to system-wide plugin
63
# directory because bzrlib from standalone bzr.exe
64
# could be imported by another standalone program
65
# (e.g. bzr-config; or TortoiseBzr/Olive if/when they
66
# will become standalone exe). [bialix 20071123]
67
# __file__ typically is
68
# C:\Program Files\Bazaar\lib\library.zip\bzrlib\plugin.pyc
69
# then plugins directory is
70
# C:\Program Files\Bazaar\plugins
71
# so relative path is ../../../plugins
72
path.append(osutils.abspath(osutils.pathjoin(
73
osutils.dirname(__file__), '../../../plugins')))
74
DEFAULT_PLUGIN_PATH = os.pathsep.join(path)
60
75
return DEFAULT_PLUGIN_PATH
78
@deprecated_function(zero_ninetyone)
64
80
"""Return a dictionary of the plugins."""
66
for name, plugin in plugins.__dict__.items():
67
if isinstance(plugin, types.ModuleType):
81
return dict((name, plugin.module) for name, plugin in plugins().items())
72
84
def disable_plugins():
95
def _strip_trailing_sep(path):
96
return path.rstrip("\\/")
83
99
def set_plugins_path():
84
100
"""Set the path for plugins to be loaded from."""
85
101
path = os.environ.get('BZR_PLUGIN_PATH',
86
102
get_default_plugin_path()).split(os.pathsep)
103
# Get rid of trailing slashes, since Python can't handle them when
104
# it tries to import modules.
105
path = map(_strip_trailing_sep, path)
87
106
# search the plugin path before the bzrlib installed dir
88
path.append(os.path.dirname(plugins.__file__))
89
plugins.__path__ = path
107
path.append(os.path.dirname(_mod_plugins.__file__))
108
_mod_plugins.__path__ = path
124
143
The python module path for bzrlib.plugins will be modified to be 'dirs'.
126
plugins.__path__ = dirs
145
# We need to strip the trailing separators here as well as in the
146
# set_plugins_path function because calling code can pass anything in to
147
# this function, and since it sets plugins.__path__, it should set it to
148
# something that will be valid for Python to use (in case people try to
149
# run "import bzrlib.plugins.PLUGINNAME" after calling this function).
150
_mod_plugins.__path__ = map(_strip_trailing_sep, dirs)
172
if getattr(plugins, f, None):
195
if getattr(_mod_plugins, f, None):
173
196
mutter('Plugin name %s already loaded', f)
175
198
# mutter('add plugin name %s', f)
183
206
except Exception, e:
184
207
## import pdb; pdb.set_trace()
185
208
if re.search('\.|-| ', name):
186
warning('Unable to load plugin %r from %r: '
187
'It is not a valid python module name.' % (name, d))
209
sanitised_name = re.sub('[-. ]', '_', name)
210
warning("Unable to load %r in %r as a plugin because file path"
211
" isn't a valid module name; try renaming it to %r."
212
% (name, d, sanitised_name))
189
214
warning('Unable to load plugin %r from %r' % (name, d))
190
215
log_exception_quietly()
194
219
"""Load all the plugins in a zip."""
195
220
valid_suffixes = ('.py', '.pyc', '.pyo') # only python modules/packages
197
if '.zip' not in zip_name:
200
ziobj = zipimport.zipimporter(zip_name)
201
except zipimport.ZipImportError:
224
index = zip_name.rindex('.zip')
227
archive = zip_name[:index+4]
228
prefix = zip_name[index+5:]
204
230
mutter('Looking for plugins in %r', zip_name)
208
232
# use zipfile to get list of files/dirs inside zip
209
z = zipfile.ZipFile(ziobj.archive)
210
namelist = z.namelist()
214
prefix = ziobj.prefix.replace('\\','/')
234
z = zipfile.ZipFile(archive)
235
namelist = z.namelist()
237
except zipfile.error:
242
prefix = prefix.replace('\\','/')
243
if prefix[-1] != '/':
216
246
namelist = [name[ix:]
217
247
for name in namelist
218
248
if name.startswith(prefix)]
220
250
mutter('Names in archive: %r', namelist)
222
252
for name in namelist:
249
279
if not plugin_name:
251
if getattr(plugins, plugin_name, None):
281
if getattr(_mod_plugins, plugin_name, None):
252
282
mutter('Plugin name %s already loaded', plugin_name)
256
plugin = ziobj.load_module(plugin_name)
257
setattr(plugins, plugin_name, plugin)
286
exec "import bzrlib.plugins.%s" % plugin_name in {}
258
287
mutter('Load plugin %s from zip %r', plugin_name, zip_name)
259
except zipimport.ZipImportError, e:
260
mutter('Unable to load plugin %r from %r: %s',
261
plugin_name, zip_name, str(e))
263
288
except KeyboardInterrupt:
265
290
except Exception, e:
269
294
log_exception_quietly()
298
"""Return a dictionary of the plugins.
300
Each item in the dictionary is a PlugIn object.
303
for name, plugin in _mod_plugins.__dict__.items():
304
if isinstance(plugin, types.ModuleType):
305
result[name] = PlugIn(name, plugin)
272
309
class PluginsHelpIndex(object):
273
310
"""A help index that returns help topics for plugins."""
335
372
def get_help_topic(self):
336
373
"""Return the modules help topic - its __name__ after bzrlib.plugins.."""
337
374
return self.module.__name__[len('bzrlib.plugins.'):]
377
class PlugIn(object):
378
"""The bzrlib representation of a plugin.
380
The PlugIn object provides a way to manipulate a given plugin module.
383
def __init__(self, name, module):
384
"""Construct a plugin for module."""
389
"""Get the path that this plugin was loaded from."""
390
if getattr(self.module, '__path__', None) is not None:
391
return os.path.abspath(self.module.__path__[0])
392
elif getattr(self.module, '__file__', None) is not None:
393
return os.path.abspath(self.module.__file__)
395
return repr(self.module)
398
return "<%s.%s object at %s, name=%s, module=%s>" % (
399
self.__class__.__module__, self.__class__.__name__, id(self),
400
self.name, self.module)
404
def test_suite(self):
405
"""Return the plugin's test suite."""
406
if getattr(self.module, 'test_suite', None) is not None:
407
return self.module.test_suite()
411
def version_info(self):
412
"""Return the plugin's version_tuple or None if unknown."""
413
version_info = getattr(self.module, 'version_info', None)
414
if version_info is not None and len(version_info) == 3:
415
version_info = tuple(version_info) + ('final', 0)
418
def _get__version__(self):
419
version_info = self.version_info()
420
if version_info is None:
422
if version_info[3] == 'final':
423
version_string = '%d.%d.%d' % version_info[:3]
425
version_string = '%d.%d.%d%s%d' % version_info
426
return version_string
428
__version__ = property(_get__version__)