def getHost(self, hostUrl): if hostUrl in self.hosts: return self.hosts[hostUrl] host = HostInfo(hostUrl, appRunner=appRunner, hostDir=self.hostDir, asMirror=False, perPlatform=False) if not host.hasContentsFile: if not host.readContentsFile(): if not host.downloadContentsFile(self.http): Installer.notify.error("couldn't read host %s" % host.hostUrl) return None self.hosts[hostUrl] = host return host
class Standalone: """ This class creates a standalone executable from a given .p3d file. """ notify = directNotify.newCategory("Standalone") def __init__(self, p3dfile, tokens={}): self.p3dfile = Filename(p3dfile) self.basename = self.p3dfile.getBasenameWoExtension() self.tokens = tokens self.tempDir = Filename.temporary("", self.basename, "") + "/" self.tempDir.makeDir() self.host = HostInfo( PandaSystem.getPackageHostUrl(), appRunner=appRunner, hostDir=self.tempDir, asMirror=False, perPlatform=True ) self.http = HTTPClient.getGlobalPtr() if not self.host.hasContentsFile: if not self.host.readContentsFile(): if not self.host.downloadContentsFile(self.http): Standalone.notify.error("couldn't read host") return def __del__(self): try: appRunner.rmtree(self.tempDir) except: try: shutil.rmtree(self.tempDir.toOsSpecific()) except: pass def buildAll(self, outputDir="."): """ Builds standalone executables for every known platform, into the specified output directory. """ platforms = set() for package in self.host.getPackages(name="p3dembed"): platforms.add(package.platform) if len(platforms) == 0: Standalone.notify.warning("No platforms found to build for!") outputDir = Filename(outputDir + "/") outputDir.makeDir() for platform in platforms: if platform.startswith("win"): self.build(Filename(outputDir, platform + "/" + self.basename + ".exe"), platform) else: self.build(Filename(outputDir, platform + "/" + self.basename), platform) def build(self, output, platform=None, extraTokens={}): """ Builds a standalone executable and stores it into the path indicated by the 'output' argument. You can specify to build for a different platform by altering the 'platform' argument. """ if platform == None: platform = PandaSystem.getPlatform() vfs = VirtualFileSystem.getGlobalPtr() for package in self.host.getPackages(name="p3dembed", platform=platform): if not package.downloadDescFile(self.http): Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) continue if not package.downloadPackage(self.http): Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) continue # Figure out where p3dembed might be now. if package.platform.startswith("win"): # Use p3dembedw unless console_environment was set. if extraTokens.get("console_environment", self.tokens.get("console_environment", 0)) != 0: p3dembed = Filename(self.host.hostDir, "p3dembed/%s/p3dembed.exe" % package.platform) else: p3dembed = Filename(self.host.hostDir, "p3dembed/%s/p3dembedw.exe" % package.platform) # Fallback for older p3dembed versions if not vfs.exists(p3dembed): Filename(self.host.hostDir, "p3dembed/%s/p3dembed.exe" % package.platform) else: p3dembed = Filename(self.host.hostDir, "p3dembed/%s/p3dembed" % package.platform) if not vfs.exists(p3dembed): Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) continue return self.embed(output, p3dembed, extraTokens) Standalone.notify.error("Failed to build standalone for platform %s" % platform) def embed(self, output, p3dembed, extraTokens={}): """ Embeds the p3d file into the provided p3dembed executable. This function is not really useful - use build() or buildAll() instead. """ # Load the p3dembed data into memory size = p3dembed.getFileSize() p3dembed_data = VirtualFileSystem.getGlobalPtr().readFile(p3dembed, True) assert len(p3dembed_data) == size # Find the magic size string and replace it with the real size, # regardless of the endianness of the p3dembed executable. hex_size = hex(size)[2:].rjust(8, "0") enc_size = "".join([chr(int(hex_size[i] + hex_size[i + 1], 16)) for i in range(0, len(hex_size), 2)]) p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC, enc_size) p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC[::-1], enc_size[::-1]) # Write the output file Standalone.notify.info("Creating %s..." % output) output.makeDir() ohandle = open(output.toOsSpecific(), "wb") ohandle.write(p3dembed_data) # Write out the tokens. Set log_basename to the basename by default tokens = {"log_basename": self.basename} tokens.update(self.tokens) tokens.update(extraTokens) for token in tokens.items(): ohandle.write("\0%s=%s" % token) ohandle.write("\0\0") # Buffer the p3d file to the output file. 1 MB buffer size. phandle = open(self.p3dfile.toOsSpecific(), "rb") buf = phandle.read(1024 * 1024) while len(buf) != 0: ohandle.write(buf) buf = phandle.read(1024 * 1024) ohandle.close() phandle.close() os.chmod(output.toOsSpecific(), 0755) def getExtraFiles(self, platform): """ Returns a list of extra files that will need to be included with the standalone executable in order for it to run, such as dependent libraries. The returned paths are full absolute paths. """ package = self.host.getPackages(name="p3dembed", platform=platform)[0] if not package.downloadDescFile(self.http): Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) return [] if not package.downloadPackage(self.http): Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) return [] filenames = [] vfs = VirtualFileSystem.getGlobalPtr() for e in package.extracts: if e.basename not in [ "p3dembed", "p3dembed.exe", "p3dembed.exe.manifest", "p3dembedw.exe", "p3dembedw.exe.manifest", ]: filename = Filename(package.getPackageDir(), e.filename) filename.makeAbsolute() if vfs.exists(filename): filenames.append(filename) else: Standalone.notify.error("%s mentioned in xml, but does not exist" % e.filename) return filenames
class Standalone: """ This class creates a standalone executable from a given .p3d file. """ notify = directNotify.newCategory("Standalone") def __init__(self, p3dfile, tokens={}): self.p3dfile = Filename(p3dfile) self.basename = self.p3dfile.getBasenameWoExtension() self.tokens = tokens self.tempDir = Filename.temporary("", self.basename, "") + "/" self.tempDir.makeDir() self.host = HostInfo(PandaSystem.getPackageHostUrl(), appRunner=appRunner, hostDir=self.tempDir, asMirror=False, perPlatform=True) self.http = HTTPClient.getGlobalPtr() if not self.host.hasContentsFile: if not self.host.readContentsFile(): if not self.host.downloadContentsFile(self.http): Standalone.notify.error("couldn't read host") return def __del__(self): try: appRunner.rmtree(self.tempDir) except: try: shutil.rmtree(self.tempDir.toOsSpecific()) except: pass def buildAll(self, outputDir="."): """ Builds standalone executables for every known platform, into the specified output directory. """ platforms = set() for package in self.host.getPackages(name="p3dembed"): platforms.add(package.platform) if len(platforms) == 0: Standalone.notify.warning("No platforms found to build for!") outputDir = Filename(outputDir + "/") outputDir.makeDir() for platform in platforms: if platform.startswith("win"): self.build( Filename(outputDir, platform + "/" + self.basename + ".exe"), platform) else: self.build(Filename(outputDir, platform + "/" + self.basename), platform) def build(self, output, platform=None, extraTokens={}): """ Builds a standalone executable and stores it into the path indicated by the 'output' argument. You can specify to build for a different platform by altering the 'platform' argument. """ if platform == None: platform = PandaSystem.getPlatform() vfs = VirtualFileSystem.getGlobalPtr() for package in self.host.getPackages(name="p3dembed", platform=platform): if not package.downloadDescFile(self.http): Standalone.notify.warning( " -> %s failed for platform %s" % (package.packageName, package.platform)) continue if not package.downloadPackage(self.http): Standalone.notify.warning( " -> %s failed for platform %s" % (package.packageName, package.platform)) continue # Figure out where p3dembed might be now. if package.platform.startswith("win"): # Use p3dembedw unless console_environment was set. if extraTokens.get("console_environment", self.tokens.get("console_environment", 0)) != 0: p3dembed = Filename( self.host.hostDir, "p3dembed/%s/p3dembed.exe" % package.platform) else: p3dembed = Filename( self.host.hostDir, "p3dembed/%s/p3dembedw.exe" % package.platform) # Fallback for older p3dembed versions if not vfs.exists(p3dembed): Filename(self.host.hostDir, "p3dembed/%s/p3dembed.exe" % package.platform) else: p3dembed = Filename(self.host.hostDir, "p3dembed/%s/p3dembed" % package.platform) if not vfs.exists(p3dembed): Standalone.notify.warning( " -> %s failed for platform %s" % (package.packageName, package.platform)) continue return self.embed(output, p3dembed, extraTokens) Standalone.notify.error("Failed to build standalone for platform %s" % platform) def embed(self, output, p3dembed, extraTokens={}): """ Embeds the p3d file into the provided p3dembed executable. This function is not really useful - use build() or buildAll() instead. """ # Load the p3dembed data into memory size = p3dembed.getFileSize() p3dembed_data = VirtualFileSystem.getGlobalPtr().readFile( p3dembed, True) assert len(p3dembed_data) == size # Find the magic size string and replace it with the real size, # regardless of the endianness of the p3dembed executable. hex_size = hex(size)[2:].rjust(8, "0") enc_size = "".join([ chr(int(hex_size[i] + hex_size[i + 1], 16)) for i in range(0, len(hex_size), 2) ]) p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC, enc_size) p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC[::-1], enc_size[::-1]) # Write the output file Standalone.notify.info("Creating %s..." % output) output.makeDir() ohandle = open(output.toOsSpecific(), "wb") ohandle.write(p3dembed_data) # Write out the tokens. Set log_basename to the basename by default tokens = {"log_basename": self.basename} tokens.update(self.tokens) tokens.update(extraTokens) for token in tokens.items(): ohandle.write("\0%s=%s" % token) ohandle.write("\0\0") # Buffer the p3d file to the output file. 1 MB buffer size. phandle = open(self.p3dfile.toOsSpecific(), "rb") buf = phandle.read(1024 * 1024) while len(buf) != 0: ohandle.write(buf) buf = phandle.read(1024 * 1024) ohandle.close() phandle.close() os.chmod(output.toOsSpecific(), 0755) def getExtraFiles(self, platform): """ Returns a list of extra files that will need to be included with the standalone executable in order for it to run, such as dependent libraries. The returned paths are full absolute paths. """ package = self.host.getPackages(name="p3dembed", platform=platform)[0] if not package.downloadDescFile(self.http): Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) return [] if not package.downloadPackage(self.http): Standalone.notify.warning(" -> %s failed for platform %s" % (package.packageName, package.platform)) return [] filenames = [] vfs = VirtualFileSystem.getGlobalPtr() for e in package.extracts: if e.basename not in [ "p3dembed", "p3dembed.exe", "p3dembed.exe.manifest", "p3dembedw.exe", "p3dembedw.exe.manifest" ]: filename = Filename(package.getPackageDir(), e.filename) filename.makeAbsolute() if vfs.exists(filename): filenames.append(filename) else: Standalone.notify.error( "%s mentioned in xml, but does not exist" % e.filename) return filenames