17
17
"""bzr python plugin support.
19
19
When load_plugins() is invoked, any python module in any directory in
20
$BZR_PLUGIN_PATH will be imported. The module will be imported as
21
'bzrlib.plugins.$BASENAME(PLUGIN)'. In the plugin's main body, it should
22
update any bzrlib registries it wants to extend.
20
$BRZ_PLUGIN_PATH will be imported. The module will be imported as
21
'breezy.plugins.$BASENAME(PLUGIN)'. In the plugin's main body, it should
22
update any breezy registries it wants to extend.
24
24
See the plugin-api developer documentation for information about writing
27
BZR_PLUGIN_PATH is also honoured for any plugins imported via
28
'import bzrlib.plugins.PLUGINNAME', as long as set_plugins_path has been
27
BRZ_PLUGIN_PATH is also honoured for any plugins imported via
28
'import breezy.plugins.PLUGINNAME', as long as set_plugins_path has been
37
from bzrlib import osutils
37
from breezy import osutils
39
from bzrlib.lazy_import import lazy_import
39
from breezy.lazy_import import lazy_import
40
40
lazy_import(globals(), """
46
46
_format_version_tuple,
52
from bzrlib.i18n import gettext
53
from bzrlib import plugins as _mod_plugins
52
from breezy.i18n import gettext
53
from breezy import plugins as _mod_plugins
158
158
_mod_plugins.__path__ = path
159
159
PluginImporter.reset()
160
160
# Set up a blacklist for disabled plugins
161
disabled_plugins = os.environ.get('BZR_DISABLE_PLUGINS', None)
161
disabled_plugins = os.environ.get('BRZ_DISABLE_PLUGINS', None)
162
162
if disabled_plugins is not None:
163
163
for name in disabled_plugins.split(os.pathsep):
164
PluginImporter.blacklist.add('bzrlib.plugins.' + name)
164
PluginImporter.blacklist.add('breezy.plugins.' + name)
165
165
# Set up a the specific paths for plugins
166
166
for plugin_name, plugin_path in _get_specific_plugin_paths(os.environ.get(
167
'BZR_PLUGINS_AT', None)):
167
'BRZ_PLUGINS_AT', None)):
168
168
PluginImporter.specific_paths[
169
'bzrlib.plugins.%s' % plugin_name] = plugin_path
169
'breezy.plugins.%s' % plugin_name] = plugin_path
180
180
def get_core_plugin_path():
182
bzr_exe = bool(getattr(sys, 'frozen', None))
183
if bzr_exe: # expand path for bzr.exe
182
brz_exe = bool(getattr(sys, 'frozen', None))
183
if brz_exe: # expand path for brz.exe
184
184
# We need to use relative path to system-wide plugin
185
# directory because bzrlib from standalone bzr.exe
185
# directory because breezy from standalone brz.exe
186
186
# could be imported by another standalone program
187
187
# (e.g. bzr-config; or TortoiseBzr/Olive if/when they
188
188
# will become standalone exe). [bialix 20071123]
189
189
# __file__ typically is
190
# C:\Program Files\Bazaar\lib\library.zip\bzrlib\plugin.pyc
190
# C:\Program Files\Bazaar\lib\library.zip\breezy\plugin.pyc
191
191
# then plugins directory is
192
192
# C:\Program Files\Bazaar\plugins
193
193
# so relative path is ../../../plugins
194
194
core_path = osutils.abspath(osutils.pathjoin(
195
195
osutils.dirname(__file__), '../../../plugins'))
196
196
else: # don't look inside library.zip
197
# search the plugin path before the bzrlib installed dir
197
# search the plugin path before the breezy installed dir
198
198
core_path = os.path.dirname(_mod_plugins.__file__)
212
212
# If distutuils is not available, we just don't know where they are
215
site_path = osutils.pathjoin(get_python_lib(), 'bzrlib', 'plugins')
215
site_path = osutils.pathjoin(get_python_lib(), 'breezy', 'plugins')
225
225
# Ad-Hoc default: core is not overriden by site but user can overrides both
226
226
# The rationale is that:
227
227
# - 'site' comes last, because these plugins should always be available and
228
# are supposed to be in sync with the bzr installed on site.
229
# - 'core' comes before 'site' so that running bzr from sources or a user
228
# are supposed to be in sync with the brz installed on site.
229
# - 'core' comes before 'site' so that running brz from sources or a user
230
230
# installed version overrides the site version.
231
231
# - 'user' comes first, because... user is always right.
232
232
# - the above rules clearly defines which plugin version will be loaded if
234
234
# so that a set of plugins is disabled as once. This can be done via
235
235
# -site, -core, -user.
237
env_paths = os.environ.get('BZR_PLUGIN_PATH', '+user').split(os.pathsep)
237
env_paths = os.environ.get('BRZ_PLUGIN_PATH', '+user').split(os.pathsep)
238
238
defaults = ['+core', '+site']
240
240
# The predefined references
273
273
def load_plugins(path=None):
274
"""Load bzrlib plugins.
274
"""Load breezy plugins.
276
The environment variable BZR_PLUGIN_PATH is considered a delimited
276
The environment variable BRZ_PLUGIN_PATH is considered a delimited
277
277
set of paths to look through. Each entry is searched for `*.py`
278
278
files (and whatever other extensions are used in the platform,
279
279
such as `*.pyd`).
298
298
def load_from_path(dirs):
299
"""Load bzrlib plugins found in each dir in dirs.
299
"""Load breezy plugins found in each dir in dirs.
301
301
Loading a plugin means importing it into the python interpreter.
302
302
The plugin is expected to make calls to register commands when
303
303
it's loaded (or perhaps access other hooks in future.)
305
Plugins are loaded into bzrlib.plugins.NAME, and can be found there
305
Plugins are loaded into breezy.plugins.NAME, and can be found there
306
306
for future reference.
308
The python module path for bzrlib.plugins will be modified to be 'dirs'.
308
The python module path for breezy.plugins will be modified to be 'dirs'.
310
310
# Explicitly load the plugins with a specific path
311
311
for fullname, path in PluginImporter.specific_paths.iteritems():
312
name = fullname[len('bzrlib.plugins.'):]
312
name = fullname[len('breezy.plugins.'):]
313
313
_load_plugin_module(name, path)
315
315
# We need to strip the trailing separators here as well as in the
316
316
# set_plugins_path function because calling code can pass anything in to
317
317
# this function, and since it sets plugins.__path__, it should set it to
318
318
# something that will be valid for Python to use (in case people try to
319
# run "import bzrlib.plugins.PLUGINNAME" after calling this function).
319
# run "import breezy.plugins.PLUGINNAME" after calling this function).
320
320
_mod_plugins.__path__ = map(_strip_trailing_sep, dirs)
373
373
def _load_plugin_module(name, dir):
374
374
"""Load plugin name from dir.
376
:param name: The plugin name in the bzrlib.plugins namespace.
376
:param name: The plugin name in the breezy.plugins namespace.
377
377
:param dir: The directory the plugin is loaded from for error messages.
379
if ('bzrlib.plugins.%s' % name) in PluginImporter.blacklist:
379
if ('breezy.plugins.%s' % name) in PluginImporter.blacklist:
382
exec "import bzrlib.plugins.%s" % name in {}
382
exec "import breezy.plugins.%s" % name in {}
383
383
except KeyboardInterrupt:
385
385
except errors.IncompatibleAPI, e:
393
393
trace.warning("%s" % e)
394
394
if re.search('\.|-| ', name):
395
395
sanitised_name = re.sub('[-. ]', '_', name)
396
if sanitised_name.startswith('bzr_'):
397
sanitised_name = sanitised_name[len('bzr_'):]
396
if sanitised_name.startswith('brz_'):
397
sanitised_name = sanitised_name[len('brz_'):]
398
398
trace.warning("Unable to load %r in %r as a plugin because the "
399
399
"file path isn't a valid module name; try renaming "
400
400
"it to %r." % (name, dir, sanitised_name))
419
419
if name is not None:
420
420
if name == '__init__':
421
421
# We do nothing with the __init__.py file in directories from
422
# the bzrlib.plugins module path, we may want to, one day
422
# the breezy.plugins module path, we may want to, one day
423
423
# -- vila 20100316.
424
424
continue # We don't load __init__.py in the plugins dirs
425
425
elif getattr(_mod_plugins, name, None) is not None:
478
478
if topic.startswith(self.prefix):
479
479
topic = topic[len(self.prefix):]
480
plugin_module_name = 'bzrlib.plugins.%s' % topic
480
plugin_module_name = 'breezy.plugins.%s' % topic
482
482
module = sys.modules[plugin_module_name]
508
508
result = self.module.__doc__
509
509
if result[-1] != '\n':
511
from bzrlib import help_topics
511
from breezy import help_topics
512
512
result += help_topics._format_see_also(additional_see_also)
515
515
def get_help_topic(self):
516
516
"""Return the module help topic: its basename."""
517
return self.module.__name__[len('bzrlib.plugins.'):]
517
return self.module.__name__[len('breezy.plugins.'):]
520
520
class PlugIn(object):
521
"""The bzrlib representation of a plugin.
521
"""The breezy representation of a plugin.
523
523
The PlugIn object provides a way to manipulate a given plugin module.
602
602
class _PluginImporter(object):
603
"""An importer tailored to bzr specific needs.
603
"""An importer tailored to brz specific needs.
605
605
This is a singleton that takes care of:
606
606
- disabled plugins specified in 'blacklist',
623
623
:return: None if the plugin doesn't need special handling, self
626
if not fullname.startswith('bzrlib.plugins.'):
626
if not fullname.startswith('breezy.plugins.'):
628
628
if fullname in self.blacklist:
629
629
raise ImportError('%s is disabled' % fullname)