1
# Copyright (C) 2004, 2005, 2007 Canonical Ltd
1
# Copyright (C) 2004, 2005 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
50
49
from bzrlib.trace import mutter, warning, log_exception_quietly
57
56
"""Get the DEFAULT_PLUGIN_PATH"""
58
57
global DEFAULT_PLUGIN_PATH
59
58
if DEFAULT_PLUGIN_PATH is None:
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)
59
DEFAULT_PLUGIN_PATH = osutils.pathjoin(config.config_dir(), 'plugins')
75
60
return DEFAULT_PLUGIN_PATH
78
@deprecated_function(zero_ninetyone)
80
64
"""Return a dictionary of the plugins."""
81
return dict((name, plugin.module) for name, plugin in plugins().items())
66
for name, plugin in plugins.__dict__.items():
67
if isinstance(plugin, types.ModuleType):
84
72
def disable_plugins():
95
def _strip_trailing_sep(path):
96
return path.rstrip("\\/")
99
83
def set_plugins_path():
100
84
"""Set the path for plugins to be loaded from."""
101
85
path = os.environ.get('BZR_PLUGIN_PATH',
102
86
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)
106
87
# search the plugin path before the bzrlib installed dir
107
path.append(os.path.dirname(_mod_plugins.__file__))
108
_mod_plugins.__path__ = path
88
path.append(os.path.dirname(plugins.__file__))
89
plugins.__path__ = path
143
124
The python module path for bzrlib.plugins will be modified to be '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)
126
plugins.__path__ = dirs
195
if getattr(_mod_plugins, f, None):
172
if getattr(plugins, f, None):
196
173
mutter('Plugin name %s already loaded', f)
198
175
# mutter('add plugin name %s', f)
206
183
except Exception, e:
207
184
## import pdb; pdb.set_trace()
208
185
if re.search('\.|-| ', name):
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))
186
warning('Unable to load plugin %r from %r: '
187
'It is not a valid python module name.' % (name, d))
214
189
warning('Unable to load plugin %r from %r' % (name, d))
215
190
log_exception_quietly()
219
194
"""Load all the plugins in a zip."""
220
195
valid_suffixes = ('.py', '.pyc', '.pyo') # only python modules/packages
197
if '.zip' not in zip_name:
224
index = zip_name.rindex('.zip')
200
ziobj = zipimport.zipimporter(zip_name)
201
except zipimport.ZipImportError:
227
archive = zip_name[:index+4]
228
prefix = zip_name[index+5:]
230
204
mutter('Looking for plugins in %r', zip_name)
232
208
# use zipfile to get list of files/dirs inside zip
234
z = zipfile.ZipFile(archive)
235
namelist = z.namelist()
237
except zipfile.error:
242
prefix = prefix.replace('\\','/')
243
if prefix[-1] != '/':
209
z = zipfile.ZipFile(ziobj.archive)
210
namelist = z.namelist()
214
prefix = ziobj.prefix.replace('\\','/')
246
216
namelist = [name[ix:]
247
217
for name in namelist
248
218
if name.startswith(prefix)]
250
220
mutter('Names in archive: %r', namelist)
252
222
for name in namelist:
279
249
if not plugin_name:
281
if getattr(_mod_plugins, plugin_name, None):
251
if getattr(plugins, plugin_name, None):
282
252
mutter('Plugin name %s already loaded', plugin_name)
286
exec "import bzrlib.plugins.%s" % plugin_name in {}
256
plugin = ziobj.load_module(plugin_name)
257
setattr(plugins, plugin_name, plugin)
287
258
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))
288
263
except KeyboardInterrupt:
290
265
except Exception, e:
294
269
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)
309
272
class PluginsHelpIndex(object):
310
273
"""A help index that returns help topics for plugins."""
372
335
def get_help_topic(self):
373
336
"""Return the modules help topic - its __name__ after bzrlib.plugins.."""
374
337
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__)