def __installPlugin(self, archiveFilename): """ Private slot to install the selected plugin. @param archiveFilename name of the plugin archive file (string or QString) @return flag indicating success (boolean), error message upon failure (QString) and flag indicating a restart of the IDE is required (boolean) """ installedPluginName = "" archive = unicode(archiveFilename) destination = \ unicode(self.destinationCombo.itemData(self.destinationCombo.currentIndex())\ .toString()) # check if archive is a local url url = urlparse.urlparse(archive) if url[0].lower() == 'file': archive = url[2] # check, if the archive exists if not os.path.exists(archive): return False, \ self.trUtf8("""<p>The archive file <b>%1</b> does not exist. """ """Aborting...</p>""").arg(archive), \ False # check, if the archive is a valid zip file if not zipfile.is_zipfile(archive): return False, \ self.trUtf8("""<p>The file <b>%1</b> is not a valid plugin """ """ZIP-archive. Aborting...</p>""").arg(archive), \ False # check, if the destination is writeable if not os.access(destination, os.W_OK): return False, \ self.trUtf8("""<p>The destination directory <b>%1</b> is not """ """writeable. Aborting...</p>""").arg(destination), \ False zip = zipfile.ZipFile(archive, "r") # check, if the archive contains a valid plugin pluginFound = False pluginFileName = "" for name in zip.namelist(): if self.__pluginManager.isValidPluginName(name): installedPluginName = name[:-3] pluginFound = True pluginFileName = name break if not pluginFound: return False, \ self.trUtf8("""<p>The file <b>%1</b> is not a valid plugin """ """ZIP-archive. Aborting...</p>""").arg(archive), \ False # parse the plugin module's plugin header pluginSource = zip.read(pluginFileName) packageName = "" internalPackages = [] needsRestart = False for line in pluginSource.splitlines(): if line.startswith("packageName"): tokens = line.split("=") if tokens[0].strip() == "packageName" and \ tokens[1].strip()[1:-1] != "__core__": if tokens[1].strip()[0] in ['"', "'"]: packageName = tokens[1].strip()[1:-1] else: if tokens[1].strip() == "None": packageName = "None" elif line.startswith("internalPackages"): tokens = line.split("=") token = tokens[1].strip()[1:-1] # it is a comma separated string internalPackages = [p.strip() for p in token.split(",")] elif line.startswith("needsRestart"): tokens = line.split("=") needsRestart = tokens[1].strip() == "True" elif line.startswith("# End-Of-Header"): break if not packageName: return False, \ self.trUtf8("""<p>The plugin module <b>%1</b> does not contain """ """a 'packageName' attribute. Aborting...</p>""")\ .arg(pluginFileName), \ False # check, if it is a plugin, that collides with others if not os.path.exists(os.path.join(destination, pluginFileName)) and \ packageName != "None" and \ os.path.exists(os.path.join(destination, packageName)): return False, \ self.trUtf8("""<p>The plugin package <b>%1</b> exists. """ """Aborting...</p>""")\ .arg(os.path.join(destination, packageName)), \ False if os.path.exists(os.path.join(destination, pluginFileName)) and \ packageName != "None" and \ not os.path.exists(os.path.join(destination, packageName)): return False, \ self.trUtf8("""<p>The plugin module <b>%1</b> exists. """ """Aborting...</p>""")\ .arg(os.path.join(destination, pluginFileName)), \ False activatePlugin = False if not self.__external: activatePlugin = \ not self.__pluginManager.isPluginLoaded(installedPluginName) or \ (self.__pluginManager.isPluginLoaded(installedPluginName) and \ self.__pluginManager.isPluginActive(installedPluginName)) # try to unload a plugin with the same name self.__pluginManager.unloadPlugin(installedPluginName, destination) # uninstall existing plugin first to get clean conditions self.__uninstallPackage(destination, pluginFileName, packageName) # clean sys.modules reload_ = self.__pluginManager.removePluginFromSysModules( installedPluginName, packageName, internalPackages) # now do the installation self.__installedDirs = [] self.__installedFiles = [] try: if packageName != "None": packageDirs = ["%s/" % packageName, "%s\\" % packageName] namelist = zip.namelist() namelist.sort() tot = len(namelist) prog = 0 self.progress.setMaximum(tot) QApplication.processEvents() for name in namelist: self.progress.setValue(prog) QApplication.processEvents() prog += 1 if name == pluginFileName or \ name.startswith("%s/" % packageName) or \ name.startswith("%s\\" % packageName): outname = name.replace("/", os.sep) outname = os.path.join(destination, outname) if outname.endswith("/") or outname.endswith("\\"): # it is a directory entry outname = outname[:-1] if not os.path.exists(outname): self.__makedirs(outname) else: # it is a file d = os.path.dirname(outname) if not os.path.exists(d): self.__makedirs(d) f = open(outname, "wb") f.write(zip.read(name)) f.close() self.__installedFiles.append(outname) self.progress.setValue(tot) # now compile user interface files compileUiFiles(os.path.join(destination, packageName), True) else: outname = os.path.join(destination, pluginFileName) f = open(outname, "wb") f.write(pluginSource) f.close() self.__installedFiles.append(outname) except os.error, why: self.__rollback() return False, \ self.trUtf8("Error installing plugin. Reason: %1").arg(str(why)), \ False
def __installPlugin(self, archiveFilename): """ Private slot to install the selected plugin. @param archiveFilename name of the plugin archive file (string) @return flag indicating success (boolean), error message upon failure (string) and flag indicating a restart of the IDE is required (boolean) """ installedPluginName = "" archive = archiveFilename destination = self.destinationCombo.itemData( self.destinationCombo.currentIndex()) # check if archive is a local url url = parse.urlparse(archive) if url[0].lower() == 'file': archive = url[2] # check, if the archive exists if not os.path.exists(archive): return False, \ self.tr( """<p>The archive file <b>{0}</b> does not exist. """ """Aborting...</p>""").format(archive), \ False # check, if the archive is a valid zip file if not zipfile.is_zipfile(archive): return False, \ self.tr( """<p>The file <b>{0}</b> is not a valid plugin """ """ZIP-archive. Aborting...</p>""").format(archive), \ False # check, if the destination is writeable if not os.access(destination, os.W_OK): return False, \ self.tr( """<p>The destination directory <b>{0}</b> is not """ """writeable. Aborting...</p>""").format(destination), \ False zip = zipfile.ZipFile(archive, "r") # check, if the archive contains a valid plugin pluginFound = False pluginFileName = "" for name in zip.namelist(): if self.__pluginManager.isValidPluginName(name): installedPluginName = name[:-3] pluginFound = True pluginFileName = name break if not pluginFound: return False, \ self.tr( """<p>The file <b>{0}</b> is not a valid plugin """ """ZIP-archive. Aborting...</p>""").format(archive), \ False # parse the plugin module's plugin header pluginSource = Utilities.decode(zip.read(pluginFileName))[0] packageName = "" internalPackages = [] needsRestart = False pyqtApi = 0 doCompile = True for line in pluginSource.splitlines(): if line.startswith("packageName"): tokens = line.split("=") if tokens[0].strip() == "packageName" and \ tokens[1].strip()[1:-1] != "__core__": if tokens[1].strip()[0] in ['"', "'"]: packageName = tokens[1].strip()[1:-1] else: if tokens[1].strip() == "None": packageName = "None" elif line.startswith("internalPackages"): tokens = line.split("=") token = tokens[1].strip()[1:-1] # it is a comma separated string internalPackages = [p.strip() for p in token.split(",")] elif line.startswith("needsRestart"): tokens = line.split("=") needsRestart = tokens[1].strip() == "True" elif line.startswith("pyqtApi"): tokens = line.split("=") try: pyqtApi = int(tokens[1].strip()) except ValueError: pass elif line.startswith("doNotCompile"): tokens = line.split("=") if tokens[1].strip() == "True": doCompile = False elif line.startswith("# End-Of-Header"): break if not packageName: return False, \ self.tr( """<p>The plugin module <b>{0}</b> does not contain """ """a 'packageName' attribute. Aborting...</p>""")\ .format(pluginFileName), \ False if pyqtApi < 2: return False, \ self.tr( """<p>The plugin module <b>{0}</b> does not conform""" """ with the PyQt v2 API. Aborting...</p>""")\ .format(pluginFileName), \ False # check, if it is a plugin, that collides with others if not os.path.exists(os.path.join(destination, pluginFileName)) and \ packageName != "None" and \ os.path.exists(os.path.join(destination, packageName)): return False, \ self.tr("""<p>The plugin package <b>{0}</b> exists. """ """Aborting...</p>""")\ .format(os.path.join(destination, packageName)), \ False if os.path.exists(os.path.join(destination, pluginFileName)) and \ packageName != "None" and \ not os.path.exists(os.path.join(destination, packageName)): return False, \ self.tr("""<p>The plugin module <b>{0}</b> exists. """ """Aborting...</p>""")\ .format(os.path.join(destination, pluginFileName)), \ False activatePlugin = False if not self.__external: activatePlugin = \ not self.__pluginManager.isPluginLoaded( installedPluginName) or \ (self.__pluginManager.isPluginLoaded(installedPluginName) and self.__pluginManager.isPluginActive(installedPluginName)) # try to unload a plugin with the same name self.__pluginManager.unloadPlugin(installedPluginName) # uninstall existing plugin first to get clean conditions self.__uninstallPackage(destination, pluginFileName, packageName) # clean sys.modules reload_ = self.__pluginManager.removePluginFromSysModules( installedPluginName, packageName, internalPackages) # now do the installation self.__installedDirs = [] self.__installedFiles = [] try: if packageName != "None": namelist = sorted(zip.namelist()) tot = len(namelist) prog = 0 self.progress.setMaximum(tot) QApplication.processEvents() for name in namelist: self.progress.setValue(prog) QApplication.processEvents() prog += 1 if name == pluginFileName or \ name.startswith("{0}/".format(packageName)) or \ name.startswith("{0}\\".format(packageName)): outname = name.replace("/", os.sep) outname = os.path.join(destination, outname) if outname.endswith("/") or outname.endswith("\\"): # it is a directory entry outname = outname[:-1] if not os.path.exists(outname): self.__makedirs(outname) else: # it is a file d = os.path.dirname(outname) if not os.path.exists(d): self.__makedirs(d) f = open(outname, "wb") f.write(zip.read(name)) f.close() self.__installedFiles.append(outname) self.progress.setValue(tot) # now compile user interface files compileUiFiles(os.path.join(destination, packageName), True) else: outname = os.path.join(destination, pluginFileName) f = open(outname, "w", encoding="utf-8") f.write(pluginSource) f.close() self.__installedFiles.append(outname) except os.error as why: self.__rollback() return False, \ self.tr( "Error installing plugin. Reason: {0}").format(str(why)), \ False except IOError as why: self.__rollback() return False, \ self.tr( "Error installing plugin. Reason: {0}").format(str(why)), \ False except OSError as why: self.__rollback() return False, \ self.tr( "Error installing plugin. Reason: {0}").format(str(why)), \ False except Exception: sys.stderr.write("Unspecific exception installing plugin.\n") self.__rollback() return False, \ self.tr("Unspecific exception installing plugin."), \ False # now compile the plugins if doCompile: dir = os.path.join(destination, packageName) files = os.path.join(destination, pluginFileName) if sys.version_info[0] == 2: dir = dir.encode(sys.getfilesystemencoding()) files = files.encode(sys.getfilesystemencoding()) os.path.join_unicode = False compileall.compile_dir(dir, quiet=True) compileall.compile_file(files, quiet=True) os.path.join_unicode = True if not self.__external: # now load and activate the plugin self.__pluginManager.loadPlugin(installedPluginName, destination, reload_) if activatePlugin: self.__pluginManager.activatePlugin(installedPluginName) return True, "", needsRestart