def load(self): if not self.FILE_PATH.is_file(): self.data = {} self.save() return with open(self.FILE_PATH, 'rb') as fd: try: self.data = pickle.load(fd) except Exception: try: import shelve s = shelve.open(self.FILE_PATH) for (k, v) in s.items(): self.data[k] = v if not isinstance(self.data, dict): raise GajimPluginException s.close() self.save() except Exception: enc = locale.getpreferredencoding() filename = self.FILE_PATH.decode(enc) + '.bak' log.warning( '%s plugin config file not readable. Saving it as ' '%s and creating a new one', self.plugin.short_name, filename) if os.path.exists(self.FILE_PATH + '.bak'): os.remove(self.FILE_PATH + '.bak') os.rename(self.FILE_PATH, self.FILE_PATH + '.bak') self.data = {} self.save()
def deactivate_plugin(self, plugin): # remove GUI extension points handlers (provided by plug-in) from # handlers list for gui_extpoint_name, gui_extpoint_handlers in \ plugin.gui_extension_points.items(): self.gui_extension_points_handlers[gui_extpoint_name].remove( gui_extpoint_handlers) # detaching plug-in from handler GUI extension points (calling # cleaning up method that must be provided by plug-in developer # for each handled GUI extension point) for gui_extpoint_name, gui_extpoint_handlers in \ plugin.gui_extension_points.items(): if gui_extpoint_name in self.gui_extension_points: for gui_extension_point_args in self.gui_extension_points[ gui_extpoint_name]: handler = gui_extpoint_handlers[1] if handler: try: handler(*gui_extension_point_args) except Exception as e: log.warning('Error executing %s', handler, exc_info=True) self._remove_events_handler_from_ged(plugin) self._remove_network_events_from_nec(plugin) self._remove_name_from_encryption_plugins(plugin) # removing plug-in from active plug-ins list plugin.deactivate() self.active_plugins.remove(plugin) self._set_plugin_active_in_global_config(plugin, False) plugin.active = False
def load_module(self): module_path = self.path / '__init__.py' if not module_path.exists(): # On Windows we only ship compiled files module_path = self.path / '__init__.pyc' module_name = self.path.stem try: spec = spec_from_file_location(module_name, module_path) if spec is None: return None module = module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) except Exception as error: log.warning('Error while loading module: %s', error) return None for module_attr_name in dir(module): module_attr = getattr(module, module_attr_name) if issubclass(module_attr, GajimPlugin): for field in FIELDS: setattr(module_attr, field, str(getattr(self, field))) setattr(module_attr, '__path__', str(self.path)) return module_attr return None
def load(self): if os.path.isfile(self.FILE_PATH): fd = open(self.FILE_PATH, 'rb') try: self.data = pickle.load(fd) fd.close() except: fd.close() try: import shelve s = shelve.open(self.FILE_PATH) for (k, v) in s.items(): self.data[k] = v if not isinstance(self.data, dict): raise GajimPluginException s.close() self.save() except: log.warning( '%s plugin config file not readable. Saving it as ' '%s and creating a new one' % (self.plugin.short_name, self.FILE_PATH.decode(locale.getpreferredencoding()) + '.bak')) if os.path.exists(self.FILE_PATH + '.bak'): os.remove(self.FILE_PATH + '.bak') os.rename(self.FILE_PATH, self.FILE_PATH + '.bak') self.data = {} self.save() else: self.data = {} self.save()
def _execute_all_handlers_of_gui_extension_point(self, gui_extpoint_name, *args): if gui_extpoint_name in self.gui_extension_points_handlers: for handlers in self.gui_extension_points_handlers[ gui_extpoint_name]: try: handlers[0](*args) except Exception as e: log.warning('Error executing %s', handlers[0], exc_info=True)
def install_from_zip(self, zip_filename, overwrite=None): ''' Install plugin from zip and return plugin ''' try: zip_file = zipfile.ZipFile(zip_filename) except zipfile.BadZipfile: # it is not zip file raise PluginsystemError(_('Archive corrupted')) except IOError: raise PluginsystemError(_('Archive empty')) if zip_file.testzip(): # CRC error raise PluginsystemError(_('Archive corrupted')) dirs = [] manifest = None for filename in zip_file.namelist(): if filename.startswith('.') or filename.startswith('/') or \ ('/' not in filename): # members not safe raise PluginsystemError(_('Archive is malformed')) if filename.endswith('/') and filename.find('/', 0, -1) < 0: dirs.append(filename.strip('/')) if 'manifest.ini' in filename.split('/')[1]: manifest = True if not manifest: return None if len(dirs) > 1: raise PluginsystemError(_('Archive is malformed')) plugin_name = dirs[0] user_dir = configpaths.get('PLUGINS_USER') plugin_path = user_dir / plugin_name if plugin_path.exists(): # Plugin dir already exists if not overwrite: raise PluginsystemError(_('Plugin already exists')) self.uninstall_plugin(self.get_plugin_by_path(str(plugin_path))) zip_file.extractall(user_dir) zip_file.close() plugin = self._load_plugin(plugin_path) if plugin is None: log.warning('Error while installing from zip') rmtree(plugin_path) raise PluginsystemError(_('Installation failed')) return self.add_plugin(plugin)
def _handle_all_gui_extension_points_with_plugin(self, plugin): for gui_extpoint_name, gui_extpoint_handlers in \ plugin.gui_extension_points.items(): if gui_extpoint_name in self.gui_extension_points: for gui_extension_point_args in self.gui_extension_points[ gui_extpoint_name]: handler = gui_extpoint_handlers[0] if handler: try: handler(*gui_extension_point_args) except Exception as e: log.warning('Error executing %s', handler, exc_info=True)
def update_plugins(self, replace=True, activate=False, plugin_name=None): ''' Move plugins from the downloaded folder to the user plugin folder :param replace: replace plugin files if they already exist. :type replace: boolean :param activate: load and activate the plugin :type activate: boolean :param plugin_name: if provided, update only this plugin :type plugin_name: str :return: list of updated plugins (files have been installed) :rtype: [] of str ''' updated_plugins = [] user_dir = configpaths.get('PLUGINS_USER') dl_dir = configpaths.get('PLUGINS_DOWNLOAD') to_update = [plugin_name] if plugin_name else next(os.walk(dl_dir))[1] for directory in to_update: src_dir = dl_dir / directory dst_dir = user_dir / directory try: if dst_dir.exists(): if not replace: continue self.delete_plugin_files(dst_dir) move(src_dir, dst_dir) except Exception: log.exception( 'Upgrade of plugin %s failed. ' 'Impossible to move files from "%s" to "%s"', directory, src_dir, dst_dir) continue updated_plugins.append(directory) if activate: plugin = self._load_plugin(Path(dst_dir)) if plugin is None: log.warning('Error while updating plugin') continue self.add_plugin(plugin, activate=True) return updated_plugins
def scan_dir_for_plugins(path, scan_dirs=True, package=False): r''' Scans given directory for plugin classes. :param path: directory to scan for plugins :type path: str :param scan_dirs: folders inside path are processed as modules :type scan_dirs: boolean :param package: if path points to a single package folder :type package: boolean :return: list of found plugin classes (subclasses of `GajimPlugin` :rtype: [] of class objects :note: currently it only searches for plugin classes in '\*.py' files present in given directory `path` (no recursion here) :todo: add scanning zipped modules ''' from gajim.plugins.plugins_i18n import _ plugins_found = [] conf = configparser.ConfigParser() fields = ('name', 'short_name', 'version', 'description', 'authors', 'homepage') if not os.path.isdir(path): return plugins_found if package: path, package_name = os.path.split(path) dir_list = [package_name] else: dir_list = os.listdir(path) sys.path.insert(0, path) for elem_name in dir_list: file_path = os.path.join(path, elem_name) if os.path.isfile(file_path) and fnmatch.fnmatch( file_path, '*.py'): module_name = os.path.splitext(elem_name)[0] elif os.path.isdir(file_path) and scan_dirs: module_name = elem_name file_path += os.path.sep else: continue manifest_path = os.path.join(os.path.dirname(file_path), 'manifest.ini') if scan_dirs and (not os.path.isfile(manifest_path)): continue # read metadata from manifest.ini conf.remove_section('info') with open(manifest_path, encoding='utf-8') as conf_file: try: conf.read_file(conf_file) except configparser.Error: log.warning(("Plugin {plugin} not loaded, error loading" " manifest").format(plugin=elem_name), exc_info=True) continue min_v = conf.get('info', 'min_gajim_version', fallback=None) max_v = conf.get('info', 'max_gajim_version', fallback=None) gajim_v = gajim.__version__.split('+', 1)[0] gajim_v_cmp = parse_version(gajim_v) if min_v and gajim_v_cmp < parse_version(min_v): log.warning(('Plugin {plugin} not loaded, newer version of' 'gajim required: {gajim_v} < {min_v}').format( plugin=elem_name, gajim_v=gajim_v, min_v=min_v)) continue if max_v and gajim_v_cmp > parse_version(max_v): log.warning(('Plugin {plugin} not loaded, plugin incompatible ' 'with current version of gajim: ' '{gajim_v} > {max_v}').format(plugin=elem_name, gajim_v=gajim_v, max_v=max_v)) continue module = None try: log.info('Loading %s', module_name) module = __import__(module_name) except Exception as error: log.warning( "While trying to load {plugin}, exception occurred".format( plugin=elem_name), exc_info=sys.exc_info()) continue if module is None: continue log.debug('Attributes processing started') for module_attr_name in [ attr_name for attr_name in dir(module) if not ( attr_name.startswith('__') or attr_name.endswith('__')) ]: module_attr = getattr(module, module_attr_name) log.debug('%s : %s' % (module_attr_name, module_attr)) try: if not issubclass(module_attr, GajimPlugin) or \ module_attr is GajimPlugin: continue log.debug('is subclass of GajimPlugin') module_attr.__path__ = os.path.abspath( os.path.dirname(file_path)) for option in fields: if conf.get('info', option) is '': raise configparser.NoOptionError(option, 'info') if option == 'description': setattr(module_attr, option, _(conf.get('info', option))) continue setattr(module_attr, option, conf.get('info', option)) plugins_found.append(module_attr) except TypeError: # set plugin localization try: module_attr._ = _ except AttributeError: pass except configparser.NoOptionError: # all fields are required log.debug( '%s : %s' % (module_attr_name, 'wrong manifest file. all fields are required!')) except configparser.NoSectionError: # info section are required log.debug( '%s : %s' % (module_attr_name, 'wrong manifest file. info section are required!')) except configparser.MissingSectionHeaderError: # info section are required log.debug('%s : %s' % (module_attr_name, 'wrong manifest file. section are required!')) sys.path.remove(path) return plugins_found
def _load_plugin(plugin_path): try: return Plugin.from_manifest(plugin_path) except Exception as error: log.warning(error)