/breezy/unstable

To get this branch, use:
bzr branch https://code.breezy-vcs.org/breezy/unstable

« back to all changes in this revision

Viewing changes to breezy/plugin.py

  • Committer: Jelmer Vernooij
  • Date: 2017-05-24 01:39:33 UTC
  • mfrom: (3815.3776.6)
  • Revision ID: jelmer@jelmer.uk-20170524013933-ir4y4tqtrsiz2ka2
New upstream snapshot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""bzr python plugin support.
18
18
 
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.
23
23
 
24
24
See the plugin-api developer documentation for information about writing
25
25
plugins.
26
26
 
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
29
29
called.
30
30
"""
31
31
 
34
34
import os
35
35
import sys
36
36
 
37
 
from bzrlib import osutils
 
37
from . import osutils
38
38
 
39
 
from bzrlib.lazy_import import lazy_import
 
39
from .lazy_import import lazy_import
40
40
lazy_import(globals(), """
41
41
import imp
42
42
import re
43
43
import types
44
44
 
45
 
from bzrlib import (
 
45
from breezy import (
46
46
    _format_version_tuple,
47
47
    config,
48
48
    debug,
49
49
    errors,
50
50
    trace,
51
51
    )
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
54
54
""")
55
55
 
56
56
 
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
170
170
    return path
171
171
 
172
172
 
179
179
 
180
180
def get_core_plugin_path():
181
181
    core_path = None
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__)
199
199
    return core_path
200
200
 
212
212
        # If distutuils is not available, we just don't know where they are
213
213
        pass
214
214
    else:
215
 
        site_path = osutils.pathjoin(get_python_lib(), 'bzrlib', 'plugins')
 
215
        site_path = osutils.pathjoin(get_python_lib(), 'breezy', 'plugins')
216
216
    return site_path
217
217
 
218
218
 
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.
236
236
 
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']
239
239
 
240
240
    # The predefined references
243
243
                user=get_user_plugin_path())
244
244
 
245
245
    # Unset paths that should be removed
246
 
    for k,v in refs.iteritems():
 
246
    for k,v in refs.items():
247
247
        removed = '-%s' % k
248
248
        # defaults can never mention removing paths as that will make it
249
249
        # impossible for the user to revoke these removals.
271
271
 
272
272
 
273
273
def load_plugins(path=None):
274
 
    """Load bzrlib plugins.
 
274
    """Load breezy plugins.
275
275
 
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`).
296
296
 
297
297
 
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.
300
300
 
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.)
304
304
 
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.
307
307
 
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'.
309
309
    """
310
310
    # Explicitly load the plugins with a specific path
311
 
    for fullname, path in PluginImporter.specific_paths.iteritems():
312
 
        name = fullname[len('bzrlib.plugins.'):]
 
311
    for fullname, path in PluginImporter.specific_paths.items():
 
312
        name = fullname[len('breezy.plugins.'):]
313
313
        _load_plugin_module(name, path)
314
314
 
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)
321
321
    for d in dirs:
322
322
        if not d:
373
373
def _load_plugin_module(name, dir):
374
374
    """Load plugin name from dir.
375
375
 
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.
378
378
    """
379
 
    if ('bzrlib.plugins.%s' % name) in PluginImporter.blacklist:
 
379
    if ('breezy.plugins.%s' % name) in PluginImporter.blacklist:
380
380
        return
381
381
    try:
382
 
        exec "import bzrlib.plugins.%s" % name in {}
 
382
        exec("import breezy.plugins.%s" % name, {})
383
383
    except KeyboardInterrupt:
384
384
        raise
385
 
    except errors.IncompatibleAPI, e:
 
385
    except errors.IncompatibleAPI as e:
386
386
        warning_message = (
387
387
            "Unable to load plugin %r. It requested API version "
388
388
            "%s of module %s but the minimum exported version is %s, and "
389
389
            "the maximum is %s" %
390
390
            (name, e.wanted, e.api, e.minimum, e.current))
391
391
        record_plugin_warning(name, warning_message)
392
 
    except Exception, e:
 
392
    except Exception as 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:
477
477
            return []
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
481
481
        try:
482
482
            module = sys.modules[plugin_module_name]
483
483
        except KeyError:
508
508
            result = self.module.__doc__
509
509
        if result[-1] != '\n':
510
510
            result += '\n'
511
 
        from bzrlib import help_topics
 
511
        from . import help_topics
512
512
        result += help_topics._format_see_also(additional_see_also)
513
513
        return result
514
514
 
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.'):]
518
518
 
519
519
 
520
520
class PlugIn(object):
521
 
    """The bzrlib representation of a plugin.
 
521
    """The breezy representation of a plugin.
522
522
 
523
523
    The PlugIn object provides a way to manipulate a given plugin module.
524
524
    """
577
577
                    version_info = version_info.split('.')
578
578
                elif len(version_info) == 3:
579
579
                    version_info = tuple(version_info) + ('final', 0)
580
 
            except TypeError, e:
 
580
            except TypeError as e:
581
581
                # The given version_info isn't even iteratible
582
582
                trace.log_exception_quietly()
583
583
                version_info = (version_info,)
589
589
            return "unknown"
590
590
        try:
591
591
            version_string = _format_version_tuple(version_info)
592
 
        except (ValueError, TypeError, IndexError), e:
 
592
        except (ValueError, TypeError, IndexError) as e:
593
593
            trace.log_exception_quietly()
594
594
            # try to return something usefull for bad plugins, in stead of
595
595
            # stack tracing.
600
600
 
601
601
 
602
602
class _PluginImporter(object):
603
 
    """An importer tailored to bzr specific needs.
 
603
    """An importer tailored to brz specific needs.
604
604
 
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
624
624
            otherwise.
625
625
        """
626
 
        if not fullname.startswith('bzrlib.plugins.'):
 
626
        if not fullname.startswith('breezy.plugins.'):
627
627
            return None
628
628
        if fullname in self.blacklist:
629
629
            raise ImportError('%s is disabled' % fullname)