From 506f9dc643acf1cb9fb13c4fd27940a8ea110352 Mon Sep 17 00:00:00 2001 From: Doug Blank Date: Fri, 13 Aug 2010 04:19:16 +0000 Subject: [PATCH] Refactor to move load_addon_file out of gui code svn: r15719 --- src/gen/plug/utils.py | 232 +++++++++++++++++++++++++++++++++++++++ src/gui/plug/_windows.py | 212 +---------------------------------- 2 files changed, 236 insertions(+), 208 deletions(-) diff --git a/src/gen/plug/utils.py b/src/gen/plug/utils.py index 8a97e4755..d5555c350 100644 --- a/src/gen/plug/utils.py +++ b/src/gen/plug/utils.py @@ -30,7 +30,22 @@ General utility functions useful for the generic plugin system # #------------------------------------------------------------------------- import locale +import sys +import os +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from gen.plug._pluginreg import make_environment +import const + +#------------------------------------------------------------------------- +# +# Local utility functions for gen.plug +# +#------------------------------------------------------------------------- def gfloat(val): """Convert to floating number, taking care of possible locale differences. @@ -57,3 +72,220 @@ def gformat(val): decimal_point = locale.localeconv()['decimal_point'] return_val = "%.3f" % val return return_val.replace(decimal_point, '.') + +def version_str_to_tup(sversion, positions): + """ + Given a string version and positions count, returns a tuple of + integers. + + >>> version_str_to_tup("1.02.9", 2) + (1, 2) + """ + try: + tup = tuple(([int(n) for n in + sversion.split(".", sversion.count("."))] + + [0] * positions)[0:positions]) + except: + tup = (0,) * positions + return tup + +class newplugin(object): + """ + Fake newplugin. + """ + def __init__(self): + globals()["register_results"].append({}) + def __setattr__(self, attr, value): + globals()["register_results"][-1][attr] = value + +def register(ptype, **kwargs): + """ + Fake registration. Side-effect sets register_results to kwargs. + """ + retval = {"ptype": ptype} + retval.update(kwargs) + # Get the results back to calling function + if "register_results" in globals(): + globals()["register_results"].append(retval) + else: + globals()["register_results"] = [retval] + +class Zipfile(object): + """ + Class to duplicate the methods of tarfile.TarFile, for Python 2.5. + """ + def __init__(self, buffer): + import zipfile + self.buffer = buffer + self.zip_obj = zipfile.ZipFile(buffer) + + def extractall(self, path, members=None): + """ + Extract all of the files in the zip into path. + """ + names = self.zip_obj.namelist() + for name in self.get_paths(names): + fullname = os.path.join(path, name) + if not os.path.exists(fullname): + os.mkdir(fullname) + for name in self.get_files(names): + fullname = os.path.join(path, name) + outfile = file(fullname, 'wb') + outfile.write(self.zip_obj.read(name)) + outfile.close() + + def extractfile(self, name): + """ + Extract a name from the zip file. + + >>> Zipfile(buffer).extractfile("Dir/dile.py").read() + + """ + class ExtractFile(object): + def __init__(self, zip_obj, name): + self.zip_obj = zip_obj + self.name = name + def read(self): + data = self.zip_obj.read(self.name) + del self.zip_obj + return data + return ExtractFile(self.zip_obj, name) + + def close(self): + """ + Close the zip object. + """ + self.zip_obj.close() + + def getnames(self): + """ + Get the files and directories of the zipfile. + """ + return self.zip_obj.namelist() + + def get_paths(self, items): + """ + Get the directories from the items. + """ + return (name for name in items if self.is_path(name) and not self.is_file(name)) + + def get_files(self, items): + """ + Get the files from the items. + """ + return (name for name in items if self.is_file(name)) + + def is_path(self, name): + """ + Is the name a path? + """ + return os.path.split(name)[0] + + def is_file(self, name): + """ + Is the name a directory? + """ + return os.path.split(name)[1] + +def load_addon_file(path, callback=None, register_plugin=None): + """ + Load an addon from a particular path (from URL or file system). + """ + import urllib + import tarfile + import cStringIO + if (path.startswith("http://") or + path.startswith("https://") or + path.startswith("ftp://")): + try: + fp = urllib.urlopen(path) + except: + if callback: + callback(_("Unable to open '%s'") % path) + return + else: + try: + fp = open(path) + except: + if callback: + callback(_("Unable to open '%s'") % path) + return + buffer = cStringIO.StringIO(fp.read()) + fp.close() + # file_obj is either Zipfile or TarFile + if path.endswith(".zip") or path.endswith(".ZIP"): + file_obj = Zipfile(buffer) + elif path.endswith(".tar.gz") or path.endswith(".tgz"): + try: + file_obj = tarfile.open(None, fileobj=buffer) + except: + if callback: + callback(_("Error: cannot open '%s'") % path) + return + else: + if callback: + callback(_("Error: unknown file type: '%s'") % path) + return + # First, see what versions we have/are getting: + good_gpr = set() + for gpr_file in [name for name in file_obj.getnames() if name.endswith(".gpr.py")]: + if callback: + callback((_("Examining '%s'...") % gpr_file) + "\n") + contents = file_obj.extractfile(gpr_file).read() + # Put a fake register and _ function in environment: + env = make_environment(register=register, + newplugin=newplugin, + _=lambda text: text) + # clear out the result variable: + globals()["register_results"] = [] + # evaluate the contents: + try: + exec(contents, env) + except: + if callback: + msg = _("Error in '%s' file: cannot load.") % gpr_file + callback(" " + msg + "\n") + continue + # There can be multiple addons per gpr file: + for results in globals()["register_results"]: + gramps_target_version = results.get("gramps_target_version", None) + if gramps_target_version: + vtup = version_str_to_tup(gramps_target_version, 2) + # Is it for the right version of gramps? + if vtup == const.VERSION_TUPLE[0:2]: + # If this version is not installed, or > installed, install it + good_gpr.add(gpr_file) + if callback: + callback(" " + (_("'%s' is for this version of Gramps.") % gpr_file) + "\n") + else: + # If the plugin is for another version; inform and do nothing + if callback: + callback(" " + (_("'%s' is NOT for this version of Gramps.") % gpr_file) + "\n") + callback(" " + (_("It is for version %d.%d" % vtup) + "\n")) + continue + else: + # another register function doesn't have gramps_target_version + if gpr_file in good_gpr: + s.remove(gpr_file) + if callback: + callback(" " + (_("Error: missing gramps_target_version in '%s'...") % gpr_file) + "\n") + if len(good_gpr) > 0: + # Now, install the ok ones + file_obj.extractall(const.USER_PLUGINS) + if callback: + callback((_("Installing '%s'...") % path) + "\n") + gpr_files = set([os.path.split(os.path.join(const.USER_PLUGINS, name))[0] + for name in good_gpr]) + for gpr_file in gpr_files: + # Convert gpr_file to unicode otherwise the callback will not + # work with non ASCII characters in filenames in Windows. + # But don't use converted filenames + # in the call to self.__pmgr.reg_plugins + # as that will break in reg_plugins. + u_gpr_file = unicode(gpr_file, sys.getfilesystemencoding()) + if callback: + callback(" " + (_("Registered '%s'") % u_gpr_file) + "\n") + if register_plugin: + register_plugin(gpr_file) + file_obj.close() + diff --git a/src/gui/plug/_windows.py b/src/gui/plug/_windows.py index 617308edc..0add06253 100644 --- a/src/gui/plug/_windows.py +++ b/src/gui/plug/_windows.py @@ -47,7 +47,7 @@ import gobject #------------------------------------------------------------------------- import ManagedWindow import Errors -from gen.plug import PluginRegister, PTYPE_STR, make_environment +from gen.plug import PluginRegister, PTYPE_STR, load_addon_file from gen.ggettext import gettext as _ from gui.utils import open_file_with_default_application from gui.pluginmanager import GuiPluginManager @@ -64,120 +64,6 @@ def display_message(message): """ print message -def version_str_to_tup(sversion, positions): - """ - Given a string version and positions count, returns a tuple of - integers. - - >>> version_str_to_tup("1.02.9", 2) - (1, 2) - """ - try: - tup = tuple(([int(n) for n in - sversion.split(".", sversion.count("."))] + - [0] * positions)[0:positions]) - except: - tup = (0,) * positions - return tup - -class newplugin(object): - """ - Fake newplugin. - """ - def __init__(self): - globals()["register_results"].append({}) - def __setattr__(self, attr, value): - globals()["register_results"][-1][attr] = value - -def register(ptype, **kwargs): - """ - Fake registration. Side-effect sets register_results to kwargs. - """ - retval = {"ptype": ptype} - retval.update(kwargs) - # Get the results back to calling function - if "register_results" in globals(): - globals()["register_results"].append(retval) - else: - globals()["register_results"] = [retval] - -class Zipfile(object): - """ - Class to duplicate the methods of tarfile.TarFile, for Python 2.5. - """ - def __init__(self, buffer): - import zipfile - self.buffer = buffer - self.zip_obj = zipfile.ZipFile(buffer) - - def extractall(self, path, members=None): - """ - Extract all of the files in the zip into path. - """ - names = self.zip_obj.namelist() - for name in self.get_paths(names): - fullname = os.path.join(path, name) - if not os.path.exists(fullname): - os.mkdir(fullname) - for name in self.get_files(names): - fullname = os.path.join(path, name) - outfile = file(fullname, 'wb') - outfile.write(self.zip_obj.read(name)) - outfile.close() - - def extractfile(self, name): - """ - Extract a name from the zip file. - - >>> Zipfile(buffer).extractfile("Dir/dile.py").read() - - """ - class ExtractFile(object): - def __init__(self, zip_obj, name): - self.zip_obj = zip_obj - self.name = name - def read(self): - data = self.zip_obj.read(self.name) - del self.zip_obj - return data - return ExtractFile(self.zip_obj, name) - - def close(self): - """ - Close the zip object. - """ - self.zip_obj.close() - - def getnames(self): - """ - Get the files and directories of the zipfile. - """ - return self.zip_obj.namelist() - - def get_paths(self, items): - """ - Get the directories from the items. - """ - return (name for name in items if self.is_path(name) and not self.is_file(name)) - - def get_files(self, items): - """ - Get the files from the items. - """ - return (name for name in items if self.is_file(name)) - - def is_path(self, name): - """ - Is the name a path? - """ - return os.path.split(name)[0] - - def is_file(self, name): - """ - Is the name a directory? - """ - return os.path.split(name)[1] - #------------------------------------------------------------------------- # # PluginStatus: overview of all plugins @@ -493,7 +379,8 @@ class PluginStatus(ManagedWindow.ManagedWindow): pm.step() (help_name, name, ptype, image, desc, use, rating, contact, download, url) = row - self.__load_addon_file(url, callback=pm.append_message) + load_addon_file(url, callback=pm.append_message, + register_plugin=self.__pmgr.reg_plugins) pm.message_area_ok.set_sensitive(True) self.__rebuild_load_list() self.__rebuild_reg_list() @@ -515,101 +402,10 @@ class PluginStatus(ManagedWindow.ManagedWindow): Get an addon from the wiki or file system and install it. """ path = self.install_addon_path.get_text() - self.__load_addon_file(path, callback) + load_addon_file(path, callback, self.__pmgr.reg_plugins) self.__rebuild_load_list() self.__rebuild_reg_list() - def __load_addon_file(self, path, callback=display_message): - """ - Load an addon from a particular path (from URL or file system). - """ - import urllib - import tarfile - import cStringIO - if (path.startswith("http://") or - path.startswith("https://") or - path.startswith("ftp://")): - try: - fp = urllib.urlopen(path) - except: - callback(_("Unable to open '%s'") % path) - return - else: - try: - fp = open(path) - except: - callback(_("Unable to open '%s'") % path) - return - buffer = cStringIO.StringIO(fp.read()) - fp.close() - # file_obj is either Zipfile or TarFile - if path.endswith(".zip") or path.endswith(".ZIP"): - file_obj = Zipfile(buffer) - elif path.endswith(".tar.gz") or path.endswith(".tgz"): - try: - file_obj = tarfile.open(None, fileobj=buffer) - except: - callback(_("Error: cannot open '%s'") % path) - return - else: - callback(_("Error: unknown file type: '%s'") % path) - return - # First, see what versions we have/are getting: - good_gpr = set() - for gpr_file in [name for name in file_obj.getnames() if name.endswith(".gpr.py")]: - callback((_("Examining '%s'...") % gpr_file) + "\n") - contents = file_obj.extractfile(gpr_file).read() - # Put a fake register and _ function in environment: - env = make_environment(register=register, - newplugin=newplugin, - _=lambda text: text) - # clear out the result variable: - globals()["register_results"] = [] - # evaluate the contents: - try: - exec(contents, env) - except: - msg = _("Error in '%s' file: cannot load.") % gpr_file - callback(" " + msg + "\n") - continue - # There can be multiple addons per gpr file: - for results in globals()["register_results"]: - gramps_target_version = results.get("gramps_target_version", None) - if gramps_target_version: - vtup = version_str_to_tup(gramps_target_version, 2) - # Is it for the right version of gramps? - if vtup == const.VERSION_TUPLE[0:2]: - # If this version is not installed, or > installed, install it - good_gpr.add(gpr_file) - callback(" " + (_("'%s' is for this version of Gramps.") % gpr_file) + "\n") - else: - # If the plugin is for another version; inform and do nothing - callback(" " + (_("'%s' is NOT for this version of Gramps.") % gpr_file) + "\n") - callback(" " + (_("It is for version %d.%d" % vtup) + "\n")) - continue - else: - # another register function doesn't have gramps_target_version - if gpr_file in good_gpr: - s.remove(gpr_file) - callback(" " + (_("Error: missing gramps_target_version in '%s'...") % gpr_file) + "\n") - if len(good_gpr) > 0: - # Now, install the ok ones - file_obj.extractall(const.USER_PLUGINS) - callback((_("Installing '%s'...") % path) + "\n") - gpr_files = set([os.path.split(os.path.join(const.USER_PLUGINS, name))[0] - for name in good_gpr]) - for gpr_file in gpr_files: - # Convert gpr_file to unicode otherwise the callback will not - # work with non ASCII characters in filenames in Windows. - # But don't use converted filenames - # in the call to self.__pmgr.reg_plugins - # as that will break in reg_plugins. - u_gpr_file = unicode(gpr_file, sys.getfilesystemencoding()) - callback(" " + (_("Registered '%s'") % u_gpr_file) + "\n") - self.__pmgr.reg_plugins(gpr_file) - - file_obj.close() - def __select_file(self, obj): """ Select a file from the file system.