From 899862377c0f1c4629c510a15c2b3355aa1d0320 Mon Sep 17 00:00:00 2001 From: rdb Date: Sat, 5 Sep 2009 16:59:59 +0000 Subject: [PATCH] WIP installer maker - deb already functional, exe in progress --- direct/src/p3d/InstallerMaker.py | 168 +++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 direct/src/p3d/InstallerMaker.py diff --git a/direct/src/p3d/InstallerMaker.py b/direct/src/p3d/InstallerMaker.py new file mode 100644 index 0000000000..30e2b7fa5a --- /dev/null +++ b/direct/src/p3d/InstallerMaker.py @@ -0,0 +1,168 @@ +""" This module is used to build a graphical installer +from a p3d file. It will try to build installers for as +many platforms as possible. """ + +__all__ = ["InstallerMaker"] + +import os, sys, subprocess, tarfile, shutil, time +from direct.directnotify.DirectNotifyGlobal import * +from pandac.PandaModules import Filename + +class CachedFile: + def __init__(self): self.str = "" + def write(self, data): self.str += data + +class InstallerMaker: + notify = directNotify.newCategory("InstallerMaker") + + def __init__(self, shortname, fullname, p3dfile): + self.shortname = shortname + self.fullname = fullname + self.p3dfile = p3dfile + self.__makeNSIS() + self.__makeDEB() + + def __makeDEB(self): + InstallerMaker.notify.info("Creating %s.deb..." % self.shortname) + + # Create a temporary directory and write the control file + launcher to it + tempdir = Filename.temporary("", self.shortname + "_deb_", "") + "/" + tempdir.makeDir() + tempdir = tempdir.toOsSpecific() + controlfile = open(os.path.join(tempdir, "control"), "w") + controlfile.write("Package: %s\n" % self.shortname) + controlfile.write("Version: 1\n") + controlfile.write("Section: games\n") + controlfile.write("Priority: optional\n") + controlfile.write("Architecture: all\n") + controlfile.write("Depends: panda3d-runtime\n") + controlfile.write("Description: %s\n" % self.fullname) + controlfile.close() + os.mkdir(os.path.join(tempdir, "usr")) + os.mkdir(os.path.join(tempdir, "usr", "bin")) + os.mkdir(os.path.join(tempdir, "usr", "share")) + os.mkdir(os.path.join(tempdir, "usr", "share", "games")) + launcherfile = open(os.path.join(tempdir, "usr", "bin", self.shortname), "w") + launcherfile.write("#!/bin/sh\n") + launcherfile.write("/usr/bin/panda3d /usr/share/games/%s/data.p3d\n" % self.shortname) + launcherfile.close() + shutil.copyfile(self.p3dfile, os.path.join(tempdir, "usr", "share", "games", "data.p3d")) + + # Create a control.tar.gz file in memory + controltargz = CachedFile() + controltarfile = tarfile.TarFile.gzopen("control.tar.gz", "w", controltargz) + controltarfile.add(os.path.join(tempdir, "control"), "control") + controltarfile.close() + os.remove(os.path.join(tempdir, "control")) + + # Create the data.tar.gz file in the temporary directory + datatarfile = tarfile.TarFile.gzopen(os.path.join(tempdir, "data.tar.gz"), "w") + datatarfile.add(tempdir + "/usr", "/usr") + datatarfile.close() + + # Open the deb file and write to it. It's actually + # just an AR file, which is very easy to make. + modtime = str(int(time.time())).ljust(11) + debfile = open(self.shortname + ".deb", "wb") + debfile.write("!\x0A") + debfile.write("debian-binary %s 0 0 100644 4 \x60\x0A" % modtime) + debfile.write("2.0\x0A") + debfile.write("control.tar.gz %s 0 0 100644 %s \x60\x0A" % (modtime, str(len(controltargz.str)-1).ljust(9))) + debfile.write(controltargz.str) + debfile.write("data.tar.gz %s 0 0 100644 %s \x60\x0A" % (modtime, str(os.path.getsize(os.path.join(tempdir, "data.tar.gz"))).ljust(9))) + + # Copy everything from data.tar.gz to the deb file megabyte by megabyte. + datatargz = open(os.path.join(tempdir, "data.tar.gz"), "rb") + data = datatargz.read(1024 * 1024) + while data != "": + debfile.write(data) + data = datatargz.read(1024 * 1024) + datatargz.close() + debfile.close() + + def __makeNSIS(self): + # Check if we have makensis first + makensis = None + if (sys.platform.startswith("win")): + for p in os.defpath.split(";") + os.environ["PATH"].split(";"): + if os.path.isfile(os.path.join(p, "makensis.exe")): + makensis = os.path.join(p, "makensis.exe") + 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: + InstallerMaker.notify.warning("Makensis utility not found, no Windows installer will be built!") + return + InstallerMaker.notify.info("Creating %s.exe..." % self.shortname) + + # Some global info + nsi = 'Name "%s"' % self.fullname + nsi += 'OutFile "%s.exe"' % self.shortname + nsi += 'InstallDir "$PROGRAMFILES\%s"' % self.fullname + nsi += 'SetCompress auto' + nsi += 'SetCompressor lzma' + nsi += 'ShowInstDetails nevershow' + nsi += 'ShowUninstDetails nevershow' + nsi += 'InstType "Typical"' + + # Tell Vista that we require admin rights + nsi += 'RequestExecutionLevel admin' + nsi += '' + nsi += 'Function launch' + nsi += ' ExecShell "open" "$INSTDIR\%s.bat"' % self.shortname + nsi += 'FunctionEnd' + nsi += '' + nsi += '!include "MUI2.nsh"' + nsi += '!define MUI_HEADERIMAGE' + nsi += '!define MUI_HEADERIMAGE_BITMAP "/home/pro-rsoft/Projects/vikings-old/Vikings/installer.bmp"' + nsi += '!define MUI_HEADERIMAGE_UNBITMAP "/home/pro-rsoft/Projects/vikings-old/Vikings/installer.bmp"' + nsi += '!define MUI_WELCOMEFINISHPAGE_BITMAP "/home/pro-rsoft/Projects/vikings-old/Vikings/installer.bmp"' + nsi += '!define MUI_UNWELCOMEFINISHPAGE_BITMAP "/home/pro-rsoft/Projects/vikings-old/Vikings/installer.bmp"' + nsi += '!define MUI_ABORTWARNING' + nsi += '!define MUI_FINISHPAGE_RUN' + nsi += '!define MUI_FINISHPAGE_RUN_FUNCTION launch' + nsi += '!define MUI_FINISHPAGE_RUN_TEXT "Play %s"' % self.fullname + nsi += '' + nsi += 'Var StartMenuFolder' + nsi += '!insertmacro MUI_PAGE_WELCOME' + nsi += ';!insertmacro MUI_PAGE_LICENSE "weirdo.egg"' + nsi += '!insertmacro MUI_PAGE_DIRECTORY' + nsi += '!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder' + nsi += '!insertmacro MUI_PAGE_INSTFILES' + nsi += '!insertmacro MUI_PAGE_FINISH' + nsi += '!insertmacro MUI_UNPAGE_WELCOME' + nsi += '!insertmacro MUI_UNPAGE_CONFIRM' + nsi += '!insertmacro MUI_UNPAGE_INSTFILES' + nsi += '!insertmacro MUI_UNPAGE_FINISH' + nsi += '!insertmacro MUI_LANGUAGE "English"' + + # This section defines the installer. + nsi += 'Section "Install"' + nsi += ' SetOutPath "$INSTDIR"' + nsi += ' WriteUninstaller "$INSTDIR\Uninstall.exe"' + nsi += ' ; Start menu items' + nsi += ' !insertmacro MUI_STARTMENU_WRITE_BEGIN Application' + nsi += ' CreateDirectory "$SMPROGRAMS\$StartMenuFolder"' + nsi += ' CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk" "$INSTDIR\Uninstall.exe"' + nsi += ' !insertmacro MUI_STARTMENU_WRITE_END' + nsi += 'SectionEnd' + + # This section defines the uninstaller. + nsi += 'Section "Uninstall"' + nsi += ' Delete "$INSTDIR\Uninstall.exe"' + nsi += ' RMDir "$INSTDIR"' + nsi += ' ; Start menu items' + nsi += ' !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder' + nsi += ' Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall.lnk"' + nsi += ' RMDir "$SMPROGRAMS\$StartMenuFolder"' + nsi += 'SectionEnd' + + subprocess.call(makensis) +