def downloadIndexTask(self, task): if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) self.redownloadingNews = False return task.done self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.newsIndexEntries = list(self.newsFiles) self.notify.info('Server lists %s news files' % len(self.newsFiles)) self.notify.debug('self.newsIndexEntries=%s' % self.newsIndexEntries) self.readNewsCache() for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info('Removing %s' % junk) junk.unlink() self.nextNewsFile = 0 return self.downloadNextFile(task)
def downloadCurrentFileTask(self, task): if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: self.notify.info('already cached: %s' % self.filename) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() return self.downloadNextFile(task) self.notify.info('downloaded %s' % self.filename) size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() return self.downloadNextFile(task)
def downloadCurrentFileTask(self, task): if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: self.notify.info('already cached: %s' % self.filename) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning('Unable to download %s' % self.url) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() return self.downloadNextFile(task) self.notify.info('downloaded %s' % self.filename) size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() return self.downloadNextFile(task)
def downloadIndexTask(self, task): if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning("Unable to download %s" % self.url) self.redownloadingNews = False return task.done self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.newsIndexEntries = list(self.newsFiles) self.notify.info("Server lists %s news files" % len(self.newsFiles)) self.notify.debug("self.newsIndexEntries=%s" % self.newsIndexEntries) self.readNewsCache() for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info("Removing %s" % junk) junk.unlink() self.nextNewsFile = 0 return self.downloadNextFile(task)
def __uncompressArchive(self, step): """ Turns the compressed archive into the uncompressed archive. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed return self.updated = True sourcePathname = Filename(self.getPackageDir(), self.compressedArchive.filename) targetPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) targetPathname.unlink() self.notify.info("Uncompressing %s to %s" % (sourcePathname, targetPathname)) decompressor = Decompressor() decompressor.initiate(sourcePathname, targetPathname) totalBytes = self.uncompressedArchive.size result = decompressor.run() while result == EUOk: step.bytesDone = int(totalBytes * decompressor.getProgress()) self.__updateStepProgress(step) result = decompressor.run() if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning( "Task Manager destroyed, aborting decompresss %s" % (sourcePathname)) yield self.stepFailed return yield self.stepContinue if result != EUSuccess: yield self.stepFailed return step.bytesDone = totalBytes self.__updateStepProgress(step) if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify=self.notify): self.notify.warning("after uncompressing, %s still incorrect" % (self.uncompressedArchive.filename)) yield self.stepFailed return # Now that we've verified the archive, make it read-only. os.chmod(targetPathname.toOsSpecific(), 0444) # Now we can safely remove the compressed archive. sourcePathname.unlink() yield self.stepComplete return
def __checkArchiveStatus(self): """ Returns true if the archive and all extractable files are already correct on disk, false otherwise. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # Assume that everything is just fine. return True # Get a list of all of the files in the directory, so we can # remove files that don't belong. contents = self.__scanDirectoryRecursively(self.getPackageDir()) self.__removeFileFromList(contents, self.descFileBasename) self.__removeFileFromList(contents, self.compressedArchive.filename) self.__removeFileFromList(contents, self.UsageBasename) if not self.asMirror: self.__removeFileFromList(contents, self.uncompressedArchive.filename) for file in self.extracts: self.__removeFileFromList(contents, file.filename) # Now, any files that are still in the contents list don't # belong. It's important to remove these files before we # start verifying the files that we expect to find here, in # case there is a problem with ambiguous filenames or # something (e.g. case insensitivity). for filename in contents: self.notify.info("Removing %s" % (filename)) pathname = Filename(self.getPackageDir(), filename) pathname.unlink() self.updated = True if self.asMirror: return self.compressedArchive.quickVerify(self.getPackageDir(), notify = self.notify) allExtractsOk = True if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify = self.notify): self.notify.debug("File is incorrect: %s" % (self.uncompressedArchive.filename)) allExtractsOk = False if allExtractsOk: # OK, the uncompressed archive is good; that means there # shouldn't be a compressed archive file here. pathname = Filename(self.getPackageDir(), self.compressedArchive.filename) pathname.unlink() for file in self.extracts: if not file.quickVerify(self.getPackageDir(), notify = self.notify): self.notify.debug("File is incorrect: %s" % (file.filename)) allExtractsOk = False break if allExtractsOk: self.notify.debug("All %s extracts of %s seem good." % ( len(self.extracts), self.packageName)) return allExtractsOk
def buildDmg(startDir): fstartDir = Filename.fromOsSpecific(startDir) rootFilename = Filename(fstartDir, 'bundle') output = Filename(fstartDir, 'nppanda3d.dmg') output.unlink() cmd = 'hdiutil create -fs HFS+ -srcfolder "%(dir)s" -volname "%(volname)s" "%(output)s"' % { 'dir': rootFilename.toOsSpecific(), 'volname': 'nppanda3d', 'output': output.toOsSpecific(), } os.system(cmd)
def buildDmg(startDir): fstartDir = Filename.fromOsSpecific(startDir) rootFilename = Filename(fstartDir, 'bundle') output = Filename(fstartDir, 'nppanda3d.dmg') output.unlink() cmd = 'hdiutil create -fs HFS+ -srcfolder "%(dir)s" -volname "%(volname)s" "%(output)s"' % { 'dir' : rootFilename.toOsSpecific(), 'volname' : 'nppanda3d', 'output' : output.toOsSpecific(), } os.system(cmd)
def __uncompressArchive(self, step): """ Turns the compressed archive into the uncompressed archive. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed return self.updated = True sourcePathname = Filename(self.getPackageDir(), self.compressedArchive.filename) targetPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) targetPathname.unlink() self.notify.info("Uncompressing %s to %s" % (sourcePathname, targetPathname)) decompressor = Decompressor() decompressor.initiate(sourcePathname, targetPathname) totalBytes = self.uncompressedArchive.size result = decompressor.run() while result == EUOk: step.bytesDone = int(totalBytes * decompressor.getProgress()) self.__updateStepProgress(step) result = decompressor.run() if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting decompresss %s" % (sourcePathname)) yield self.stepFailed return yield self.stepContinue if result != EUSuccess: yield self.stepFailed return step.bytesDone = totalBytes self.__updateStepProgress(step) if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify=self.notify): self.notify.warning("after uncompressing, %s still incorrect" % (self.uncompressedArchive.filename)) yield self.stepFailed return # Now that we've verified the archive, make it read-only. os.chmod(targetPathname.toOsSpecific(), 0444) # Now we can safely remove the compressed archive. sourcePathname.unlink() yield self.stepComplete return
def __applyPatch(self, step, patchfile): """ Applies the indicated patching in-place to the current uncompressed archive. The patchfile is removed after the operation. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ self.updated = True origPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) patchPathname = Filename(self.getPackageDir(), patchfile.file.filename) result = Filename.temporary('', 'patch_') self.notify.info("Patching %s with %s" % (origPathname, patchPathname)) p = PandaModules.Patchfile() # The C++ class ret = p.initiate(patchPathname, origPathname, result) if ret == EUSuccess: ret = p.run() while ret == EUOk: step.bytesDone = step.bytesNeeded * p.getProgress() self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning( "Task Manager destroyed, aborting patch %s" % (origPathname)) yield self.stepFailed return yield self.stepContinue ret = p.run() del p patchPathname.unlink() if ret < 0: self.notify.warning("Patching of %s failed." % (origPathname)) result.unlink() yield self.stepFailed return if not result.renameTo(origPathname): self.notify.warning("Couldn't rename %s to %s" % (result, origPathname)) yield self.stepFailed return yield self.stepComplete return
def __applyPatch(self, step, patchfile): """ Applies the indicated patching in-place to the current uncompressed archive. The patchfile is removed after the operation. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ self.updated = True origPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) patchPathname = Filename(self.getPackageDir(), patchfile.file.filename) result = Filename.temporary("", "patch_") self.notify.info("Patching %s with %s" % (origPathname, patchPathname)) p = PandaModules.Patchfile() # The C++ class ret = p.initiate(patchPathname, origPathname, result) if ret == EUSuccess: ret = p.run() while ret == EUOk: step.bytesDone = step.bytesNeeded * p.getProgress() self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting patch %s" % (origPathname)) yield self.stepFailed return yield self.stepContinue ret = p.run() del p patchPathname.unlink() if ret < 0: self.notify.warning("Patching of %s failed." % (origPathname)) result.unlink() yield self.stepFailed return if not result.renameTo(origPathname): self.notify.warning("Couldn't rename %s to %s" % (result, origPathname)) yield self.stepFailed return yield self.stepComplete return
def downloadCurrentFileTask(self, task): """ Continues downloading the URL in self.url and self.filename. """ if self.ch.run(): return task.cont if self.ch.getStatusCode() == 304: # This file is still cached from before. We don't need to # download it again. Move on to the next file. self.notify.info("already cached: %s" % (self.filename)) return self.downloadNextFile(task) localFilename = Filename(self.newsDir, self.filename) if not self.ch.isValid(): self.notify.warning("Unable to download %s" % (self.url)) localFilename.unlink() if self.filename in self.newsCache: del self.newsCache[self.filename] self.saveNewsCache() # Might as well see if we can get the next file. return self.downloadNextFile(task) # Successfully downloaded. self.notify.info("downloaded %s" % (self.filename)) # The HTTP "Entity Tag" appears to be useless with our CDN: # different CDN servers will serve up different etag values # for the same file. We rely on file size and date instead. size = self.ch.getFileSize() doc = self.ch.getDocumentSpec() date = '' if doc.hasDate(): date = doc.getDate().getString() self.newsCache[self.filename] = (size, date) self.saveNewsCache() # Continue downloading files. return self.downloadNextFile(task)
def downloadIndexTask(self, task): """ Get the initial index file from the HTTP server. """ if self.ch.run(): return task.cont if not self.ch.isValid(): self.notify.warning("Unable to download %s" % (self.url)) self.redownloadingNews = False return task.done # OK, now we've got the list of files hosted by the server. # Parse the list. self.newsFiles = [] filename = self.rf.readline() while filename: filename = filename.strip() if filename: self.newsFiles.append(filename) filename = self.rf.readline() del self.rf self.newsFiles.sort() self.notify.info("Server lists %s news files" % (len(self.newsFiles))) # Now see if we already have copies of these files we # downloaded previously. self.readNewsCache() # Clean up any unexpected files in this directory--they might # be old news files, or partial failed downloads from before. for basename in os.listdir(self.newsDir.toOsSpecific()): if basename != self.CacheIndexFilename and basename not in self.newsCache: junk = Filename(self.newsDir, basename) self.notify.info("Removing %s" % (junk)) junk.unlink() # And start downloading the files. self.nextNewsFile = 0 return self.downloadNextFile(task)
def __unpackArchive(self, step): """ Unpacks any files in the archive that want to be unpacked to disk. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if not self.extracts: # Nothing to extract. self.hasPackage = True yield self.stepComplete return if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed return self.updated = True mfPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) self.notify.info("Unpacking %s" % (mfPathname)) mf = Multifile() if not mf.openRead(mfPathname): self.notify.warning("Couldn't open %s" % (mfPathname)) yield self.stepFailed return allExtractsOk = True step.bytesDone = 0 for file in self.extracts: i = mf.findSubfile(file.filename) if i == -1: self.notify.warning("Not in Multifile: %s" % (file.filename)) allExtractsOk = False continue targetPathname = Filename(self.getPackageDir(), file.filename) targetPathname.setBinary() targetPathname.unlink() if not mf.extractSubfile(i, targetPathname): self.notify.warning("Couldn't extract: %s" % (file.filename)) allExtractsOk = False continue if not file.quickVerify(self.getPackageDir(), notify=self.notify): self.notify.warning("After extracting, still incorrect: %s" % (file.filename)) allExtractsOk = False continue # Make sure it's executable, and not writable. os.chmod(targetPathname.toOsSpecific(), 0555) step.bytesDone += file.size self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning( "Task Manager destroyed, aborting unpacking %s" % (mfPathname)) yield self.stepFailed return yield self.stepContinue if not allExtractsOk: yield self.stepFailed return self.hasPackage = True yield self.stepComplete return
def buildDEB(self, output, platform): """ Builds a .deb archive and stores it in the path indicated by the 'output' argument. It will be built for the architecture specified by the 'arch' argument. If 'output' is a directory, the deb file will be stored in it. """ arch = platform.rsplit("_", 1)[-1] output = Filename(output) if output.isDirectory(): output = Filename( output, "%s_%s_%s.deb" % (self.shortname.lower(), self.version, arch)) Installer.notify.info("Creating %s..." % output) modtime = int(time.time()) # Create a temporary directory and write the launcher and dependencies to it. tempdir, totsize = self.__buildTempLinux(platform) # Create a control file in memory. controlfile = StringIO() print >> controlfile, "Package: %s" % self.shortname.lower() print >> controlfile, "Version: %s" % self.version print >> controlfile, "Maintainer: %s <%s>" % (self.authorname, self.authoremail) print >> controlfile, "Section: games" print >> controlfile, "Priority: optional" print >> controlfile, "Architecture: %s" % arch print >> controlfile, "Installed-Size: %d" % -(-totsize / 1024) print >> controlfile, "Description: %s" % self.fullname print >> controlfile, "Depends: libc6, libgcc1, libstdc++6, libx11-6" controlinfo = TarInfoRoot("control") controlinfo.mtime = modtime controlinfo.size = controlfile.tell() controlfile.seek(0) # Open the deb file and write to it. It's actually # just an AR file, which is very easy to make. if output.exists(): output.unlink() debfile = open(output.toOsSpecific(), "wb") debfile.write("!<arch>\x0A") debfile.write( "debian-binary %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 4)) debfile.write("2.0\x0A") # Write the control.tar.gz to the archive. debfile.write( "control.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0)) ctaroffs = debfile.tell() ctarfile = tarfile.open("control.tar.gz", "w:gz", debfile, tarinfo=TarInfoRoot) ctarfile.addfile(controlinfo, controlfile) ctarfile.close() ctarsize = debfile.tell() - ctaroffs if (ctarsize & 1): debfile.write("\x0A") # Write the data.tar.gz to the archive. debfile.write( "data.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0)) dtaroffs = debfile.tell() dtarfile = tarfile.open("data.tar.gz", "w:gz", debfile, tarinfo=TarInfoRoot) dtarfile.add(Filename(tempdir, "usr").toOsSpecific(), "/usr") dtarfile.close() dtarsize = debfile.tell() - dtaroffs if (dtarsize & 1): debfile.write("\x0A") # Write the correct sizes of the archives. debfile.seek(ctaroffs - 12) debfile.write("%-10ld" % ctarsize) debfile.seek(dtaroffs - 12) debfile.write("%-10ld" % dtarsize) debfile.close() return output
def buildNSIS(self, output, platform): # Check if we have makensis first makensis = None if (sys.platform.startswith("win")): syspath = os.defpath.split(";") + os.environ["PATH"].split(";") for p in set(syspath): p1 = os.path.join(p, "makensis.exe") p2 = os.path.join(os.path.dirname(p), "nsis", "makensis.exe") if os.path.isfile(p1): makensis = p1 break elif os.path.isfile(p2): makensis = p2 break if not makensis: import pandac makensis = os.path.dirname(os.path.dirname(pandac.__file__)) makensis = os.path.join(makensis, "nsis", "makensis.exe") if not os.path.isfile(makensis): makensis = None else: for p in os.defpath.split(":") + os.environ["PATH"].split(":"): if os.path.isfile(os.path.join(p, "makensis")): makensis = os.path.join(p, "makensis") if makensis == None: Installer.notify.warning( "Makensis utility not found, no Windows installer will be built!" ) return None output = Filename(output) if output.isDirectory(): output = Filename(output, "%s %s.exe" % (self.fullname, self.version)) Installer.notify.info("Creating %s..." % output) output.makeAbsolute() extrafiles = self.standalone.getExtraFiles(platform) exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe") exefile.unlink() if self.includeRequires: extraTokens = {"host_dir": "."} else: extraTokens = {} self.standalone.build(exefile, platform, extraTokens) # Temporary directory to store the hostdir in hostDir = Filename(self.tempDir, platform + "/") if not hostDir.exists(): hostDir.makeDir() self.installPackagesInto(hostDir, platform) nsifile = Filename(Filename.getTempDirectory(), self.shortname + ".nsi") nsifile.unlink() nsi = open(nsifile.toOsSpecific(), "w") # Some global info nsi.write('Name "%s"\n' % self.fullname) nsi.write('OutFile "%s"\n' % output.toOsSpecific()) nsi.write('InstallDir "$PROGRAMFILES\\%s"\n' % self.fullname) nsi.write('SetCompress auto\n') nsi.write('SetCompressor lzma\n') nsi.write('ShowInstDetails nevershow\n') nsi.write('ShowUninstDetails nevershow\n') nsi.write('InstType "Typical"\n') # Tell Vista that we require admin rights nsi.write('RequestExecutionLevel admin\n') nsi.write('\n') nsi.write('Function launch\n') nsi.write(' ExecShell "open" "$INSTDIR\\%s.exe"\n' % self.shortname) nsi.write('FunctionEnd\n') nsi.write('\n') nsi.write('!include "MUI2.nsh"\n') nsi.write('!define MUI_ABORTWARNING\n') nsi.write('!define MUI_FINISHPAGE_RUN\n') nsi.write('!define MUI_FINISHPAGE_RUN_FUNCTION launch\n') nsi.write('!define MUI_FINISHPAGE_RUN_TEXT "Run %s"\n' % self.fullname) nsi.write('\n') nsi.write('Var StartMenuFolder\n') nsi.write('!insertmacro MUI_PAGE_WELCOME\n') if not self.licensefile.empty(): abs = Filename(self.licensefile) abs.makeAbsolute() nsi.write('!insertmacro MUI_PAGE_LICENSE "%s"\n' % abs.toOsSpecific()) nsi.write('!insertmacro MUI_PAGE_DIRECTORY\n') nsi.write( '!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder\n') nsi.write('!insertmacro MUI_PAGE_INSTFILES\n') nsi.write('!insertmacro MUI_PAGE_FINISH\n') nsi.write('!insertmacro MUI_UNPAGE_WELCOME\n') nsi.write('!insertmacro MUI_UNPAGE_CONFIRM\n') nsi.write('!insertmacro MUI_UNPAGE_INSTFILES\n') nsi.write('!insertmacro MUI_UNPAGE_FINISH\n') nsi.write('!insertmacro MUI_LANGUAGE "English"\n') # This section defines the installer. nsi.write('Section "" SecCore\n') nsi.write(' SetOutPath "$INSTDIR"\n') nsi.write(' File "%s"\n' % exefile.toOsSpecific()) for f in extrafiles: nsi.write(' File "%s"\n' % f.toOsSpecific()) curdir = "" for root, dirs, files in self.os_walk(hostDir.toOsSpecific()): for name in files: file = Filename.fromOsSpecific(os.path.join(root, name)) file.makeAbsolute() file.makeRelativeTo(hostDir) outdir = file.getDirname().replace('/', '\\') if curdir != outdir: nsi.write(' SetOutPath "$INSTDIR\\%s"\n' % outdir) curdir = outdir nsi.write(' File "%s"\n' % os.path.join(root, name)) nsi.write(' WriteUninstaller "$INSTDIR\\Uninstall.exe"\n') nsi.write(' ; Start menu items\n') nsi.write(' !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n') nsi.write(' CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"\n') nsi.write( ' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk" "$INSTDIR\\%s.exe"\n' % (self.fullname, self.shortname)) nsi.write( ' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"\n' ) nsi.write(' !insertmacro MUI_STARTMENU_WRITE_END\n') nsi.write('SectionEnd\n') # This section defines the uninstaller. nsi.write('Section Uninstall\n') nsi.write(' Delete "$INSTDIR\\%s.exe"\n' % self.shortname) for f in extrafiles: nsi.write(' Delete "%s"\n' % f.getBasename()) nsi.write(' Delete "$INSTDIR\\Uninstall.exe"\n') nsi.write(' RMDir /r "$INSTDIR"\n') nsi.write(' ; Start menu items\n') nsi.write( ' !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder\n' ) nsi.write(' Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk"\n') nsi.write(' RMDir "$SMPROGRAMS\\$StartMenuFolder"\n') nsi.write('SectionEnd') nsi.close() cmd = [makensis] for o in ["V2"]: if sys.platform.startswith("win"): cmd.append("/" + o) else: cmd.append("-" + o) cmd.append(nsifile.toOsSpecific()) print cmd try: retcode = subprocess.call(cmd, shell=False) if retcode != 0: self.notify.warning("Failure invoking NSIS command.") except OSError: self.notify.warning("Unable to invoke NSIS command.") nsifile.unlink() return output
def buildDEB(self, output, platform): """ Builds a .deb archive and stores it in the path indicated by the 'output' argument. It will be built for the architecture specified by the 'arch' argument. If 'output' is a directory, the deb file will be stored in it. """ arch = platform.rsplit("_", 1)[-1] output = Filename(output) if output.isDirectory(): output = Filename(output, "%s_%s_%s.deb" % (self.shortname.lower(), self.version, arch)) Installer.notify.info("Creating %s..." % output) modtime = int(time.time()) # Create a temporary directory and write the launcher and dependencies to it. tempdir, totsize = self.__buildTempLinux(platform) # Create a control file in memory. controlfile = StringIO() print >> controlfile, "Package: %s" % self.shortname.lower() print >> controlfile, "Version: %s" % self.version print >> controlfile, "Maintainer: %s <%s>" % (self.authorname, self.authoremail) print >> controlfile, "Section: games" print >> controlfile, "Priority: optional" print >> controlfile, "Architecture: %s" % arch print >> controlfile, "Installed-Size: %d" % -(-totsize / 1024) print >> controlfile, "Description: %s" % self.fullname print >> controlfile, "Depends: libc6, libgcc1, libstdc++6, libx11-6" controlinfo = TarInfoRoot("control") controlinfo.mtime = modtime controlinfo.size = controlfile.tell() controlfile.seek(0) # Open the deb file and write to it. It's actually # just an AR file, which is very easy to make. if output.exists(): output.unlink() debfile = open(output.toOsSpecific(), "wb") debfile.write("!<arch>\x0A") debfile.write("debian-binary %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 4)) debfile.write("2.0\x0A") # Write the control.tar.gz to the archive. debfile.write("control.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0)) ctaroffs = debfile.tell() ctarfile = tarfile.open("control.tar.gz", "w:gz", debfile, tarinfo=TarInfoRoot) ctarfile.addfile(controlinfo, controlfile) ctarfile.close() ctarsize = debfile.tell() - ctaroffs if ctarsize & 1: debfile.write("\x0A") # Write the data.tar.gz to the archive. debfile.write("data.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0)) dtaroffs = debfile.tell() dtarfile = tarfile.open("data.tar.gz", "w:gz", debfile, tarinfo=TarInfoRoot) dtarfile.add(Filename(tempdir, "usr").toOsSpecific(), "/usr") dtarfile.close() dtarsize = debfile.tell() - dtaroffs if dtarsize & 1: debfile.write("\x0A") # Write the correct sizes of the archives. debfile.seek(ctaroffs - 12) debfile.write("%-10ld" % ctarsize) debfile.seek(dtaroffs - 12) debfile.write("%-10ld" % dtarsize) debfile.close() return output
def buildNSIS(self, output, platform): # Check if we have makensis first makensis = None if sys.platform.startswith("win"): syspath = os.defpath.split(";") + os.environ["PATH"].split(";") for p in set(syspath): p1 = os.path.join(p, "makensis.exe") p2 = os.path.join(os.path.dirname(p), "nsis", "makensis.exe") if os.path.isfile(p1): makensis = p1 break elif os.path.isfile(p2): makensis = p2 break if not makensis: import pandac makensis = os.path.dirname(os.path.dirname(pandac.__file__)) makensis = os.path.join(makensis, "nsis", "makensis.exe") if not os.path.isfile(makensis): makensis = None else: for p in os.defpath.split(":") + os.environ["PATH"].split(":"): if os.path.isfile(os.path.join(p, "makensis")): makensis = os.path.join(p, "makensis") if makensis == None: Installer.notify.warning("Makensis utility not found, no Windows installer will be built!") return None output = Filename(output) if output.isDirectory(): output = Filename(output, "%s %s.exe" % (self.fullname, self.version)) Installer.notify.info("Creating %s..." % output) output.makeAbsolute() extrafiles = self.standalone.getExtraFiles(platform) exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe") exefile.unlink() if self.includeRequires: extraTokens = {"host_dir": "."} else: extraTokens = {} self.standalone.build(exefile, platform, extraTokens) # Temporary directory to store the hostdir in hostDir = Filename(self.tempDir, platform + "/") if not hostDir.exists(): hostDir.makeDir() self.installPackagesInto(hostDir, platform) nsifile = Filename(Filename.getTempDirectory(), self.shortname + ".nsi") nsifile.unlink() nsi = open(nsifile.toOsSpecific(), "w") # Some global info nsi.write('Name "%s"\n' % self.fullname) nsi.write('OutFile "%s"\n' % output.toOsSpecific()) nsi.write('InstallDir "$PROGRAMFILES\\%s"\n' % self.fullname) nsi.write("SetCompress auto\n") nsi.write("SetCompressor lzma\n") nsi.write("ShowInstDetails nevershow\n") nsi.write("ShowUninstDetails nevershow\n") nsi.write('InstType "Typical"\n') # Tell Vista that we require admin rights nsi.write("RequestExecutionLevel admin\n") nsi.write("\n") nsi.write("Function launch\n") nsi.write(' ExecShell "open" "$INSTDIR\\%s.exe"\n' % self.shortname) nsi.write("FunctionEnd\n") nsi.write("\n") nsi.write('!include "MUI2.nsh"\n') nsi.write("!define MUI_ABORTWARNING\n") nsi.write("!define MUI_FINISHPAGE_RUN\n") nsi.write("!define MUI_FINISHPAGE_RUN_FUNCTION launch\n") nsi.write('!define MUI_FINISHPAGE_RUN_TEXT "Run %s"\n' % self.fullname) nsi.write("\n") nsi.write("Var StartMenuFolder\n") nsi.write("!insertmacro MUI_PAGE_WELCOME\n") if not self.licensefile.empty(): abs = Filename(self.licensefile) abs.makeAbsolute() nsi.write('!insertmacro MUI_PAGE_LICENSE "%s"\n' % abs.toOsSpecific()) nsi.write("!insertmacro MUI_PAGE_DIRECTORY\n") nsi.write("!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder\n") nsi.write("!insertmacro MUI_PAGE_INSTFILES\n") nsi.write("!insertmacro MUI_PAGE_FINISH\n") nsi.write("!insertmacro MUI_UNPAGE_WELCOME\n") nsi.write("!insertmacro MUI_UNPAGE_CONFIRM\n") nsi.write("!insertmacro MUI_UNPAGE_INSTFILES\n") nsi.write("!insertmacro MUI_UNPAGE_FINISH\n") nsi.write('!insertmacro MUI_LANGUAGE "English"\n') # This section defines the installer. nsi.write('Section "" SecCore\n') nsi.write(' SetOutPath "$INSTDIR"\n') nsi.write(' File "%s"\n' % exefile.toOsSpecific()) for f in extrafiles: nsi.write(' File "%s"\n' % f.toOsSpecific()) curdir = "" for root, dirs, files in self.os_walk(hostDir.toOsSpecific()): for name in files: file = Filename.fromOsSpecific(os.path.join(root, name)) file.makeAbsolute() file.makeRelativeTo(hostDir) outdir = file.getDirname().replace("/", "\\") if curdir != outdir: nsi.write(' SetOutPath "$INSTDIR\\%s"\n' % outdir) curdir = outdir nsi.write(' File "%s"\n' % os.path.join(root, name)) nsi.write(' WriteUninstaller "$INSTDIR\\Uninstall.exe"\n') nsi.write(" ; Start menu items\n") nsi.write(" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n") nsi.write(' CreateDirectory "$SMPROGRAMS\\$StartMenuFolder"\n') nsi.write( ' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\%s.lnk" "$INSTDIR\\%s.exe"\n' % (self.fullname, self.shortname) ) nsi.write(' CreateShortCut "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk" "$INSTDIR\\Uninstall.exe"\n') nsi.write(" !insertmacro MUI_STARTMENU_WRITE_END\n") nsi.write("SectionEnd\n") # This section defines the uninstaller. nsi.write("Section Uninstall\n") nsi.write(' Delete "$INSTDIR\\%s.exe"\n' % self.shortname) for f in extrafiles: nsi.write(' Delete "%s"\n' % f.getBasename()) nsi.write(' Delete "$INSTDIR\\Uninstall.exe"\n') nsi.write(' RMDir /r "$INSTDIR"\n') nsi.write(" ; Start menu items\n") nsi.write(" !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder\n") nsi.write(' Delete "$SMPROGRAMS\\$StartMenuFolder\\Uninstall.lnk"\n') nsi.write(' RMDir "$SMPROGRAMS\\$StartMenuFolder"\n') nsi.write("SectionEnd") nsi.close() cmd = [makensis] for o in ["V2"]: if sys.platform.startswith("win"): cmd.append("/" + o) else: cmd.append("-" + o) cmd.append(nsifile.toOsSpecific()) print cmd try: retcode = subprocess.call(cmd, shell=False) if retcode != 0: self.notify.warning("Failure invoking NSIS command.") except OSError: self.notify.warning("Unable to invoke NSIS command.") nsifile.unlink() return output
def __downloadFile(self, step, fileSpec, urlbase = None, filename = None, allowPartial = False): """ Downloads the indicated file from the host into packageDir. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to download anything. yield self.stepFailed; return self.updated = True if not urlbase: urlbase = self.descFileDirname + '/' + fileSpec.filename # Build up a list of URL's to try downloading from. Unlike # the C++ implementation in P3DPackage.cxx, here we build the # URL's in forward order. tryUrls = [] if self.host.appRunner and self.host.appRunner.superMirrorUrl: # We start with the "super mirror", if it's defined. url = self.host.appRunner.superMirrorUrl + urlbase tryUrls.append((url, False)) if self.host.mirrors: # Choose two mirrors at random. mirrors = self.host.mirrors[:] for i in range(2): mirror = random.choice(mirrors) mirrors.remove(mirror) url = mirror + urlbase tryUrls.append((url, False)) if not mirrors: break # After trying two mirrors and failing (or if there are no # mirrors), go get it from the original host. url = self.host.downloadUrlPrefix + urlbase tryUrls.append((url, False)) # And finally, if the original host also fails, try again with # a cache-buster. tryUrls.append((url, True)) for url, cacheBust in tryUrls: request = DocumentSpec(url) if cacheBust: # On the last attempt to download a particular file, # we bust through the cache: append a query string to # do this. url += '?' + str(int(time.time())) request = DocumentSpec(url) request.setCacheControl(DocumentSpec.CCNoCache) self.notify.info("%s downloading %s" % (self.packageName, url)) if not filename: filename = fileSpec.filename targetPathname = Filename(self.getPackageDir(), filename) targetPathname.setBinary() channel = self.http.makeChannel(False) # If there's a previous partial download, attempt to resume it. bytesStarted = 0 if allowPartial and not cacheBust and targetPathname.exists(): bytesStarted = targetPathname.getFileSize() if bytesStarted < 1024*1024: # Not enough bytes downloaded to be worth the risk of # a partial download. bytesStarted = 0 elif bytesStarted >= fileSpec.size: # Couldn't possibly be our file. bytesStarted = 0 if bytesStarted: self.notify.info("Resuming %s after %s bytes already downloaded" % (url, bytesStarted)) # Make sure the file is writable. os.chmod(targetPathname.toOsSpecific(), 0644) channel.beginGetSubdocument(request, bytesStarted, 0) else: # No partial download possible; get the whole file. targetPathname.makeDir() targetPathname.unlink() channel.beginGetDocument(request) channel.downloadToFile(targetPathname) while channel.run(): if step: step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered() if step.bytesDone > step.bytesNeeded: # Oops, too much data. Might as well abort; # it's the wrong file. self.notify.warning("Got more data than expected for download %s" % (url)) break self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting %s" % (url)) yield self.stepFailed; return yield self.stepContinue if step: step.bytesDone = channel.getBytesDownloaded() + channel.getFirstByteDelivered() self.__updateStepProgress(step) if not channel.isValid(): self.notify.warning("Failed to download %s" % (url)) elif not fileSpec.fullVerify(self.getPackageDir(), pathname = targetPathname, notify = self.notify): self.notify.warning("After downloading, %s incorrect" % (Filename(fileSpec.filename).getBasename())) # This attempt failed. Maybe the original contents.xml # file is stale. Try re-downloading it now, just to be # sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload; return else: # Success! yield self.stepComplete; return # Maybe the mirror is bad. Go back and try the next # mirror. # All attempts failed. Maybe the original contents.xml file # is stale. Try re-downloading it now, just to be sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload; return # All mirrors failed; the server (or the internet connection) # must be just fubar. yield self.stepFailed; return
def __downloadFile(self, step, fileSpec, urlbase=None, filename=None, allowPartial=False): """ Downloads the indicated file from the host into packageDir. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to download anything. yield self.stepFailed return self.updated = True if not urlbase: urlbase = self.descFileDirname + '/' + fileSpec.filename # Build up a list of URL's to try downloading from. Unlike # the C++ implementation in P3DPackage.cxx, here we build the # URL's in forward order. tryUrls = [] if self.host.appRunner and self.host.appRunner.superMirrorUrl: # We start with the "super mirror", if it's defined. url = self.host.appRunner.superMirrorUrl + urlbase tryUrls.append((url, False)) if self.host.mirrors: # Choose two mirrors at random. mirrors = self.host.mirrors[:] for i in range(2): mirror = random.choice(mirrors) mirrors.remove(mirror) url = mirror + urlbase tryUrls.append((url, False)) if not mirrors: break # After trying two mirrors and failing (or if there are no # mirrors), go get it from the original host. url = self.host.downloadUrlPrefix + urlbase tryUrls.append((url, False)) # And finally, if the original host also fails, try again with # a cache-buster. tryUrls.append((url, True)) for url, cacheBust in tryUrls: request = DocumentSpec(url) if cacheBust: # On the last attempt to download a particular file, # we bust through the cache: append a query string to # do this. url += '?' + str(int(time.time())) request = DocumentSpec(url) request.setCacheControl(DocumentSpec.CCNoCache) self.notify.info("%s downloading %s" % (self.packageName, url)) if not filename: filename = fileSpec.filename targetPathname = Filename(self.getPackageDir(), filename) targetPathname.setBinary() channel = self.http.makeChannel(False) # If there's a previous partial download, attempt to resume it. bytesStarted = 0 if allowPartial and not cacheBust and targetPathname.exists(): bytesStarted = targetPathname.getFileSize() if bytesStarted < 1024 * 1024: # Not enough bytes downloaded to be worth the risk of # a partial download. bytesStarted = 0 elif bytesStarted >= fileSpec.size: # Couldn't possibly be our file. bytesStarted = 0 if bytesStarted: self.notify.info( "Resuming %s after %s bytes already downloaded" % (url, bytesStarted)) # Make sure the file is writable. os.chmod(targetPathname.toOsSpecific(), 0644) channel.beginGetSubdocument(request, bytesStarted, 0) else: # No partial download possible; get the whole file. targetPathname.makeDir() targetPathname.unlink() channel.beginGetDocument(request) channel.downloadToFile(targetPathname) while channel.run(): if step: step.bytesDone = channel.getBytesDownloaded( ) + channel.getFirstByteDelivered() if step.bytesDone > step.bytesNeeded: # Oops, too much data. Might as well abort; # it's the wrong file. self.notify.warning( "Got more data than expected for download %s" % (url)) break self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting %s" % (url)) yield self.stepFailed return yield self.stepContinue if step: step.bytesDone = channel.getBytesDownloaded( ) + channel.getFirstByteDelivered() self.__updateStepProgress(step) if not channel.isValid(): self.notify.warning("Failed to download %s" % (url)) elif not fileSpec.fullVerify(self.getPackageDir(), pathname=targetPathname, notify=self.notify): self.notify.warning( "After downloading, %s incorrect" % (Filename(fileSpec.filename).getBasename())) # This attempt failed. Maybe the original contents.xml # file is stale. Try re-downloading it now, just to be # sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload return else: # Success! yield self.stepComplete return # Maybe the mirror is bad. Go back and try the next # mirror. # All attempts failed. Maybe the original contents.xml file # is stale. Try re-downloading it now, just to be sure. if self.host.redownloadContentsFile(self.http): # Yes! Go back and start over from the beginning. yield self.restartDownload return # All mirrors failed; the server (or the internet connection) # must be just fubar. yield self.stepFailed return
def __checkArchiveStatus(self): """ Returns true if the archive and all extractable files are already correct on disk, false otherwise. """ if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # Assume that everything is just fine. return True # Get a list of all of the files in the directory, so we can # remove files that don't belong. contents = self.__scanDirectoryRecursively(self.getPackageDir()) self.__removeFileFromList(contents, self.descFileBasename) self.__removeFileFromList(contents, self.compressedArchive.filename) self.__removeFileFromList(contents, self.UsageBasename) if not self.asMirror: self.__removeFileFromList(contents, self.uncompressedArchive.filename) for file in self.extracts: self.__removeFileFromList(contents, file.filename) # Now, any files that are still in the contents list don't # belong. It's important to remove these files before we # start verifying the files that we expect to find here, in # case there is a problem with ambiguous filenames or # something (e.g. case insensitivity). for filename in contents: self.notify.info("Removing %s" % (filename)) pathname = Filename(self.getPackageDir(), filename) pathname.unlink() self.updated = True if self.asMirror: return self.compressedArchive.quickVerify(self.getPackageDir(), notify=self.notify) allExtractsOk = True if not self.uncompressedArchive.quickVerify(self.getPackageDir(), notify=self.notify): self.notify.debug("File is incorrect: %s" % (self.uncompressedArchive.filename)) allExtractsOk = False if allExtractsOk: # OK, the uncompressed archive is good; that means there # shouldn't be a compressed archive file here. pathname = Filename(self.getPackageDir(), self.compressedArchive.filename) pathname.unlink() for file in self.extracts: if not file.quickVerify(self.getPackageDir(), notify=self.notify): self.notify.debug("File is incorrect: %s" % (file.filename)) allExtractsOk = False break if allExtractsOk: self.notify.debug("All %s extracts of %s seem good." % (len(self.extracts), self.packageName)) return allExtractsOk
def __unpackArchive(self, step): """ Unpacks any files in the archive that want to be unpacked to disk. Yields one of stepComplete, stepFailed, restartDownload, or stepContinue. """ if not self.extracts: # Nothing to extract. self.hasPackage = True yield self.stepComplete; return if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to! yield self.stepFailed; return self.updated = True mfPathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) self.notify.info("Unpacking %s" % (mfPathname)) mf = Multifile() if not mf.openRead(mfPathname): self.notify.warning("Couldn't open %s" % (mfPathname)) yield self.stepFailed; return allExtractsOk = True step.bytesDone = 0 for file in self.extracts: i = mf.findSubfile(file.filename) if i == -1: self.notify.warning("Not in Multifile: %s" % (file.filename)) allExtractsOk = False continue targetPathname = Filename(self.getPackageDir(), file.filename) targetPathname.unlink() if not mf.extractSubfile(i, targetPathname): self.notify.warning("Couldn't extract: %s" % (file.filename)) allExtractsOk = False continue if not file.quickVerify(self.getPackageDir(), notify = self.notify): self.notify.warning("After extracting, still incorrect: %s" % (file.filename)) allExtractsOk = False continue # Make sure it's executable, and not writable. os.chmod(targetPathname.toOsSpecific(), 0555) step.bytesDone += file.size self.__updateStepProgress(step) if taskMgr.destroyed: # If the task manager has been destroyed, we must # be shutting down. Get out of here. self.notify.warning("Task Manager destroyed, aborting unpacking %s" % (mfPathname)) yield self.stepFailed; return yield self.stepContinue if not allExtractsOk: yield self.stepFailed; return self.hasPackage = True yield self.stepComplete; return