1
2
3 """
4 @copyright: Copyright (C) 2008, 2010 Oracle and/or its affiliates. All rights reserved.
5
6 @license: See the file COPYING for redistribution information.
7
8 @summary: Simple plugin manager used to discover and use Storage Connect plugins.
9 """
10
11 import os
12 import sys
13 import inspect
14 import gettext
15
16 import OSCPlugin
17
18 from OSCPlugin import IPlugin
19
20 _ = gettext.gettext
21
22 __docformat__ = "epytext en"
23
25 """
26 Simple proxy class to encapsulate a Storage Connect plugin.
27 """
28
30 """
31 Proxy class constructor.
32
33 @param plugin_class: Specific Storage Connect plugin class.
34 @type plugin_class: L{IPlugin class<IPlugin.IPlugin>}
35 """
36 if not issubclass(plugin_class, IPlugin):
37 raise TypeError("Supplied class is not a IPlugin class!")
38
39 self.__plugin_class__ = plugin_class
40 self.__plugin_methods__ = inspect.getmembers(plugin_class, inspect.ismethod)
41 self.__plugin_method_names__ = []
42 for name, value in self.__plugin_methods__:
43 if not name.startswith("_"):
44 self.__setattr__(name, value)
45 self.__plugin_method_names__.append(name)
46
47 self.__plugin_functions__ = inspect.getmembers(plugin_class, inspect.isfunction)
48 self.__plugin_func_names__ = []
49 for name, value in self.__plugin_functions__:
50 if not name.startswith("_"):
51 self.__setattr__(name, value)
52 self.__plugin_func_names__.append(name)
53
54 self.__plugin_info__ = plugin_class.getPluginInfo()
55 for name in self.__plugin_info__:
56 if not name.startswith("_"):
57 self.__setattr__(name, self.__plugin_info__[name])
58
61
65
67 return self.__plugin_func_names__[:]
68
70 return self.__plugin_method_names__[:]
71
73 return self.__plugin_class__.__dict__
74
76 """
77 Class used by Storage Connect Plugin consumers to discover and use the installed plugins.
78 """
79
80 - def __init__(self, plugin_logger = None):
93
95 """
96 Discover all installed Storage Connect plugins on the system.
97
98 @param plugin_types: L{Optional Plugin types to discover<IPlugin.__plugin_types__>}
99 @type plugin_types: C{list}
100
101 @param ignore_failed: Optional flag to ignore all failures
102 @type ignore_failed: C{bool}
103
104 @return: list of newly discovered Storage Connect Plugins.
105 @rtype: C{list}
106 """
107 failed = []
108 plugins = []
109 for vendor_dir in os.listdir(IPlugin.__plugin_top_dir__):
110 vendor_path = os.path.join(IPlugin.__plugin_top_dir__, vendor_dir)
111 if not os.path.isdir(vendor_path) or vendor_dir.startswith('.'):
112 continue
113
114 for plugin_mod_dir in os.listdir(vendor_path):
115 plugin_mod_path = os.path.join(vendor_path, plugin_mod_dir)
116 if os.path.isdir(plugin_mod_path) and not plugin_mod_dir.startswith('.'):
117 plugin_mod_name = "%s.%s" % (vendor_dir, plugin_mod_dir)
118 try:
119 plugin_mod = __import__(plugin_mod_name, globals(), locals(), plugin_mod_dir)
120
121 except Exception:
122 failed.append(plugin_mod_name)
123 continue
124
125 for plugin_type in plugin_types:
126 plugin_names = plugin_mod.__dict__.get("osc_%s_plugins" % plugin_type, None)
127 if plugin_names:
128 for plugin_name in plugin_names:
129 if plugin_name not in self.__plugins__:
130 self.__plugins__.append(Plugin(plugin_name,
131 plugin_mod))
132 plugins.append(plugin_name)
133
134 if len(failed) > 0 and not ignore_failed:
135 raise PluginManagerError(_("Failed to to load plugins: %s" % (','.join(failed))))
136
137 return plugins
138
140 """
141 Get the Plugin Manager class for the named plugin.
142
143 @return: Plugin Manager class for the named Storage Connect plugin.
144 @rtype: C{Plugin}
145 """
146 for plugin in self.__plugins__:
147 if plugin.getName() == plugin_name:
148 return plugin
149
150 try:
151 plugin_mod_name, class_name = plugin_name.rsplit('.', 1)
152
153 except ValueError:
154 raise PluginManagerError(_("Illegal plugin implementation name format,"
155 " should be vendor.module.file.class"))
156
157 plugin_mod = __import__(plugin_mod_name, globals(), locals(), class_name)
158 pkg_name = plugin_mod.__dict__.get("__package__", None)
159 if pkg_name:
160 vendor_name, mod_name = pkg_name.rsplit('.', 1)
161 try:
162 plugin_mod = __import__(pkg_name, globals(), locals(), mod_name)
163
164 except ImportError:
165 raise PluginManagerError(_("Failed to to load plugin"))
166
167 plugin = Plugin(plugin_name, plugin_mod)
168 if auto_import:
169 plugin.getClass(auto_import)
170
171 if plugin not in self.__plugins__:
172 self.__plugins__.append(plugin)
173
174 return plugin
175
177 """
178 Get the Plugin class for the named plugin.
179
180 @return: Plugin class for the named Storage Connect plugin.
181 @rtype: C{IPlugin class}
182 """
183 for plugin in self.__plugins__:
184 if plugin.getName() == plugin_name:
185 return plugin.getClass()
186
187 else:
188 plugin = self.getPluginManagerClass(plugin_name)
189 return plugin.getClass()
190
192 """
193 Get the list of known plugin names.
194
195 @return: list of known Storage Connect plugin names.
196 @rtype: C{list}
197 """
198 return [plugin.getName() for plugin in self.__plugins__]
199
201 """
202 Get the install path for a specific plugin.
203
204 @param plugin_name: Name of the specific plugin.
205 @type plugin_name: C{str}
206
207 @return: list of newly discovered Storage Connect Plugins.
208 @rtype: C{list}
209 """
210 for plugin in self.__plugins__:
211 if plugin.getName() == plugin_name:
212 return plugin.getPath()
213
214 return None
215
217 """
218 Get the plugin's module name.
219
220 @param plugin_name: Name of the specific plugin.
221 @type plugin_name: C{str}
222
223 @return: module of the Storage Connect Plugin.
224 @rtype: C{str}
225 """
226 for plugin in self.__plugins__:
227 if plugin.getName() == plugin_name:
228 return plugin.getModuleName()
229
230 return None
231
233 """
234 Import the plugin.
235
236 @param plugin_name: Name of the plugin that should be imported.
237 @type plugin_name: C{str}
238
239 @return: Class object for the plugin.
240 @rtype: C{list}
241 """
242 for plugin in self.__plugins__:
243 if plugin_name == plugin.getName():
244 try:
245 return plugin.importPlugin()
246
247 except:
248 if plugin in self.__plugins__:
249 self.__plugins__.remove(plugin)
250
251 raise
252
253 return None
254
256 """
257 Get a list of names for all the imported plugins.
258
259 @param plugin_name: Name of the plugin to check.
260 @type plugin_name: C{str}
261
262 @return: True if the plugin is found and imported.
263 @rtype: C{bool}
264 """
265 for plugin in self.__plugins__:
266 if plugin_name == plugin.getName():
267 return plugin.isImported()
268
269 return False
270
272 """
273 Get a list of names for all the imported plugins.
274
275 @return: list of names of all the imported plugins.
276 @rtype: C{list}
277 """
278 return [plugin.getName() for plugin in self.__plugins__ if plugin.isImported()]
279
281 """
282 Get the information for the specified plugin.
283
284 @return: information on and about the Storage Connect plug-in.
285 @rtype: C{dict}
286 """
287 for plugin in self.__plugins__:
288 if plugin.getName() == plugin_name:
289 return plugin.getInfo()
290
291 return None
292
294 """
295 Get a proxy class for the plugin.
296
297 @param plugin_name: Name of the plugin to obtain a proxy for.
298 @type plugin_name: C{str}
299
300 @return: The L{Plugin Proxy class<PluginProxy>} for the plugin.
301 @rtype: L{PluginProxy}
302 """
303 for plugin in self.__plugins__:
304 if plugin.getName() == plugin_name:
305 return plugin.getProxy()
306
307 return None
308
310 """
311 Change the logger the plugin should use.
312
313 @param plugin_logger: Set the C{Logger} to use by the plugin
314 @type plugin_logger: C{logger}
315
316 """
317 OSCPlugin.IPlugin.logger = plugin_logger
318
320 """
321 Get an iterator object.
322
323 @return: Iterator object.
324 @rtype: C{iter}
325 """
326 self.__plugins_iter__ = self.__plugins__.__iter__()
327 return self
328
330 """
331 Get the next iterator value.
332
333 @return: Next iterator object.
334 @rtype: C{iter}
335 """
336 return self.__plugins_iter__.next()
337
339 """
340 Class encapsulating the Storage Connect plugin
341 """
342
343 - def __init__(self, plugin_name, plugin_module):
344 """
345 Construstor for the Plugin encapsulation class.
346
347 @param plugin_name: Name of the plugin.
348 @type plugin_name: C{str}
349
350 @param plugin_module: Plugin module.
351 @type plugin_module: C{object}
352 """
353 self.__plugin_name__ = plugin_name
354 self.__plugin_module__ = plugin_module
355 self.__class_module__ = None
356 self.__plugin_class__ = None
357
359 """
360 Get the plugin's fully qualified name.
361
362 @return: Fully Qualified name of the plugin.
363 @rtype: C{str}
364 """
365 return self.__plugin_name__
366
368 """
369 Get the plugin's path.
370
371 @return: Path to the plugin.
372 @rtype: C{str}
373 """
374 return self.__plugin_module__.__path__[0]
375
377 """
378 Get the plugin's module name.
379
380 @return: Module name of the plugin.
381 @rtype: C{str}
382 """
383 return self.__plugin_module__.__name__
384
385 - def getClass(self, auto_import = True):
386 """
387 Get the plugin's list of classes.
388
389 @return: Class objects for the plugin (if it is already imported).
390 @rtype: C{list}
391 """
392 if not self.__plugin_class__ and auto_import:
393 self.importPlugin()
394
395 return self.__plugin_class__
396
398 """
399 Import the IPlugin class.
400 """
401 mod_name, class_name = self.__plugin_name__.rsplit('.', 1)
402 try:
403 self.__class_module__ = __import__(mod_name, globals(), locals(), class_name)
404
405 except ImportError, imp_err:
406 if imp_err.__dict__.has_key("args"):
407 raise PluginManagerError(_("Unable to import plugin %s (%s)" % (self.__plugin_name__, imp_err.args[0])))
408
409 else:
410 raise PluginManagerError(_("Unable to import plugin %s (%s)" % (self.__plugin_name__, imp_err.message)))
411
412 self.__plugin_class__ = self.__class_module__.__dict__.get(class_name, None)
413 if not self.__plugin_class__:
414 raise PluginManagerError(_("Unable to import plugin %s" % self.__plugin_name__))
415
416 required_api_vers = self.__plugin_class__.__dict__.get("required_api_vers", None)
417 if required_api_vers is None:
418 raise PluginManagerError(_("Unable to import plugin %s, plugin did not set minimum API level!" % self.__plugin_name__))
419
420 if int("".join(required_api_vers)) > int("".join(IPlugin.plugin_api_version)):
421 raise PluginManagerError(_("Unable to import plugin %s, plugin require API version %.2f" %
422 (self.__plugin_name__,
423 int("".join(required_api_vers)) / 100.0)))
424
426 """
427 Check if the Plugin is already imported.
428
429 @return: True if the Plugin is already imported.
430 @rtype: C{bool}
431 """
432 return (self.__plugin_class__ != None)
433
435 """
436 Get the information for the plugin.
437
438 @return: information on and about the Storage Connect plug-in.
439 @rtype: C{dict}
440 """
441 p_class = self.getClass(auto_import = True)
442 p_info = p_class.getPluginInfo()
443 return p_info
444
446 """
447 Get a proxy instance for the plugin class.
448
449 @return: Plugin proxy instance.
450 @rtype: L{Plugin proxy instance<PluginProxy>}
451 """
452 if self.__plugin_class__:
453 return PluginProxy(self.__plugin_class__)
454
455 return None
456
458 """
459 Allow displaying of the plugin names.
460
461 @return: Plugin name.
462 @rtype: C{str}
463 """
464 return self.__plugin_name__
465
467 """
468 Plugin manager error exception.
469 """
472
474 return repr(self.msg)
475