More pdeploy stuff.

This commit is contained in:
rdb 2009-12-23 20:23:52 +00:00
parent 36cd79a82f
commit a737a35314
3 changed files with 94 additions and 52 deletions

View File

@ -9,6 +9,7 @@ from direct.directnotify.DirectNotifyGlobal import *
from pandac.PandaModules import PandaSystem, HTTPClient, Filename, VirtualFileSystem
from direct.p3d.HostInfo import HostInfo
from direct.showbase.AppRunnerGlobal import appRunner
import glob
class CachedFile:
def __init__(self): self.str = ""
@ -48,6 +49,8 @@ class Standalone:
if len(platforms) == 0:
Standalone.notify.error("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)
@ -82,8 +85,7 @@ class Standalone:
Standalone.notify.error(" -> %s failed for platform %s" % (package.packageName, package.platform))
continue
self.embed(output, p3dembed)
return
return self.embed(output, p3dembed)
Standalone.notify.error("Failed to build standalone for platform %s" % platform)
@ -123,6 +125,28 @@ class Standalone:
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 will be absolute. """
for package in self.host.getPackages(name = "p3dembed", platform = platform):
if not package.downloadDescFile(self.http):
Standalone.notify.error(" -> %s failed for platform %s" % (package.packageName, package.platform))
continue
if not package.downloadPackage(self.http):
Standalone.notify.error(" -> %s failed for platform %s" % (package.packageName, package.platform))
continue
directory = Filename(self.host.hostDir, "p3dembed/%s/p3dembed.exe" % package.platform)
directory.makeAbsolute()
filelist = []
for f in glob.glob(os.path.join(directory.toOsSpecific(), "*")):
if not f.endswith("p3dembed") and not f.endswith("p3dembed.exe"):
filelist.append(Filename.fromOsSpecific(f))
return filelist
return []
class Installer:
""" This class creates a (graphical) installer from a given .p3d file. """
notify = directNotify.newCategory("Installer")
@ -142,15 +166,17 @@ class Installer:
Call this after you have set the desired parameters. """
platforms = set()
for package in self.host.getPackages(name = "p3dembed"):
for package in self.standalone.host.getPackages(name = "p3dembed"):
platforms.add(package.platform)
if len(platforms) == 0:
Installer.notify.error("No platforms found to build for!")
outputDir = Filename(outputDir)
assert outputDir.isDirectory()
outputDir = Filename(outputDir + "/")
outputDir.makeDir()
for platform in platforms:
self.build(outputDir, platform)
output = Filename(outputDir, platform + "/")
output.makeDir()
self.build(output, platform)
def build(self, output, platform = None):
""" Builds a (graphical) installer and stores it into the path
@ -162,21 +188,24 @@ class Installer:
platform = PandaSystem.getPlatform()
if platform == "win32":
return self.buildNSIS()
return self.buildNSIS(output, platform)
elif "_" in platform:
os, arch = platform.rsplit("_", 1)
os, arch = platform.split("_", 1)
if os == "linux":
return self.buildDEB(output, arch)
return self.buildDEB(output, platform)
elif os == "osx":
return self.buildDMG(output, arch)
return self.buildPKG(output, platform)
elif os == "freebsd":
return self.buildDEB(output, platform)
Installer.notify.info("Ignoring unknown platform " + platform)
def buildDEB(self, output, arch):
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))
@ -194,7 +223,7 @@ class Installer:
controlfile.write("Description: %s\n" % self.fullname)
controlfile.close()
Filename(tempdir, "usr/bin/").makeDir()
self.standalone.build(Filename(tempdir, "usr/bin/" + self.shortname.lower()), "linux_" + arch)
self.standalone.build(Filename(tempdir, "usr/bin/" + self.shortname.lower()), platform)
if not self.licensefile.empty():
Filename(tempdir, "usr/share/doc/%s/" % self.shortname.lower()).makeDir()
shutil.copyfile(self.licensefile.toOsSpecific(), Filename(tempdir, "usr/share/doc/%s/copyright" % self.shortname.lower()).toOsSpecific())
@ -231,33 +260,22 @@ class Installer:
debfile.close()
shutil.rmtree(tempdir.toOsSpecific())
def __buildAPP(self, plugin_standalone):
pkgfn = "%s %s.pkg" % (self.shortname, self.version)
appname = "/Applications/%s.app" % self.longname
Installer.notify.info("Creating %s..." % pkgfn)
def buildAPP(self, output, platform):
# Create a temporary directory to hold the application in
tempdir = Filename.temporary("", self.shortname.lower() + "_app_", "") + "/"
tempdir = tempdir.toOsSpecific()
if os.path.exists(tempdir):
shutil.rmtree(tempdir)
os.makedirs(tempdir)
contents = os.path.join(tempdir, appname.lstrip("/"), "Contents")
os.makedirs(os.path.join(contents, "MacOS"))
os.makedirs(os.path.join(contents, "Resources"))
output = Filename(output)
if output.isDirectory() and output.getExtension() != 'app':
output = Filename(output, "%s.app" % self.fullname)
Installer.notify.info("Creating %s..." % output)
# Create the "launch" script used to run the game.
launch = open(os.path.join(contents, "MacOS", "launch"), "w")
print >>launch, '#!/bin/sh'
print >>launch, 'panda3d_mac ../Resources/%s' % self.p3dfile.getBasename()
launch.close()
shutil.copyfile(self.p3dfile.toOsSpecific(), os.path.join(contents, "Resources", self.p3dfile.getBasename()))
shutil.copyfile(target, os.path.join(contents, "MacOS", "panda3d_mac"))
# Create the executable for the application bundle
exefile = Filename(output, "Contents/MacOS/" + self.shortname)
exefile.makeDir()
self.standalone.build(exefile, platform)
# Create the application plist file.
# Although it might make more sense to use Python's plistlib module here,
# it is not available on non-OSX systems before Python 2.6.
plist = open(os.path.join(tempdir, appname.lstrip("/"), "Contents", "Info.plist"), "w")
plist = open(Filename(output, "Contents/Info.plist").toOsSpecific(), "w")
print >>plist, '<?xml version="1.0" encoding="UTF-8"?>'
print >>plist, '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
print >>plist, '<plist version="1.0">'
@ -267,7 +285,7 @@ class Installer:
print >>plist, '\t<key>CFBundleDisplayName</key>'
print >>plist, '\t<string>%s</string>' % self.fullname
print >>plist, '\t<key>CFBundleExecutable</key>'
print >>plist, '\t<string>launch</string>'
print >>plist, '\t<string>%s</string>' % exefile.getBasename()
print >>plist, '\t<key>CFBundleIdentifier</key>'
print >>plist, '\t<string>%s.%s</string>' % (self.authorid, self.shortname)
print >>plist, '\t<key>CFBundleInfoDictionaryVersion</key>'
@ -290,7 +308,15 @@ class Installer:
print >>plist, '</plist>'
plist.close()
def buildNSIS(self):
def buildPKG(self, output, platform):
output = Filename(output)
#if output.isDirectory():
# output = Filename(output, "%s %s.pkg" % (self.fullname, self.version))
self.buildAPP(output, platform)
return
def buildNSIS(self, output, platform):
# Check if we have makensis first
makensis = None
if (sys.platform.startswith("win")):
@ -308,16 +334,26 @@ class Installer:
makensis = os.path.join(p, "makensis")
if makensis == None:
Installer.notify.warning("Makensis utility not found, no Windows installer will be built!")
Installer.notify.error("Makensis utility not found, no Windows installer will be built!")
return
Installer.notify.info("Creating %s.exe..." % self.shortname)
output = Filename(output)
if output.isDirectory():
output = Filename(output, "%s %s.exe" % (self.fullname, self.version))
Installer.notify.info("Creating %s..." % output)
output.makeAbsolute()
tempfile = self.shortname + ".nsi"
nsi = open(tempfile, "w")
exefile = Filename(Filename.getTempDirectory(), self.shortname + ".exe")
exefile.unlink()
self.standalone.build(exefile, 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.exe"\n' % self.shortname)
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')
@ -329,7 +365,7 @@ class Installer:
nsi.write('RequestExecutionLevel admin\n')
nsi.write('\n')
nsi.write('Function launch\n')
nsi.write(' ExecShell "open" "$INSTDIR\%s.bat"\n' % self.shortname)
nsi.write(' ExecShell "open" "$INSTDIR\%s.exe"\n' % self.shortname)
nsi.write('FunctionEnd\n')
nsi.write('\n')
nsi.write('!include "MUI2.nsh"\n')
@ -353,8 +389,11 @@ class Installer:
nsi.write('!insertmacro MUI_LANGUAGE "English"\n')
# This section defines the installer.
nsi.write('Section "Install"\n')
nsi.write('Section "" SecCore\n')
nsi.write(' SetOutPath "$INSTDIR"\n')
nsi.write(' File "%s"\n' % exefile.toOsSpecific())
for f in self.standalone.getExtraFiles(platform):
nsi.write(' File "%s"\n' % f.toOsSpecific())
nsi.write(' WriteUninstaller "$INSTDIR\Uninstall.exe"\n')
nsi.write(' ; Start menu items\n')
nsi.write(' !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\n')
@ -364,7 +403,10 @@ class Installer:
nsi.write('SectionEnd\n')
# This section defines the uninstaller.
nsi.write('Section "Uninstall"\n')
nsi.write('Section Uninstall\n')
nsi.write(' Delete "$INSTDIR\%s.exe"\n' % self.shortname)
for f in self.standalone.getExtraFiles(platform):
nsi.write(' Delete "%s"\n' % f.getBasename())
nsi.write(' Delete "$INSTDIR\Uninstall.exe"\n')
nsi.write(' RMDir "$INSTDIR"\n')
nsi.write(' ; Start menu items\n')
@ -381,7 +423,7 @@ class Installer:
cmd += " /" + o
else:
cmd += " -" + o
cmd += " " + tempfile
cmd += " " + nsifile.toOsSpecific()
os.system(cmd)
os.remove(tempfile)
nsifile.unlink()

View File

@ -99,7 +99,7 @@ class p3dcert(package):
file('p3dcert.exe')
class p3dembed(solo):
class p3dembed(package):
# This contains the p3dembed executable, that is used by
# pdeploy to generate a self-extracting .p3d executable.

View File

@ -31,7 +31,7 @@ Modes:
Options:
-n your_app
Short, lowercase name of the application or game. Can only
Short, lowercase name of the application or game. May only
contain alphanumeric characters, underscore or dash. This
name will also define the output file(s) of the process.
If omitted, the basename of the p3d file is used.
@ -94,7 +94,7 @@ DEPLOY_MODES = ["standalone", "installer", "html"]
import sys
import os
import getopt
from DeploymentTools import Standalone, Installer
from direct.p3d.DeploymentTools import Standalone, Installer
from pandac.PandaModules import Filename, PandaSystem
def usage(code, msg = ''):
@ -208,10 +208,10 @@ elif deploy_mode == 'installer':
i.buildAll(outputDir)
else:
for platform in platforms:
if platform.startswith("win"):
i.build(Filename(outputDir, platform + "/"), platform)
else:
i.build(Filename(outputDir, platform + "/"), platform)
output = Filename(outputDir, platform + "/")
output.makeDir()
i.build(output, platform)
elif deploy_mode == 'html':
print "Creating %s.html..." % shortname
html = open(shortname + ".html", "w")