/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/plugin.py

  • Committer: Neil Santos
  • Date: 2010-03-04 02:43:41 UTC
  • mto: (5080.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5081.
  • Revision ID: neil_santos@users.sourceforge.net-20100304024341-ra7njxj4lzjb46rl
Removed separate lstat() and reverted LocalTransport and SFTPTransport's stat() methods to using lstat() internally.
Reworked how SFTPTransport's symlink() handles success and signals failure.
Removed lstat() declaration on the Transport base class.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2007, 2008, 2010 Canonical Ltd
2
2
#
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
67
67
    return _plugins_disabled
68
68
 
69
69
 
 
70
@deprecated_function(deprecated_in((2, 0, 0)))
 
71
def get_default_plugin_path():
 
72
    """Get the DEFAULT_PLUGIN_PATH"""
 
73
    global DEFAULT_PLUGIN_PATH
 
74
    if DEFAULT_PLUGIN_PATH is None:
 
75
        DEFAULT_PLUGIN_PATH = osutils.pathjoin(config.config_dir(), 'plugins')
 
76
    return DEFAULT_PLUGIN_PATH
 
77
 
 
78
 
70
79
def disable_plugins():
71
80
    """Disable loading plugins.
72
81
 
91
100
    if path is None:
92
101
        path = get_standard_plugins_path()
93
102
    _mod_plugins.__path__ = path
94
 
    PluginImporter.reset()
95
 
    # Set up a blacklist for disabled plugins
96
 
    disabled_plugins = os.environ.get('BZR_DISABLE_PLUGINS', None)
97
 
    if disabled_plugins is not None:
98
 
        for name in disabled_plugins.split(os.pathsep):
99
 
            PluginImporter.blacklist.add('bzrlib.plugins.' + name)
100
 
    # Set up a the specific paths for plugins
101
 
    specific_plugins = os.environ.get('BZR_PLUGINS_AT', None)
102
 
    if specific_plugins is not None:
103
 
        for spec in specific_plugins.split(os.pathsep):
104
 
            plugin_name, plugin_path = spec.split('@')
105
 
            PluginImporter.specific_paths[
106
 
                'bzrlib.plugins.%s' % plugin_name] = plugin_path
107
103
    return path
108
104
 
109
105
 
192
188
    paths = []
193
189
    for p in env_paths + defaults:
194
190
        if p.startswith('+'):
195
 
            # Resolve references if they are known
 
191
            # Resolve reference if they are known
196
192
            try:
197
193
                p = refs[p[1:]]
198
194
            except KeyError:
199
 
                # Leave them untouched so user can still use paths starting
200
 
                # with '+'
 
195
                # Leave them untouched otherwise, user may have paths starting
 
196
                # with '+'...
201
197
                pass
202
198
        _append_new_path(paths, p)
203
199
 
215
211
    files (and whatever other extensions are used in the platform,
216
212
    such as *.pyd).
217
213
 
218
 
    load_from_path() provides the underlying mechanism and is called with
 
214
    load_from_dirs() provides the underlying mechanism and is called with
219
215
    the default directory list to provide the normal behaviour.
220
216
 
221
217
    :param path: The list of paths to search for plugins.  By default,
244
240
 
245
241
    The python module path for bzrlib.plugins will be modified to be 'dirs'.
246
242
    """
247
 
    # Explicitly load the plugins with a specific path
248
 
    for fullname, path in PluginImporter.specific_paths.iteritems():
249
 
        name = fullname[len('bzrlib.plugins.'):]
250
 
        _load_plugin_module(name, path)
251
 
 
252
243
    # We need to strip the trailing separators here as well as in the
253
244
    # set_plugins_path function because calling code can pass anything in to
254
245
    # this function, and since it sets plugins.__path__, it should set it to
268
259
load_from_dirs = load_from_path
269
260
 
270
261
 
271
 
def _find_plugin_module(dir, name):
272
 
    """Check if there is a valid python module that can be loaded as a plugin.
273
 
 
274
 
    :param dir: The directory where the search is performed.
275
 
    :param path: An existing file path, either a python file or a package
276
 
        directory.
277
 
 
278
 
    :return: (name, path, description) name is the module name, path is the
279
 
        file to load and description is the tuple returned by
280
 
        imp.get_suffixes().
281
 
    """
282
 
    path = osutils.pathjoin(dir, name)
283
 
    if os.path.isdir(path):
284
 
        # Check for a valid __init__.py file, valid suffixes depends on -O and
285
 
        # can be .py, .pyc and .pyo
286
 
        for suffix, mode, kind in imp.get_suffixes():
287
 
            if kind not in (imp.PY_SOURCE, imp.PY_COMPILED):
288
 
                # We don't recognize compiled modules (.so, .dll, etc)
289
 
                continue
290
 
            init_path = osutils.pathjoin(path, '__init__' + suffix)
291
 
            if os.path.isfile(init_path):
292
 
                return name, init_path, (suffix, mode, kind)
293
 
    else:
294
 
        for suffix, mode, kind in imp.get_suffixes():
295
 
            if name.endswith(suffix):
296
 
                # Clean up the module name
297
 
                name = name[:-len(suffix)]
298
 
                if kind == imp.C_EXTENSION and name.endswith('module'):
299
 
                    name = name[:-len('module')]
300
 
                return name, path, (suffix, mode, kind)
301
 
    # There is no python module here
302
 
    return None, None, (None, None, None)
303
 
 
304
 
 
305
 
def _load_plugin_module(name, dir):
306
 
    """Load plugin name from dir.
307
 
 
308
 
    :param name: The plugin name in the bzrlib.plugins namespace.
309
 
    :param dir: The directory the plugin is loaded from for error messages.
310
 
    """
311
 
    if ('bzrlib.plugins.%s' % name) in PluginImporter.blacklist:
312
 
        return
313
 
    try:
314
 
        exec "import bzrlib.plugins.%s" % name in {}
315
 
    except KeyboardInterrupt:
316
 
        raise
317
 
    except errors.IncompatibleAPI, e:
318
 
        trace.warning("Unable to load plugin %r. It requested API version "
319
 
            "%s of module %s but the minimum exported version is %s, and "
320
 
            "the maximum is %s" %
321
 
            (name, e.wanted, e.api, e.minimum, e.current))
322
 
    except Exception, e:
323
 
        trace.warning("%s" % e)
324
 
        if re.search('\.|-| ', name):
325
 
            sanitised_name = re.sub('[-. ]', '_', name)
326
 
            if sanitised_name.startswith('bzr_'):
327
 
                sanitised_name = sanitised_name[len('bzr_'):]
328
 
            trace.warning("Unable to load %r in %r as a plugin because the "
329
 
                    "file path isn't a valid module name; try renaming "
330
 
                    "it to %r." % (name, dir, sanitised_name))
331
 
        else:
332
 
            trace.warning('Unable to load plugin %r from %r' % (name, dir))
333
 
        trace.log_exception_quietly()
334
 
        if 'error' in debug.debug_flags:
335
 
            trace.print_exception(sys.exc_info(), sys.stderr)
336
 
 
337
 
 
338
262
def load_from_dir(d):
339
263
    """Load the plugins in directory d.
340
264
 
341
265
    d must be in the plugins module path already.
342
 
    This function is called once for each directory in the module path.
343
266
    """
 
267
    # Get the list of valid python suffixes for __init__.py?
 
268
    # this includes .py, .pyc, and .pyo (depending on if we are running -O)
 
269
    # but it doesn't include compiled modules (.so, .dll, etc)
 
270
    valid_suffixes = [suffix for suffix, mod_type, flags in imp.get_suffixes()
 
271
                              if flags in (imp.PY_SOURCE, imp.PY_COMPILED)]
 
272
    package_entries = ['__init__'+suffix for suffix in valid_suffixes]
344
273
    plugin_names = set()
345
 
    for p in os.listdir(d):
346
 
        name, path, desc = _find_plugin_module(d, p)
347
 
        if name is not None:
348
 
            if name == '__init__':
349
 
                # We do nothing with the __init__.py file in directories from
350
 
                # the bzrlib.plugins module path, we may want to, one day
351
 
                # -- vila 20100316.
352
 
                continue # We don't load __init__.py in the plugins dirs
353
 
            elif getattr(_mod_plugins, name, None) is not None:
354
 
                # The module has already been loaded from another directory
355
 
                # during a previous call.
356
 
                # FIXME: There should be a better way to report masked plugins
357
 
                # -- vila 20100316
358
 
                trace.mutter('Plugin name %s already loaded', name)
 
274
    for f in os.listdir(d):
 
275
        path = osutils.pathjoin(d, f)
 
276
        if os.path.isdir(path):
 
277
            for entry in package_entries:
 
278
                # This directory should be a package, and thus added to
 
279
                # the list
 
280
                if os.path.isfile(osutils.pathjoin(path, entry)):
 
281
                    break
 
282
            else: # This directory is not a package
 
283
                continue
 
284
        else:
 
285
            for suffix_info in imp.get_suffixes():
 
286
                if f.endswith(suffix_info[0]):
 
287
                    f = f[:-len(suffix_info[0])]
 
288
                    if suffix_info[2] == imp.C_EXTENSION and f.endswith('module'):
 
289
                        f = f[:-len('module')]
 
290
                    break
359
291
            else:
360
 
                plugin_names.add(name)
 
292
                continue
 
293
        if f == '__init__':
 
294
            continue # We don't load __init__.py again in the plugin dir
 
295
        elif getattr(_mod_plugins, f, None):
 
296
            trace.mutter('Plugin name %s already loaded', f)
 
297
        else:
 
298
            # trace.mutter('add plugin name %s', f)
 
299
            plugin_names.add(f)
361
300
 
362
301
    for name in plugin_names:
363
 
        _load_plugin_module(name, d)
 
302
        try:
 
303
            exec "import bzrlib.plugins.%s" % name in {}
 
304
        except KeyboardInterrupt:
 
305
            raise
 
306
        except errors.IncompatibleAPI, e:
 
307
            trace.warning("Unable to load plugin %r. It requested API version "
 
308
                "%s of module %s but the minimum exported version is %s, and "
 
309
                "the maximum is %s" %
 
310
                (name, e.wanted, e.api, e.minimum, e.current))
 
311
        except Exception, e:
 
312
            trace.warning("%s" % e)
 
313
            ## import pdb; pdb.set_trace()
 
314
            if re.search('\.|-| ', name):
 
315
                sanitised_name = re.sub('[-. ]', '_', name)
 
316
                if sanitised_name.startswith('bzr_'):
 
317
                    sanitised_name = sanitised_name[len('bzr_'):]
 
318
                trace.warning("Unable to load %r in %r as a plugin because the "
 
319
                        "file path isn't a valid module name; try renaming "
 
320
                        "it to %r." % (name, d, sanitised_name))
 
321
            else:
 
322
                trace.warning('Unable to load plugin %r from %r' % (name, d))
 
323
            trace.log_exception_quietly()
 
324
            if 'error' in debug.debug_flags:
 
325
                trace.print_exception(sys.exc_info(), sys.stderr)
364
326
 
365
327
 
366
328
def plugins():
523
485
        return version_string
524
486
 
525
487
    __version__ = property(_get__version__)
526
 
 
527
 
 
528
 
class _PluginImporter(object):
529
 
    """An importer tailored to bzr specific needs.
530
 
 
531
 
    This is a singleton that takes care of:
532
 
    - disabled plugins specified in 'blacklist',
533
 
    - plugins that needs to be loaded from specific directories.
534
 
    """
535
 
 
536
 
    def __init__(self):
537
 
        self.reset()
538
 
 
539
 
    def reset(self):
540
 
        self.blacklist = set()
541
 
        self.specific_paths = {}
542
 
 
543
 
    def find_module(self, fullname, parent_path=None):
544
 
        """Search a plugin module.
545
 
 
546
 
        Disabled plugins raise an import error, plugins with specific paths
547
 
        returns a specific loader.
548
 
 
549
 
        :return: None if the plugin doesn't need special handling, self
550
 
            otherwise.
551
 
        """
552
 
        if not fullname.startswith('bzrlib.plugins.'):
553
 
            return None
554
 
        if fullname in self.blacklist:
555
 
            raise ImportError('%s is disabled' % fullname)
556
 
        if fullname in self.specific_paths:
557
 
            return self
558
 
        return None
559
 
 
560
 
    def load_module(self, fullname):
561
 
        """Load a plugin from a specific directory."""
562
 
        # We are called only for specific paths
563
 
        plugin_path = self.specific_paths[fullname]
564
 
        loading_path = None
565
 
        package = False
566
 
        if os.path.isdir(plugin_path):
567
 
            for suffix, mode, kind in imp.get_suffixes():
568
 
                if kind not in (imp.PY_SOURCE, imp.PY_COMPILED):
569
 
                    # We don't recognize compiled modules (.so, .dll, etc)
570
 
                    continue
571
 
                init_path = osutils.pathjoin(plugin_path, '__init__' + suffix)
572
 
                if os.path.isfile(init_path):
573
 
                    loading_path = init_path
574
 
                    package = True
575
 
                    break
576
 
        else:
577
 
            for suffix, mode, kind in imp.get_suffixes():
578
 
                if plugin_path.endswith(suffix):
579
 
                    loading_path = plugin_path
580
 
                    break
581
 
        if loading_path is None:
582
 
            raise ImportError('%s cannot be loaded from %s'
583
 
                              % (fullname, plugin_path))
584
 
        f = open(loading_path, mode)
585
 
        try:
586
 
            mod = imp.load_module(fullname, f, loading_path,
587
 
                                  (suffix, mode, kind))
588
 
            if package:
589
 
                # The plugin can contain modules, so be ready
590
 
                mod.__path__ = [plugin_path]
591
 
            mod.__package__ = fullname
592
 
            return mod
593
 
        finally:
594
 
            f.close()
595
 
 
596
 
 
597
 
# Install a dedicated importer for plugins requiring special handling
598
 
PluginImporter = _PluginImporter()
599
 
sys.meta_path.append(PluginImporter)