# Copyright 2005-2015 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import print_function from portage import os from portage.exception import PortageException from portage.cache.mappings import ProtectedDict class InvalidModuleName(PortageException): """An invalid or unknown module name.""" class Module(object): """Class to define and hold our plug-in module @type name: string @param name: the module name @type path: the path to the new module """ def __init__(self, name, namepath): """Some variables initialization""" self.name = name self._namepath = namepath self.kids_names = [] self.kids = {} self.initialized = self._initialize() def _initialize(self): """Initialize the plug-in module @rtype: boolean """ self.valid = False try: mod_name = ".".join([self._namepath, self.name]) self._module = __import__(mod_name, [], [], ["not empty"]) self.valid = True except ImportError as e: print("MODULE; failed import", mod_name, " error was:", e) return False self.module_spec = self._module.module_spec for submodule in self.module_spec['provides']: kid = self.module_spec['provides'][submodule] kidname = kid['name'] kid['module_name'] = '.'.join([mod_name, self.name]) kid['is_imported'] = False self.kids[kidname] = kid self.kids_names.append(kidname) return True def get_class(self, name): if not name or name not in self.kids_names: raise InvalidModuleName("Module name '%s' was invalid or not" %name + "part of the module '%s'" %self.name) kid = self.kids[name] if kid['is_imported']: module = kid['instance'] else: try: module = __import__(kid['module_name'], [], [], ["not empty"]) kid['instance'] = module kid['is_imported'] = True except ImportError: raise mod_class = getattr(module, kid['class']) return mod_class class Modules(object): """Dynamic modules system for loading and retrieving any of the installed emaint modules and/or provided class's @param path: Path to the "modules" directory @param namepath: Python import path to the "modules" directory """ def __init__(self, path, namepath): self._module_path = path self._namepath = namepath self._modules = self._get_all_modules() self.modules = ProtectedDict(self._modules) self.module_names = sorted(self._modules) def _get_all_modules(self): """scans the emaint modules dir for loadable modules @rtype: dictionary of module_plugins """ module_dir = self._module_path importables = [] names = os.listdir(module_dir) for entry in names: # skip any __init__ or __pycache__ files or directories if entry.startswith('__'): continue try: # test for statinfo to ensure it should a real module # it will bail if it errors os.lstat(os.path.join(module_dir, entry, '__init__.py')) importables.append(entry) except EnvironmentError: pass kids = {} for entry in importables: new_module = Module(entry, self._namepath) for module_name in new_module.kids: kid = new_module.kids[module_name] kid['parent'] = new_module kids[kid['name']] = kid return kids def get_module_names(self): """Convienence function to return the list of installed modules available @rtype: list @return: the installed module names available """ return self.module_names def get_class(self, modname): """Retrieves a module class desired @type modname: string @param modname: the module class name """ if modname and modname in self.module_names: mod = self._modules[modname]['parent'].get_class(modname) else: raise InvalidModuleName("Module name '%s' was invalid or not" %modname + "found") return mod def get_description(self, modname): """Retrieves the module class decription @type modname: string @param modname: the module class name @type string @return: the modules class decription """ if modname and modname in self.module_names: mod = self._modules[modname]['description'] else: raise InvalidModuleName("Module name '%s' was invalid or not" %modname + "found") return mod def get_functions(self, modname): """Retrieves the module class exported function names @type modname: string @param modname: the module class name @type list @return: the modules class exported function names """ if modname and modname in self.module_names: mod = self._modules[modname]['functions'] else: raise InvalidModuleName("Module name '%s' was invalid or not" %modname + "found") return mod def get_func_descriptions(self, modname): """Retrieves the module class exported functions descriptions @type modname: string @param modname: the module class name @type dictionary @return: the modules class exported functions descriptions """ if modname and modname in self.module_names: desc = self._modules[modname]['func_desc'] else: raise InvalidModuleName("Module name '%s' was invalid or not" %modname + "found") return desc def get_opt_descriptions(self, modname): """Retrieves the module class exported options descriptions @type modname: string @param modname: the module class name @type dictionary @return: the modules class exported options descriptions """ if modname and modname in self.module_names: desc = self._modules[modname].get('opt_desc') else: raise InvalidModuleName( "Module name '%s' was invalid or not found" % modname) return desc