Module PluginManager
[hide private]
[frames] | no frames]

Source Code for Module PluginManager

  1  #!/usr/bin/env python 
  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   
24 -class PluginProxy(object):
25 """ 26 Simple proxy class to encapsulate a Storage Connect plugin. 27 """ 28
29 - def __init__(self, plugin_class):
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
59 - def __repr__(self):
60 return self.plugin_name #pylint: disable=E1101
61
62 - def __str__(self):
63 return "%s version %s by %s - %s" % (self.plugin_name, self.plugin_version, #pylint: disable=E1101 64 self.vendor_name, self.plugin_desc) #pylint: disable=E1101
65
66 - def __get_functions__(self):
67 return self.__plugin_func_names__[:]
68
69 - def __get_methods__(self):
70 return self.__plugin_method_names__[:]
71
72 - def __get_dict__(self):
73 return self.__plugin_class__.__dict__
74
75 -class PluginManager(object):
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):
81 """ 82 Constructor for the Storage Connect Plugin Manager. 83 """ 84 if not os.path.exists(IPlugin.__plugin_top_dir__): 85 raise PluginManagerError("No plugins installed!") 86 87 self.__plugins__ = [] 88 if IPlugin.__plugin_top_dir__ not in sys.path: 89 sys.path.append(IPlugin.__plugin_top_dir__) 90 91 if plugin_logger: 92 OSCPlugin.IPlugin.logger = plugin_logger
93
94 - def discoverPlugins(self, plugin_types = IPlugin.__plugin_types__, ignore_failed = False):
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
139 - def getPluginManagerClass(self, plugin_name, auto_import = True):
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
176 - def getPlugin(self, plugin_name):
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
191 - def getPluginNames(self):
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
200 - def getPluginPath(self, plugin_name):
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
216 - def getPluginModule(self, plugin_name):
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
232 - def importPlugin(self, plugin_name):
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
255 - def isPluginImported(self, plugin_name):
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
271 - def getImportedPluginNames(self):
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
280 - def getPluginInfo(self, plugin_name):
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
293 - def getPluginProxy(self, plugin_name):
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
309 - def setLogger(self, plugin_logger):
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
319 - def __iter__(self):
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
329 - def next(self):
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
338 -class Plugin(object):
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
358 - def getName(self):
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
367 - def getPath(self):
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
376 - def getModuleName(self):
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
397 - def importPlugin(self):
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
425 - def isImported(self):
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
434 - def getInfo(self):
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
445 - def getProxy(self):
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
457 - def __repr__(self):
458 """ 459 Allow displaying of the plugin names. 460 461 @return: Plugin name. 462 @rtype: C{str} 463 """ 464 return self.__plugin_name__
465
466 -class PluginManagerError(Exception):
467 """ 468 Plugin manager error exception. 469 """
470 - def __init__(self, msg):
471 self.msg = msg
472
473 - def __str__(self):
474 return repr(self.msg)
475