Port pdeploy to Python 3

This commit is contained in:
rdb 2015-09-30 14:06:12 +02:00
parent 532bee3b9e
commit 1ccf1cf29b
4 changed files with 75 additions and 73 deletions

View File

@ -5,7 +5,7 @@ to build for as many platforms as possible. """
__all__ = ["Standalone", "Installer"] __all__ = ["Standalone", "Installer"]
import os, sys, subprocess, tarfile, shutil, time, zipfile, socket, getpass, struct import os, sys, subprocess, tarfile, shutil, time, zipfile, socket, getpass, struct
from cStringIO import StringIO from io import BytesIO, TextIOWrapper
from direct.directnotify.DirectNotifyGlobal import * from direct.directnotify.DirectNotifyGlobal import *
from direct.showbase.AppRunnerGlobal import appRunner from direct.showbase.AppRunnerGlobal import appRunner
from panda3d.core import PandaSystem, HTTPClient, Filename, VirtualFileSystem, Multifile from panda3d.core import PandaSystem, HTTPClient, Filename, VirtualFileSystem, Multifile
@ -21,8 +21,8 @@ try:
except ImportError: except ImportError:
pwd = None pwd = None
# Make sure this matches with the magic in p3dEmbed.cxx. # Make sure this matches with the magic in p3dEmbedMain.cxx.
P3DEMBED_MAGIC = "\xFF\x3D\x3D\x00" P3DEMBED_MAGIC = 0xFF3D3D00
# This filter function is used when creating # This filter function is used when creating
# an archive that should be owned by root. # an archive that should be owned by root.
@ -161,10 +161,10 @@ class Standalone:
# Find the magic size string and replace it with the real size, # Find the magic size string and replace it with the real size,
# regardless of the endianness of the p3dembed executable. # regardless of the endianness of the p3dembed executable.
hex_size = hex(size)[2:].rjust(8, "0") p3dembed_data = p3dembed_data.replace(struct.pack('>I', P3DEMBED_MAGIC),
enc_size = "".join([chr(int(hex_size[i] + hex_size[i + 1], 16)) for i in range(0, len(hex_size), 2)]) struct.pack('>I', size))
p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC, enc_size) p3dembed_data = p3dembed_data.replace(struct.pack('<I', P3DEMBED_MAGIC),
p3dembed_data = p3dembed_data.replace(P3DEMBED_MAGIC[::-1], enc_size[::-1]) struct.pack('<I', size))
# Write the output file # Write the output file
Standalone.notify.info("Creating %s..." % output) Standalone.notify.info("Creating %s..." % output)
@ -173,12 +173,15 @@ class Standalone:
ohandle.write(p3dembed_data) ohandle.write(p3dembed_data)
# Write out the tokens. Set log_basename to the basename by default # Write out the tokens. Set log_basename to the basename by default
tokens = {"log_basename" : self.basename} tokens = {"log_basename": self.basename}
tokens.update(self.tokens) tokens.update(self.tokens)
tokens.update(extraTokens) tokens.update(extraTokens)
for token in tokens.items(): for key, value in tokens.items():
ohandle.write("\0%s=%s" % token) ohandle.write(b"\0")
ohandle.write("\0\0") ohandle.write(key.encode('ascii'))
ohandle.write(b"=")
ohandle.write(value.encode())
ohandle.write(b"\0\0")
# Buffer the p3d file to the output file. 1 MB buffer size. # Buffer the p3d file to the output file. 1 MB buffer size.
phandle = open(self.p3dfile.toOsSpecific(), "rb") phandle = open(self.p3dfile.toOsSpecific(), "rb")
@ -394,7 +397,7 @@ class Icon:
vfs = VirtualFileSystem.getGlobalPtr() vfs = VirtualFileSystem.getGlobalPtr()
stream = vfs.openWriteFile(fn, False, True) stream = vfs.openWriteFile(fn, False, True)
icns = open(stream, 'wb') icns = open(stream, 'wb')
icns.write('icns\0\0\0\0') icns.write(b'icns\0\0\0\0')
icon_types = {16: 'is32', 32: 'il32', 48: 'ih32', 128: 'it32'} icon_types = {16: 'is32', 32: 'il32', 48: 'ih32', 128: 'it32'}
mask_types = {16: 's8mk', 32: 'l8mk', 48: 'h8mk', 128: 't8mk'} mask_types = {16: 's8mk', 32: 'l8mk', 48: 'h8mk', 128: 't8mk'}
@ -407,7 +410,7 @@ class Icon:
if pngtype is None: if pngtype is None:
continue continue
icns.write(png_types[size]) icns.write(png_types[size])
icns.write('\0\0\0\0') icns.write(b'\0\0\0\0')
start = icns.tell() start = icns.tell()
image.write(stream, "", pngtype) image.write(stream, "", pngtype)
@ -800,16 +803,18 @@ class Installer:
tempdir, totsize = self.__buildTempLinux(platform) tempdir, totsize = self.__buildTempLinux(platform)
# Create a control file in memory. # Create a control file in memory.
controlfile = StringIO() controlfile = BytesIO()
print >>controlfile, "Package: %s" % self.shortname.lower() cout = TextIOWrapper(controlfile, encoding='utf-8', newline='')
print >>controlfile, "Version: %s" % self.version cout.write(u"Package: %s\n" % self.shortname.lower())
print >>controlfile, "Maintainer: %s <%s>" % (self.authorname, self.authoremail) cout.write(u"Version: %s\n" % self.version)
print >>controlfile, "Section: games" cout.write(u"Maintainer: %s <%s>\n" % (self.authorname, self.authoremail))
print >>controlfile, "Priority: optional" cout.write(u"Section: games\n")
print >>controlfile, "Architecture: %s" % arch cout.write(u"Priority: optional\n")
print >>controlfile, "Installed-Size: %d" % -(-totsize / 1024) cout.write(u"Architecture: %s\n" % arch)
print >>controlfile, "Description: %s" % self.fullname cout.write(u"Installed-Size: %d\n" % -(-totsize // 1024))
print >>controlfile, "Depends: libc6, libgcc1, libstdc++6, libx11-6" cout.write(u"Description: %s\n" % self.fullname)
cout.write(u"Depends: libc6, libgcc1, libstdc++6, libx11-6\n")
cout.flush()
controlinfo = TarInfoRoot("control") controlinfo = TarInfoRoot("control")
controlinfo.mtime = modtime controlinfo.mtime = modtime
controlinfo.size = controlfile.tell() controlinfo.size = controlfile.tell()
@ -820,33 +825,43 @@ class Installer:
if output.exists(): if output.exists():
output.unlink() output.unlink()
debfile = open(output.toOsSpecific(), "wb") debfile = open(output.toOsSpecific(), "wb")
debfile.write("!<arch>\x0A") debfile.write(b"!<arch>\x0A")
debfile.write("debian-binary %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 4)) pad_mtime = str(modtime).encode().ljust(12, b' ')
debfile.write("2.0\x0A")
# Write the control.tar.gz to the archive. # The first entry is a special file that marks it a .deb.
debfile.write("control.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0)) debfile.write(b"debian-binary ")
debfile.write(pad_mtime)
debfile.write(b"0 0 100644 4 \x60\x0A")
debfile.write(b"2.0\x0A")
# Write the control.tar.gz to the archive. We'll leave the
# size 0 for now, and go back and fill it in later.
debfile.write(b"control.tar.gz ")
debfile.write(pad_mtime)
debfile.write(b"0 0 100644 0 \x60\x0A")
ctaroffs = debfile.tell() ctaroffs = debfile.tell()
ctarfile = tarfile.open("control.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot) ctarfile = tarfile.open("control.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot)
ctarfile.addfile(controlinfo, controlfile) ctarfile.addfile(controlinfo, controlfile)
ctarfile.close() ctarfile.close()
ctarsize = debfile.tell() - ctaroffs ctarsize = debfile.tell() - ctaroffs
if (ctarsize & 1): debfile.write("\x0A") if (ctarsize & 1): debfile.write(b"\x0A")
# Write the data.tar.gz to the archive. # Write the data.tar.gz to the archive. Again, leave size 0.
debfile.write("data.tar.gz %-12lu0 0 100644 %-10ld\x60\x0A" % (modtime, 0)) debfile.write(b"data.tar.gz ")
debfile.write(pad_mtime)
debfile.write(b"0 0 100644 0 \x60\x0A")
dtaroffs = debfile.tell() dtaroffs = debfile.tell()
dtarfile = tarfile.open("data.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot) dtarfile = tarfile.open("data.tar.gz", "w:gz", debfile, tarinfo = TarInfoRoot)
dtarfile.add(Filename(tempdir, "usr").toOsSpecific(), "/usr") dtarfile.add(Filename(tempdir, "usr").toOsSpecific(), "/usr")
dtarfile.close() dtarfile.close()
dtarsize = debfile.tell() - dtaroffs dtarsize = debfile.tell() - dtaroffs
if (dtarsize & 1): debfile.write("\x0A") if (dtarsize & 1): debfile.write(b"\x0A")
# Write the correct sizes of the archives. # Write the correct sizes of the archives.
debfile.seek(ctaroffs - 12) debfile.seek(ctaroffs - 12)
debfile.write("%-10ld" % ctarsize) debfile.write(str(ctarsize).encode().ljust(10, b' '))
debfile.seek(dtaroffs - 12) debfile.seek(dtaroffs - 12)
debfile.write("%-10ld" % dtarsize) debfile.write(str(dtarsize).encode().ljust(10, b' '))
debfile.close() debfile.close()
@ -873,18 +888,20 @@ class Installer:
tempdir, totsize = self.__buildTempLinux(platform) tempdir, totsize = self.__buildTempLinux(platform)
# Create a pkginfo file in memory. # Create a pkginfo file in memory.
pkginfo = StringIO() pkginfo = BytesIO()
print >>pkginfo, "# Generated using pdeploy" pout = TextIOWrapper(pkginfo, encoding='utf-8', newline='')
print >>pkginfo, "# %s" % time.ctime(modtime) pout.write(u"# Generated using pdeploy\n")
print >>pkginfo, "pkgname = %s" % self.shortname.lower() pout.write(u"# %s\n" % time.ctime(modtime))
print >>pkginfo, "pkgver = %s" % pkgver pout.write(u"pkgname = %s\n" % self.shortname.lower())
print >>pkginfo, "pkgdesc = %s" % self.fullname pout.write(u"pkgver = %s\n" % pkgver)
print >>pkginfo, "builddate = %s" % modtime pout.write(u"pkgdesc = %s\n" % self.fullname)
print >>pkginfo, "packager = %s <%s>" % (self.authorname, self.authoremail) pout.write(u"builddate = %s\n" % modtime)
print >>pkginfo, "size = %d" % totsize pout.write(u"packager = %s <%s>\n" % (self.authorname, self.authoremail))
print >>pkginfo, "arch = %s" % arch pout.write(u"size = %d\n" % totsize)
pout.write(u"arch = %s\n" % arch)
if self.licensename != "": if self.licensename != "":
print >>pkginfo, "license = %s" % self.licensename pout.write(u"license = %s\n" % self.licensename)
pout.flush()
pkginfoinfo = TarInfoRoot(".PKGINFO") pkginfoinfo = TarInfoRoot(".PKGINFO")
pkginfoinfo.mtime = modtime pkginfoinfo.mtime = modtime
pkginfoinfo.size = pkginfo.tell() pkginfoinfo.size = pkginfo.tell()

View File

@ -513,18 +513,15 @@ class HostInfo:
PackageInfo, returns it. """ PackageInfo, returns it. """
if not platform: if not platform:
# Ensure that we're on the same page with non-specified platform = None
# platforms. We have to use the empty string, not None,
# since Python 3 can't sort lists with both strings and None.
platform = ""
platforms = self.packages.setdefault((name, version), {}) platforms = self.packages.setdefault((name, version or ""), {})
package = platforms.get(platform, None) package = platforms.get("", None)
if not package: if not package:
package = PackageInfo(self, name, version, platform = platform, package = PackageInfo(self, name, version, platform = platform,
solo = solo, asMirror = self.asMirror, solo = solo, asMirror = self.asMirror,
perPlatform = perPlatform) perPlatform = perPlatform)
platforms[platform] = package platforms[platform or ""] = package
return package return package
@ -534,12 +531,12 @@ class HostInfo:
platform, if one is provided by this host, or None if not. """ platform, if one is provided by this host, or None if not. """
assert self.hasContentsFile assert self.hasContentsFile
platforms = self.packages.get((name, version or None), {}) platforms = self.packages.get((name, version or ""), {})
if platform is not None: if platform:
# In this case, we are looking for a specific platform # In this case, we are looking for a specific platform
# only. # only.
return platforms.get(platform or None, None) return platforms.get(platform, None)
# We are looking for one matching the current runtime # We are looking for one matching the current runtime
# platform. First, look for a package matching the current # platform. First, look for a package matching the current
@ -548,7 +545,7 @@ class HostInfo:
# If not found, look for one matching no particular platform. # If not found, look for one matching no particular platform.
if not package: if not package:
package = platforms.get(None, None) package = platforms.get("", None)
return package return package
@ -564,7 +561,7 @@ class HostInfo:
if name and pn != name: if name and pn != name:
continue continue
if platform is None: if not platform:
for p2 in platforms: for p2 in platforms:
package = self.getPackage(pn, version, platform = p2) package = self.getPackage(pn, version, platform = p2)
if package: if package:
@ -596,7 +593,7 @@ class HostInfo:
# current platform, or no particular platform. # current platform, or no particular platform.
package = platforms.get(PandaSystem.getPlatform(), None) package = platforms.get(PandaSystem.getPlatform(), None)
if not package: if not package:
package = platforms.get(None, None) package = platforms.get("", None)
if package: if package:
result.append(package) result.append(package)

View File

@ -523,7 +523,8 @@ class PackageInfo:
# In case of unexpected failures on the internet, we will retry # In case of unexpected failures on the internet, we will retry
# the full download instead of just giving up. # the full download instead of just giving up.
for retry in range(core.ConfigVariableInt('package-full-dl-retries', 1)): retries = core.ConfigVariableInt('package-full-dl-retries', 1).getValue()
for retry in range(retries):
self.installPlans.append(planB[:]) self.installPlans.append(planB[:])
pc.stop() pc.stop()

View File

@ -15,6 +15,7 @@ import sys
import os import os
import io import io
import encodings import encodings
from posixpath import join
_vfs = core.VirtualFileSystem.getGlobalPtr() _vfs = core.VirtualFileSystem.getGlobalPtr()
@ -331,20 +332,6 @@ def walk(top, topdown = True, onerror = None, followlinks = True):
if not topdown: if not topdown:
yield (top, dirnames, filenames) yield (top, dirnames, filenames)
def join(path, *args):
for part in args:
if part == '':
continue
if part.startswith('/'):
path = part
elif path.endswith('/'):
path = path + part
else:
path = '/'.join((path, part))
return path
def isfile(path): def isfile(path):
return _vfs.isRegularFile(core.Filename.fromOsSpecific(path)) return _vfs.isRegularFile(core.Filename.fromOsSpecific(path))