def downloadNextFile(self, task): while self.nextNewsFile < len(self.newsFiles) and 'aaver' in self.newsFiles[self.nextNewsFile]: self.nextNewsFile += 1 if self.nextNewsFile >= len(self.newsFiles): self.notify.info('Done downloading news.') self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, 'filename'): del self.filename self.redownloadingNews = False if self.active: self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float(len(self.newsFiles)) self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) self.notify.info('testing for %s' % localFilename.getFullpath()) doc = DocumentSpec(self.url) if self.filename in self.newsCache: size, date = self.newsCache[self.filename] if date and localFilename.exists() and (size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName)
def downloadNextFile(self, task): while self.nextNewsFile < len(self.newsFiles) and "aaver" in self.newsFiles[self.nextNewsFile]: self.nextNewsFile += 1 if self.nextNewsFile >= len(self.newsFiles): self.notify.info("Done downloading news.") self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, "filename"): del self.filename self.redownloadingNews = False if self.active: self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float(len(self.newsFiles)) self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) self.notify.info("testing for %s" % localFilename.getFullpath()) doc = DocumentSpec(self.url) if self.filename in self.newsCache: size, date = self.newsCache[self.filename] if date and localFilename.exists() and (size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName)
def downloadNextFile(self, task): """ Starts the next news file downloading from the HTTP server. """ if self.nextNewsFile >= len(self.newsFiles): # Hey, we're done! self.notify.info("Done downloading news.") self.percentDownloaded = 1 del self.newsFiles del self.nextNewsFile del self.newsUrl del self.newsDir del self.ch del self.url if hasattr(self, 'filename'): del self.filename self.redownloadingNews = False if self.active: # If we're looking at the page now, go ahead and load it. self.parseNewsContent() return task.done self.percentDownloaded = float(self.nextNewsFile) / float( len(self.newsFiles)) # Get the next file on the list. self.filename = self.newsFiles[self.nextNewsFile] self.nextNewsFile += 1 self.url = self.newsUrl + self.filename localFilename = Filename(self.newsDir, self.filename) doc = DocumentSpec(self.url) if self.filename in self.newsCache: # We have already downloaded this file. Ask the # server to give us another copy only if the server's # copy is newer. size, date = self.newsCache[self.filename] if date and localFilename.exists() and ( size == 0 or localFilename.getFileSize() == size): doc.setDate(date) doc.setRequestMode(doc.RMNewer) self.ch.beginGetDocument(doc) self.ch.downloadToFile(localFilename) taskMgr.remove(self.RedownloadTaskName) taskMgr.add(self.downloadCurrentFileTask, self.RedownloadTaskName)
def makeBundle(startDir): fstartDir = Filename.fromOsSpecific(startDir) # Search for nppandad along $DYLD_LIBRARY_PATH. path = DSearchPath() if 'LD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['LD_LIBRARY_PATH']) if 'DYLD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['DYLD_LIBRARY_PATH']) nppanda3d = path.findFile('nppanda3d') if not nppanda3d: raise StandardError, "Couldn't find nppanda3d on path." # Generate the bundle directory structure rootFilename = Filename(fstartDir, 'bundle') if os.path.exists(rootFilename.toOsSpecific()): shutil.rmtree(rootFilename.toOsSpecific()) bundleFilename = Filename(rootFilename, 'nppanda3d.plugin') plistFilename = Filename(bundleFilename, 'Contents/Info.plist') plistFilename.makeDir() exeFilename = Filename(bundleFilename, 'Contents/MacOS/nppanda3d') exeFilename.makeDir() resourceFilename = Filename(bundleFilename, 'Contents/Resources/nppanda3d.rsrc') resourceFilename.makeDir() # Compile the .r file to an .rsrc file. os.system('/Developer/Tools/Rez -useDF -o %s %s' % (resourceFilename.toOsSpecific(), Filename(fstartDir, "nppanda3d.r").toOsSpecific())) if not resourceFilename.exists(): raise IOError, 'Unable to run Rez' # Copy in Info.plist and the compiled executable. shutil.copyfile( Filename(fstartDir, "nppanda3d.plist").toOsSpecific(), plistFilename.toOsSpecific()) shutil.copyfile(nppanda3d.toOsSpecific(), exeFilename.toOsSpecific()) # All done! bundleFilename.touch() print bundleFilename.toOsSpecific()
def makeBundle(startDir): fstartDir = Filename.fromOsSpecific(startDir) # Search for nppandad along $DYLD_LIBRARY_PATH. path = DSearchPath() if 'LD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['LD_LIBRARY_PATH']) if 'DYLD_LIBRARY_PATH' in os.environ: path.appendPath(os.environ['DYLD_LIBRARY_PATH']) nppanda3d = path.findFile('nppanda3d') if not nppanda3d: raise StandardError, "Couldn't find nppanda3d on path." # Generate the bundle directory structure rootFilename = Filename(fstartDir, 'bundle') if os.path.exists(rootFilename.toOsSpecific()): shutil.rmtree(rootFilename.toOsSpecific()) bundleFilename = Filename(rootFilename, 'nppanda3d.plugin') plistFilename = Filename(bundleFilename, 'Contents/Info.plist') plistFilename.makeDir() exeFilename = Filename(bundleFilename, 'Contents/MacOS/nppanda3d') exeFilename.makeDir() resourceFilename = Filename(bundleFilename, 'Contents/Resources/nppanda3d.rsrc') resourceFilename.makeDir() # Compile the .r file to an .rsrc file. os.system('/Developer/Tools/Rez -useDF -o %s %s' % ( resourceFilename.toOsSpecific(), Filename(fstartDir, "nppanda3d.r").toOsSpecific())) if not resourceFilename.exists(): raise IOError, 'Unable to run Rez' # Copy in Info.plist and the compiled executable. shutil.copyfile(Filename(fstartDir, "nppanda3d.plist").toOsSpecific(), plistFilename.toOsSpecific()) shutil.copyfile(nppanda3d.toOsSpecific(), exeFilename.toOsSpecific()) # All done! bundleFilename.touch() print bundleFilename.toOsSpecific()
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 __buildInstallPlans(self): """ Sets up self.installPlans, a list of one or more "plans" to download and install the package. """ pc = PStatCollector(':App:PackageInstaller:buildInstallPlans') pc.start() self.hasPackage = False if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to download anything. self.installPlans = [] pc.stop() return if self.asMirror: # If we're just downloading a mirror archive, we only need # to get the compressed archive file. # Build a one-item install plan to download the compressed # archive. downloadSize = self.compressedArchive.size func = lambda step, fileSpec=self.compressedArchive: self.__downloadFile( step, fileSpec, allowPartial=True) step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') installPlan = [step] self.installPlans = [installPlan] pc.stop() return # The normal download process. Determine what we will need to # download, and build a plan (or two) to download it all. self.installPlans = None # We know we will at least need to unpack the archive contents # at the end. unpackSize = 0 for file in self.extracts: unpackSize += file.size step = self.InstallStep(self.__unpackArchive, unpackSize, self.unpackFactor, 'unpack') planA = [step] # If the uncompressed archive file is good, that's all we'll # need to do. self.uncompressedArchive.actualFile = None if self.uncompressedArchive.quickVerify(self.getPackageDir(), notify=self.notify): self.installPlans = [planA] pc.stop() return # Maybe the compressed archive file is good. if self.compressedArchive.quickVerify(self.getPackageDir(), notify=self.notify): uncompressSize = self.uncompressedArchive.size step = self.InstallStep(self.__uncompressArchive, uncompressSize, self.uncompressFactor, 'uncompress') planA = [step] + planA self.installPlans = [planA] pc.stop() return # Maybe we can download one or more patches. We'll come back # to that in a minute as plan A. For now, construct plan B, # which will be to download the whole archive. planB = planA[:] uncompressSize = self.uncompressedArchive.size step = self.InstallStep(self.__uncompressArchive, uncompressSize, self.uncompressFactor, 'uncompress') planB = [step] + planB downloadSize = self.compressedArchive.size func = lambda step, fileSpec=self.compressedArchive: self.__downloadFile( step, fileSpec, allowPartial=True) step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') planB = [step] + planB # Now look for patches. Start with the md5 hash from the # uncompressedArchive file we have on disk, and see if we can # find a patch chain from this file to our target. pathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) fileSpec = self.uncompressedArchive.actualFile if fileSpec is None and pathname.exists(): fileSpec = FileSpec() fileSpec.fromFile(self.getPackageDir(), self.uncompressedArchive.filename) plan = None if fileSpec: plan = self.__findPatchChain(fileSpec) if plan: # We can download patches. Great! That means this is # plan A, and the full download is plan B (in case # something goes wrong with the patching). planA = plan + planA self.installPlans = [planA, planB] else: # There are no patches to download, oh well. Stick with # plan B as the only plan. self.installPlans = [planB] # In case of unexpected failures on the internet, we will retry # the full download instead of just giving up. for retry in range(ConfigVariableInt('package-full-dl-retries', 1)): self.installPlans.append(planB[:]) pc.stop()
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 __buildInstallPlans(self): """ Sets up self.installPlans, a list of one or more "plans" to download and install the package. """ pc = PStatCollector(':App:PackageInstaller:buildInstallPlans') pc.start() self.hasPackage = False if self.host.appRunner and self.host.appRunner.verifyContents == self.host.appRunner.P3DVCNever: # We're not allowed to download anything. self.installPlans = [] pc.stop() return if self.asMirror: # If we're just downloading a mirror archive, we only need # to get the compressed archive file. # Build a one-item install plan to download the compressed # archive. downloadSize = self.compressedArchive.size func = lambda step, fileSpec = self.compressedArchive: self.__downloadFile(step, fileSpec, allowPartial = True) step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') installPlan = [step] self.installPlans = [installPlan] pc.stop() return # The normal download process. Determine what we will need to # download, and build a plan (or two) to download it all. self.installPlans = None # We know we will at least need to unpack the archive contents # at the end. unpackSize = 0 for file in self.extracts: unpackSize += file.size step = self.InstallStep(self.__unpackArchive, unpackSize, self.unpackFactor, 'unpack') planA = [step] # If the uncompressed archive file is good, that's all we'll # need to do. self.uncompressedArchive.actualFile = None if self.uncompressedArchive.quickVerify(self.getPackageDir(), notify = self.notify): self.installPlans = [planA] pc.stop() return # Maybe the compressed archive file is good. if self.compressedArchive.quickVerify(self.getPackageDir(), notify = self.notify): uncompressSize = self.uncompressedArchive.size step = self.InstallStep(self.__uncompressArchive, uncompressSize, self.uncompressFactor, 'uncompress') planA = [step] + planA self.installPlans = [planA] pc.stop() return # Maybe we can download one or more patches. We'll come back # to that in a minute as plan A. For now, construct plan B, # which will be to download the whole archive. planB = planA[:] uncompressSize = self.uncompressedArchive.size step = self.InstallStep(self.__uncompressArchive, uncompressSize, self.uncompressFactor, 'uncompress') planB = [step] + planB downloadSize = self.compressedArchive.size func = lambda step, fileSpec = self.compressedArchive: self.__downloadFile(step, fileSpec, allowPartial = True) step = self.InstallStep(func, downloadSize, self.downloadFactor, 'download') planB = [step] + planB # Now look for patches. Start with the md5 hash from the # uncompressedArchive file we have on disk, and see if we can # find a patch chain from this file to our target. pathname = Filename(self.getPackageDir(), self.uncompressedArchive.filename) fileSpec = self.uncompressedArchive.actualFile if fileSpec is None and pathname.exists(): fileSpec = FileSpec() fileSpec.fromFile(self.getPackageDir(), self.uncompressedArchive.filename) plan = None if fileSpec: plan = self.__findPatchChain(fileSpec) if plan: # We can download patches. Great! That means this is # plan A, and the full download is plan B (in case # something goes wrong with the patching). planA = plan + planA self.installPlans = [planA, planB] else: # There are no patches to download, oh well. Stick with # plan B as the only plan. self.installPlans = [planB] # In case of unexpected failures on the internet, we will retry # the full download instead of just giving up. for retry in range(ConfigVariableInt('package-full-dl-retries', 1)): self.installPlans.append(planB[:]) pc.stop()
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
sys.exit(1) if shortname == "": shortname = appFilename.getBasenameWoExtension() if shortname.lower() != shortname or " " in shortname: print "\nProvided short name should be lowercase, and may not contain spaces!\n" if version == "" and deploy_mode == "installer": print '\nA version number is required in "installer" mode.\n' sys.exit(1) if not outputDir: print "\nYou must name the output directory with the -o parameter.\n" sys.exit(1) if not outputDir.exists(): print "\nThe specified output directory does not exist!\n" sys.exit(1) elif not outputDir.isDirectory(): print "\nThe specified output directory is a file!\n" sys.exit(1) if deploy_mode == "standalone": s = Standalone(appFilename, tokens) s.basename = shortname if currentPlatform: platform = PandaSystem.getPlatform() if platform.startswith("win"): s.build(Filename(outputDir, shortname + ".exe"), platform) else:
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 installPackagesInto(self, hostDir, platform): """ Installs the packages required by the .p3d file into the specified directory, for the given platform. """ if not self.includeRequires: return pkgTree = PackageTree(platform, hostDir, self.hostUrl) pkgTree.installPackage("images", None, self.standalone.host.hostUrl) for name, version, hostUrl in self.requires: pkgTree.installPackage(name, version, hostUrl) # Remove the extracted files from the compressed archive, to save space. vfs = VirtualFileSystem.getGlobalPtr() for package in pkgTree.packages.values(): if package.uncompressedArchive: archive = Filename(package.getPackageDir(), package.uncompressedArchive.filename) if not archive.exists(): continue mf = Multifile() # Make sure that it isn't mounted before altering it, just to be safe vfs.unmount(archive) os.chmod(archive.toOsSpecific(), 0644) if not mf.openReadWrite(archive): Installer.notify.warning("Failed to open archive %s" % (archive)) continue # We don't iterate over getNumSubfiles because we're # removing subfiles while we're iterating over them. subfiles = mf.getSubfileNames() for subfile in subfiles: # We do *NOT* call vfs.exists here in case the package is mounted. if Filename(package.getPackageDir(), subfile).exists(): Installer.notify.debug("Removing already-extracted %s from multifile" % (subfile)) mf.removeSubfile(subfile) # This seems essential for mf.close() not to crash later. mf.repack() # If we have no subfiles left, we can just remove the multifile. # if mf.getNumSubfiles() == 0: # Installer.notify.info("Removing empty archive %s" % (package.uncompressedArchive.filename)) # mf.close() # archive.unlink() # else: mf.close() try: os.chmod(archive.toOsSpecific(), 0444) except: pass # Write out our own contents.xml file. doc = TiXmlDocument() decl = TiXmlDeclaration("1.0", "utf-8", "") doc.InsertEndChild(decl) xcontents = TiXmlElement("contents") for package in pkgTree.packages.values(): xpackage = TiXmlElement("package") xpackage.SetAttribute("name", package.packageName) if package.platform: xpackage.SetAttribute("platform", package.platform) assert package.platform == platform if package.packageVersion: xpackage.SetAttribute("version", version) xpackage.SetAttribute( "filename", package.packageName + "/" + package.packageVersion + "/" + package.descFileBasename ) else: xpackage.SetAttribute("filename", package.packageName + "/" + package.descFileBasename) xcontents.InsertEndChild(xpackage) doc.InsertEndChild(xcontents) doc.SaveFile(Filename(hostDir, "contents.xml").toOsSpecific())
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
sys.exit(1) if shortname == '': shortname = appFilename.getBasenameWoExtension() if shortname.lower() != shortname or ' ' in shortname: print '\nProvided short name should be lowercase, and may not contain spaces!\n' if version == '' and deploy_mode == 'installer': print '\nA version number is required in "installer" mode.\n' sys.exit(1) if not outputDir: print '\nYou must name the output directory with the -o parameter.\n' sys.exit(1) if not outputDir.exists(): print '\nThe specified output directory does not exist!\n' sys.exit(1) elif not outputDir.isDirectory(): print '\nThe specified output directory is a file!\n' sys.exit(1) if deploy_mode == 'standalone': s = Standalone(appFilename, tokens) s.basename = shortname if currentPlatform: platform = PandaSystem.getPlatform() if platform.startswith("win"): s.build(Filename(outputDir, shortname + ".exe"), platform) else:
def installPackagesInto(self, hostDir, platform): """ Installs the packages required by the .p3d file into the specified directory, for the given platform. """ if not self.includeRequires: return pkgTree = PackageTree(platform, hostDir, self.hostUrl) pkgTree.installPackage("images", None, self.standalone.host.hostUrl) for name, version, hostUrl in self.requires: pkgTree.installPackage(name, version, hostUrl) # Remove the extracted files from the compressed archive, to save space. vfs = VirtualFileSystem.getGlobalPtr() for package in pkgTree.packages.values(): if package.uncompressedArchive: archive = Filename(package.getPackageDir(), package.uncompressedArchive.filename) if not archive.exists(): continue mf = Multifile() # Make sure that it isn't mounted before altering it, just to be safe vfs.unmount(archive) os.chmod(archive.toOsSpecific(), 0644) if not mf.openReadWrite(archive): Installer.notify.warning("Failed to open archive %s" % (archive)) continue # We don't iterate over getNumSubfiles because we're # removing subfiles while we're iterating over them. subfiles = mf.getSubfileNames() for subfile in subfiles: # We do *NOT* call vfs.exists here in case the package is mounted. if Filename(package.getPackageDir(), subfile).exists(): Installer.notify.debug( "Removing already-extracted %s from multifile" % (subfile)) mf.removeSubfile(subfile) # This seems essential for mf.close() not to crash later. mf.repack() # If we have no subfiles left, we can just remove the multifile. #if mf.getNumSubfiles() == 0: # Installer.notify.info("Removing empty archive %s" % (package.uncompressedArchive.filename)) # mf.close() # archive.unlink() #else: mf.close() try: os.chmod(archive.toOsSpecific(), 0444) except: pass # Write out our own contents.xml file. doc = TiXmlDocument() decl = TiXmlDeclaration("1.0", "utf-8", "") doc.InsertEndChild(decl) xcontents = TiXmlElement("contents") for package in pkgTree.packages.values(): xpackage = TiXmlElement('package') xpackage.SetAttribute('name', package.packageName) if package.platform: xpackage.SetAttribute('platform', package.platform) assert package.platform == platform if package.packageVersion: xpackage.SetAttribute('version', version) xpackage.SetAttribute( 'filename', package.packageName + "/" + package.packageVersion + "/" + package.descFileBasename) else: xpackage.SetAttribute( 'filename', package.packageName + "/" + package.descFileBasename) xcontents.InsertEndChild(xpackage) doc.InsertEndChild(xcontents) doc.SaveFile(Filename(hostDir, "contents.xml").toOsSpecific())