1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import sys
18 import os.path
19
20 from libxyz.exceptions import PluginError
21 from libxyz.exceptions import XYZValueError
22 from libxyz.core.plugins import BasePlugin
23 from libxyz.core.plugins import Namespace
24 from libxyz.core.utils import ustring
38
39 return _trans
40
44 """
45 Plugin manager class
46 It is supposed to provide easy access to plugin data
47 """
48
49 PLUGIN_CLASS = u"XYZPlugin"
50 PLUGIN_FILE = u"main"
51 VIRTUAL_NAMESPACE = u"sys"
52
54 """
55 @param xyz: XYZ data
56 @param dirs: Plugin directories list
57 @type dirs: list
58 """
59
60 if not isinstance(dirs, list):
61 raise XYZValueError(_(u"Invalid argument type %s. List expected" %
62 type(dirs)))
63 else:
64 sys.path.extend(dirs)
65
66 self.xyz = xyz
67
68 self.enabled = self._enabled_list()
69
70
71 self._loaded = {}
72 self._waiting = {}
73
74
75
76 @ns_transform
77 - def load(self, plugin, *initargs, **initkwargs):
78 """
79 Load and initiate required plugin
80 @param plugin: Plugin namespace path
81 @param initargs: Necessary arguments to initiate plugin
82 @param initkwargs: Necessary kw arguments to initiate plugin
83 """
84
85 virtual = self.is_virtual(plugin)
86
87 if plugin.pfull not in self.enabled:
88 raise PluginError(_(u"Plugin %s is disabled or does not exist" %
89 plugin))
90
91 if self.is_loaded(plugin):
92 return self.get_loaded(plugin)
93
94 if virtual:
95
96
97 return None
98
99 plugin.set_method(self.PLUGIN_FILE)
100
101
102
103 try:
104 _loaded = __import__(plugin.internal, globals(), locals(),
105 [self.PLUGIN_CLASS])
106 except ImportError, e:
107 raise PluginError(_(u"Unable to load plugin %s: %s" % (plugin, e)))
108
109 try:
110 _loaded = getattr(_loaded, self.PLUGIN_CLASS)
111 except AttributeError, e:
112 raise PluginError(_(u"Unable to find required %s class" % \
113 self.PLUGIN_CLASS))
114
115
116 _obj = _loaded(self.xyz, *initargs, **initkwargs)
117
118
119 _obj.prepare()
120
121 self.set_loaded(plugin, _obj)
122
123 return _obj
124
125
126
127 @ns_transform
128 - def reload(self, plugin, *initargs, **initkwargs):
129 """
130 Force load plugin if it's already in cache.
131 """
132
133 if self.is_virtual(plugin):
134
135 return None
136
137 if self.is_loaded(plugin):
138 self.del_loaded(plugin)
139
140 return self.load(plugin, *initargs, **initkwargs)
141
142
143
144 @ns_transform
146 """
147 Load method from plugin.
148 If plugin was not loaded before, load and initiate it first.
149
150 @param plugin: Plugin namespace path
151 @param method: Public method name
152 """
153
154 if not self.is_loaded(plugin):
155 _obj = self.load(plugin)
156 else:
157 _obj = self.get_loaded(plugin)
158
159
160 if _obj is None:
161 return None
162
163 if method not in _obj.public:
164 raise PluginError(_(u"%s plugin instance does not export "\
165 u"method %s" % (plugin, method)))
166 else:
167 return _obj.public[method]
168
169
170
171 @ns_transform
173 """
174 Load data object from plugin.
175 If plugin was not loaded before, load and initiate it first.
176
177 @param plugin: Plugin namespace path
178 @param method: Public data object name
179 """
180
181 if not self.is_loaded(plugin):
182 _obj = self.load(plugin)
183 else:
184 _obj = self.get_loaded(plugin)
185
186 if obj not in _obj.public_data:
187 raise PluginError(_(u"%s plugin instance does not export "\
188 u"data object %s" % (plugin, obj)))
189 else:
190 return _obj.public_data[obj]
191
192
193
194 @ns_transform
196 """
197 Check if plugin already loaded
198 @param plugin: Plugin namespace path
199 """
200
201 return plugin.full in self._loaded
202
203
204
205 @ns_transform
207 """
208 Return loaded and initiated inistance of plugin
209 @param plugin: Plugin namespace path
210 """
211
212 return self._loaded[plugin.pfull]
213
214
215
217 """
218 Return all currenty loaded plugins as dictionary with plugins ns path
219 as keys and instances as values
220 """
221
222 return self._loaded
223
224
225
226 @ns_transform
228 """
229 Set loaded and initiated inistance of plugin
230 @param plugin: Plugin namespace path
231 @param inst: Plugin instance
232 """
233
234
235 if plugin.pfull in self._waiting:
236
237 for _cb, _args in self._waiting[plugin.pfull]:
238 try:
239 _cb(inst, *_args)
240 except Exception, e:
241 xyzlog.warning(_(u"Error in wait_for() callback: %s" %
242 ustring(str(e))))
243 del(self._waiting[plugin.pfull])
244
245 self._loaded[plugin.pfull] = inst
246
247
248
249 @ns_transform
251 """
252 Delete loaded instance from cache
253 @param plugin: Plugin namespace path
254 """
255
256 try:
257 self.shutdown(plugin.pfull)
258 del(self._loaded[plugin.pfull])
259 except KeyError:
260 pass
261
262
263
264 @ns_transform
265 - def wait_for(self, plugin, callback, *args):
266 """
267 Some virtual plugins are not available at the parsing time.
268 This method is used to wait while plugin is loaded and then run
269 callback.
270 Arguments to callback: loaded plugin obj, and all optional *args passed
271 """
272
273
274 if self.is_loaded(plugin):
275 return callback(self.get_loaded(plugin), *args)
276
277
278 if plugin.pfull not in self._waiting:
279 self._waiting[plugin.pfull] = []
280
281
282 self._waiting[plugin.pfull].append((callback, args))
283
284
285
287 """
288 Run destructors on specified or all loaded plugins
289 """
290
291 def _fin(p):
292 try:
293 self._loaded[p].finalize()
294 except Exception:
295 pass
296
297
298
299 if plugin is not None:
300 _fin(plugin)
301 else:
302 for plugin_name in self._loaded:
303 _fin(plugin_name)
304
305
306
308 """
309 Register new plugin.
310 @param obj: libxyz.core.BasePlugin inherited instance
311 """
312
313 if not isinstance(obj, BasePlugin):
314 raise XYZValueError(_(u"BasePlugin instance expected, got: %s" %
315 type(obj)))
316
317 self.set_loaded(obj.ns, obj)
318
319
320
323
324
325
327 """
328 Make list of enabled plugins
329 """
330
331 _data = self.xyz.conf[u"xyz"][u"plugins"]
332 return [_pname for _pname in _data if _data[_pname]]
333