1
1
# Copyright (C) 2004, 2005 by 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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
11
# GNU General Public License for more details.
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
"""bzr python plugin support
20
20
Any python module in $BZR_PLUGIN_PATH will be imported upon initialization of
21
bzrlib (and then forgotten about). In the plugin's main body, it should
22
update any bzrlib registries it wants to extend; for example, to add new
23
commands, import bzrlib.commands and add your new command to the plugin_cmds
21
bzrlib. The module will be imported as 'bzrlib.plugins.$BASENAME(PLUGIN)'.
22
In the plugin's main body, it should update any bzrlib registries it wants to
23
extend; for example, to add new commands, import bzrlib.commands and add your
24
new command to the plugin_cmds variable.
27
27
# TODO: Refactor this to make it more testable. The main problem at the
47
48
from bzrlib.config import config_dir
48
from bzrlib.trace import log_error, mutter, log_exception, warning, \
49
from bzrlib.trace import log_error, mutter, warning, \
49
50
log_exception_quietly
50
51
from bzrlib.errors import BzrError
51
52
from bzrlib import plugins
53
DEFAULT_PLUGIN_PATH = os.path.join(config_dir(), 'plugins')
53
from bzrlib.osutils import pathjoin
55
DEFAULT_PLUGIN_PATH = pathjoin(config_dir(), 'plugins')
61
"""Return a dictionary of the plugins."""
63
for name, plugin in bzrlib.plugins.__dict__.items():
64
if isinstance(plugin, types.ModuleType):
69
def disable_plugins():
70
"""Disable loading plugins.
72
Future calls to load_plugins() will be ignored.
74
# TODO: jam 20060131 This should probably also disable
59
80
def load_plugins():
60
"""Find all python plugins and load them.
62
Loading a plugin means importing it into the python interpreter.
63
The plugin is expected to make calls to register commands when
64
it's loaded (or perhaps access other hooks in future.)
66
A list of plugs is stored in bzrlib.plugin.all_plugins for future
81
"""Load bzrlib plugins.
69
83
The environment variable BZR_PLUGIN_PATH is considered a delimited
70
84
set of paths to look through. Each entry is searched for *.py
71
85
files (and whatever other extensions are used in the platform,
88
load_from_dirs() provides the underlying mechanism and is called with
89
the default directory list to provide the normal behaviour.
75
global all_plugins, _loaded
77
93
# People can make sure plugins are loaded, they just won't be twice
79
95
#raise BzrError("plugins already initialized")
82
dirs = os.environ.get('BZR_PLUGIN_PATH', DEFAULT_PLUGIN_PATH).split(":")
98
dirs = os.environ.get('BZR_PLUGIN_PATH', DEFAULT_PLUGIN_PATH).split(os.pathsep)
83
99
dirs.insert(0, os.path.dirname(plugins.__file__))
85
# The problem with imp.get_suffixes() is that it doesn't include
86
# .pyo which is technically valid
87
# It also means that "testmodule.so" will show up as both test and testmodule
88
# though it is only valid as 'test'
89
# but you should be careful, because "testmodule.py" loads as testmodule.
90
suffixes = imp.get_suffixes()
91
suffixes.append(('.pyo', 'rb', imp.PY_COMPILED))
92
package_entries = ['__init__.py', '__init__.pyc', '__init__.pyo']
104
def load_from_dirs(dirs):
105
"""Load bzrlib plugins found in each dir in dirs.
107
Loading a plugin means importing it into the python interpreter.
108
The plugin is expected to make calls to register commands when
109
it's loaded (or perhaps access other hooks in future.)
111
Plugins are loaded into bzrlib.plugins.NAME, and can be found there
112
for future reference.
114
# Get the list of valid python suffixes for __init__.py?
115
# this includes .py, .pyc, and .pyo (depending on if we are running -O)
116
# but it doesn't include compiled modules (.so, .dll, etc)
117
valid_suffixes = [suffix for suffix, mod_type, flags in imp.get_suffixes()
118
if flags in (imp.PY_SOURCE, imp.PY_COMPILED)]
119
package_entries = ['__init__'+suffix for suffix in valid_suffixes]
94
# going through them one by one allows different plugins with the same
95
# filename in different directories in the path
96
mutter('looking for plugins in %s' % d)
123
mutter('looking for plugins in %s', d)
99
124
plugin_names = set()
100
125
if not os.path.isdir(d):
102
127
for f in os.listdir(d):
103
path = os.path.join(d, f)
128
path = pathjoin(d, f)
104
129
if os.path.isdir(path):
105
130
for entry in package_entries:
106
131
# This directory should be a package, and thus added to
108
if os.path.isfile(os.path.join(path, entry)):
133
if os.path.isfile(pathjoin(path, entry)):
110
135
else: # This directory is not a package
113
for suffix_info in suffixes:
138
for suffix_info in imp.get_suffixes():
114
139
if f.endswith(suffix_info[0]):
115
140
f = f[:-len(suffix_info[0])]
116
141
if suffix_info[2] == imp.C_EXTENSION and f.endswith('module'):
121
mutter('add plugin name %s' % f)
146
if getattr(bzrlib.plugins, f, None):
147
mutter('Plugin name %s already loaded', f)
149
mutter('add plugin name %s', f)
124
152
plugin_names = list(plugin_names)
125
153
plugin_names.sort()
126
154
for name in plugin_names:
128
156
plugin_info = imp.find_module(name, [d])
129
mutter('load plugin %r' % (plugin_info,))
157
mutter('load plugin %r', plugin_info)
131
159
plugin = imp.load_module('bzrlib.plugins.' + name,
133
all_plugins.append(plugin)
134
161
setattr(bzrlib.plugins, name, plugin)
136
163
if plugin_info[0] is not None:
137
164
plugin_info[0].close()
139
166
mutter('loaded succesfully')
167
except KeyboardInterrupt:
170
## import pdb; pdb.set_trace()
143
171
warning('Unable to load plugin %r from %r' % (name, d))
144
172
log_exception_quietly()