From cafd7c93f93cc0abf6e376c8610f99dc1e373ab0 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Dec 2008 21:30:50 +0000 Subject: [PATCH] Made it work on linux --- direct/src/directscripts/packpanda.py | 213 +++++++++++++++++++------- 1 file changed, 160 insertions(+), 53 deletions(-) diff --git a/direct/src/directscripts/packpanda.py b/direct/src/directscripts/packpanda.py index 8c450d7969..5c384cf259 100755 --- a/direct/src/directscripts/packpanda.py +++ b/direct/src/directscripts/packpanda.py @@ -1,7 +1,8 @@ ############################################################################# # # packpanda - this is a tool that packages up a panda game into a -# convenient, easily-downloaded windows executable. Packpanda relies on +# convenient, easily-downloaded windows executable. Packpanda runs on linux +# and windows - on linux, it builds .debs and .rpms, on windows it relies on # NSIS, the nullsoft scriptable install system, to do the hard work. # # This is intentionally a very simplistic game-packer with very @@ -12,7 +13,7 @@ # ############################################################################## -import sys, os, getopt, string, shutil, py_compile +import sys, os, getopt, string, shutil, py_compile, subprocess OPTIONLIST = [ ("dir", 1, "Name of directory containing game"), @@ -76,12 +77,14 @@ if (PANDA is None): sys.exit("Cannot locate the panda root directory in the python path (cannot locate directory containing direct and pandac).") print "PANDA located at "+PANDA -if (os.path.exists(os.path.join(PANDA,"..","makepanda","makepanda.py"))) and (os.path.exists(os.path.join(PANDA,"..","thirdparty","win-nsis","makensis.exe"))): +if (os.path.exists(os.path.join(PANDA,"..","makepanda","makepanda.py"))) and (sys.platform != "win32" or os.path.exists(os.path.join(PANDA,"..","thirdparty","win-nsis","makensis.exe"))): PSOURCE=os.path.abspath(os.path.join(PANDA,"..")) - NSIS=os.path.abspath(os.path.join(PANDA,"..","thirdparty","win-nsis")) + if (sys.platform == "win32"): + NSIS=os.path.abspath(os.path.join(PANDA,"..","thirdparty","win-nsis")) else: PSOURCE=PANDA - NSIS=os.path.join(PANDA,"nsis") + if (sys.platform == "win32"): + NSIS=os.path.join(PANDA,"nsis") ############################################################################## # @@ -95,21 +98,26 @@ if (DIR==""): print "You must specify the --dir option." ParseFailure() DIR=os.path.abspath(DIR) -NAME=os.path.basename(DIR) +MYDIR=os.path.abspath(os.getcwd()) +BASENAME=os.path.basename(DIR) if (OPTIONS["name"] != ""): NAME=OPTIONS["name"] +else: + NAME=BASENAME SMDIRECTORY=NAME if (VER!=""): SMDIRECTORY=SMDIRECTORY+" "+VER -ICON=os.path.join(DIR, "icon.ico") -BITMAP=os.path.join(DIR, "installer.bmp") +PYTHONV="python"+sys.version[:3] LICENSE=os.path.join(DIR, "license.txt") OUTFILE=os.path.basename(DIR) if (VER!=""): OUTFILE=OUTFILE+"-"+VER -OUTFILE=os.path.abspath(OUTFILE+".exe") -INSTALLDIR='C:\\'+os.path.basename(DIR) -if (VER!=""): INSTALLDIR=INSTALLDIR+"-"+VER -COMPRESS="lzma" -if (OPTIONS["fast"]): COMPRESS="zlib" +if (sys.platform == "win32"): + ICON=os.path.join(DIR, "icon.ico") + BITMAP=os.path.join(DIR, "installer.bmp") + OUTFILE=os.path.abspath(OUTFILE+".exe") + INSTALLDIR='C:\\'+os.path.basename(DIR) + if (VER!=""): INSTALLDIR=INSTALLDIR+"-"+VER + COMPRESS="lzma" + if (OPTIONS["fast"]): COMPRESS="zlib" if (OPTIONS["pyc"]): MAIN="main.pyc" else: MAIN="main.py" @@ -123,11 +131,13 @@ PrintFileStatus("Dir", DIR) print "%-15s: %s"%("Name", NAME) print "%-15s: %s"%("Start Menu", SMDIRECTORY) PrintFileStatus("Main", os.path.join(DIR, MAIN)) -PrintFileStatus("Icon", ICON) -PrintFileStatus("Bitmap", BITMAP) +if (sys.platform == "win32"): + PrintFileStatus("Icon", ICON) + PrintFileStatus("Bitmap", BITMAP) PrintFileStatus("License", LICENSE) print "%-15s: %s"%("Output", OUTFILE) -print "%-15s: %s"%("Install Dir", INSTALLDIR) +if (sys.platform == "win32"): + print "%-15s: %s"%("Install Dir", INSTALLDIR) if (os.path.isdir(DIR)==0): sys.exit("Difficulty reading "+DIR+". Cannot continue.") @@ -138,13 +148,14 @@ if (os.path.isfile(os.path.join(DIR, "main.py"))==0): if (os.path.isfile(LICENSE)==0): LICENSE=os.path.join(PANDA,"LICENSE") -if (os.path.isfile(BITMAP)==0): +if (sys.platform == "win32") and (os.path.isfile(BITMAP)==0): BITMAP=os.path.join(NSIS,"Contrib","Graphics","Wizard","nsis.bmp") -if (os.path.isfile(ICON)==0): - PPICON="bin\\ppython.exe" -else: - PPICON="game\\icon.ico" +if (sys.platform == "win32"): + if (os.path.isfile(ICON)==0): + PPICON="bin\\ppython.exe" + else: + PPICON="game\\icon.ico" ############################################################################## # @@ -156,7 +167,7 @@ def limitedCopyTree(src, dst, rmdir): if (os.path.isdir(src)): if (rmdir.has_key(os.path.basename(src))): return - os.mkdir(dst) + if (not os.path.isdir(dst)): os.mkdir(dst) for x in os.listdir(src): limitedCopyTree(os.path.join(src,x), os.path.join(dst,x), rmdir) else: @@ -164,8 +175,12 @@ def limitedCopyTree(src, dst, rmdir): TMPDIR=os.path.abspath("packpanda-TMP") -TMPGAME=os.path.join(TMPDIR,"game") -TMPETC=os.path.join(TMPDIR,"etc") +if (sys.platform == "win32"): + TMPGAME=os.path.join(TMPDIR,"game") + TMPETC=os.path.join(TMPDIR,"etc") +else: + TMPGAME=os.path.join(TMPDIR,"usr","share","games",BASENAME,"game") + TMPETC=os.path.join(TMPDIR,"usr","share","games",BASENAME,"etc") print "" print "Copying the game to "+TMPDIR+"..." if (os.path.exists(TMPDIR)): @@ -176,12 +191,16 @@ try: rmdir = {} for x in OPTIONS["rmdir"]: rmdir[x] = 1 - limitedCopyTree(DIR, TMPGAME, rmdir) if not os.path.isdir( TMPGAME ): - os.mkdir(TMPGAME) - limitedCopyTree(os.path.join(PANDA, "etc"), TMPETC, {}) + os.makedirs(TMPGAME) + limitedCopyTree(DIR, TMPGAME, rmdir) if not os.path.isdir( TMPETC ): - os.mkdir(TMPETC) + os.makedirs(TMPETC) + if sys.platform == "win32": + limitedCopyTree(os.path.join(PANDA, "etc"), TMPETC, {}) + else: + shutil.copyfile("/etc/Config.prc", os.path.join(TMPETC, "Config.prc")) + shutil.copyfile("/etc/Confauto.prc", os.path.join(TMPETC, "Confauto.prc")) except: sys.exit("Cannot copy game to "+TMPDIR) ############################################################################## @@ -219,14 +238,20 @@ if OPTIONS["bam"]: # ############################################################################## -EGG2BAM=os.path.join(PANDA,"bin","egg2bam.exe") +if (sys.platform == "win32"): + EGG2BAM=os.path.join(PANDA,"bin","egg2bam.exe") +else: + EGG2BAM=os.path.join(PANDA,"bin","egg2bam") def egg2bam(file,bam): present = os.path.exists(bam) if (present): bam = "packpanda-TMP.bam"; cmd = 'egg2bam -noabs -ps rel -pd . "'+file+'" -o "'+bam+'"' print "Executing: "+cmd - res = os.spawnl(os.P_WAIT, EGG2BAM, cmd) + if (sys.platform == "win32"): + res = os.spawnl(os.P_WAIT, EGG2BAM, cmd) + else: + res = os.system(cmd) if (res != 0): sys.exit("Problem in egg file: "+file) if (present) or (OPTIONS["bam"]==0): os.unlink(bam) @@ -283,32 +308,114 @@ DeleteFiles(".") ############################################################################## # -# Run NSIS. Yay! +# Now make the installer. Yay! # ############################################################################## -CMD="\""+NSIS+"\\makensis.exe\" /V2 " -CMD=CMD+'/DCOMPRESSOR="'+COMPRESS+'" ' -CMD=CMD+'/DNAME="'+NAME+'" ' -CMD=CMD+'/DSMDIRECTORY="'+SMDIRECTORY+'" ' -CMD=CMD+'/DINSTALLDIR="'+INSTALLDIR+'" ' -CMD=CMD+'/DOUTFILE="'+OUTFILE+'" ' -CMD=CMD+'/DLICENSE="'+LICENSE+'" ' -CMD=CMD+'/DLANGUAGE="English" ' -CMD=CMD+'/DRUNTEXT="Play '+NAME+'" ' -CMD=CMD+'/DIBITMAP="'+BITMAP+'" ' -CMD=CMD+'/DUBITMAP="'+BITMAP+'" ' -CMD=CMD+'/DPANDA="'+PANDA+'" ' -CMD=CMD+'/DPANDACONF="'+TMPETC+'" ' -CMD=CMD+'/DPSOURCE="'+PSOURCE+'" ' -CMD=CMD+'/DPPGAME="'+TMPGAME+'" ' -CMD=CMD+'/DPPMAIN="'+MAIN+'" ' -CMD=CMD+'/DPPICON="'+PPICON+'" ' -CMD=CMD+'"'+PSOURCE+'\\direct\\src\\directscripts\\packpanda.nsi"' +INSTALLER_DEB_FILE=""" +Package: BASENAME +Version: VERSION +Section: games +Priority: optional +Architecture: ARCH +Essential: no +Depends: PYTHONV +Provides: BASENAME +Description: NAME +Maintainer: Unknown +""" -print "" -print CMD -print "packing..." -os.system(CMD) +INSTALLER_SPEC_FILE=""" +Summary: NAME +Name: BASENAME +Version: VERSION +Release: 1 +Group: Amusement/Games +License: See license file +BuildRoot: TMPDIR +BuildRequires: PYTHONV +%description +NAME +%files +%defattr(-,root,root) +/usr/bin/BASENAME +/usr/lib/games/BASENAME +/usr/share/games/BASENAME +""" +RUN_SCRIPT=""" +#!/bin/sh +cd /usr/share/games/BASENAME/game +PYTHONPATH=/usr/lib/games/BASENAME:/usr/share/games/BASENAME +LD_LIBRARY_PATH=/usr/lib/games/BASENAME +PYTHONV MAIN +""" + +if (sys.platform == "win32"): + CMD="\""+NSIS+"\\makensis.exe\" /V2 " + CMD=CMD+'/DCOMPRESSOR="'+COMPRESS+'" ' + CMD=CMD+'/DNAME="'+NAME+'" ' + CMD=CMD+'/DSMDIRECTORY="'+SMDIRECTORY+'" ' + CMD=CMD+'/DINSTALLDIR="'+INSTALLDIR+'" ' + CMD=CMD+'/DOUTFILE="'+OUTFILE+'" ' + CMD=CMD+'/DLICENSE="'+LICENSE+'" ' + CMD=CMD+'/DLANGUAGE="English" ' + CMD=CMD+'/DRUNTEXT="Play '+NAME+'" ' + CMD=CMD+'/DIBITMAP="'+BITMAP+'" ' + CMD=CMD+'/DUBITMAP="'+BITMAP+'" ' + CMD=CMD+'/DPANDA="'+PANDA+'" ' + CMD=CMD+'/DPANDACONF="'+TMPETC+'" ' + CMD=CMD+'/DPSOURCE="'+PSOURCE+'" ' + CMD=CMD+'/DPPGAME="'+TMPGAME+'" ' + CMD=CMD+'/DPPMAIN="'+MAIN+'" ' + CMD=CMD+'/DPPICON="'+PPICON+'" ' + CMD=CMD+'"'+PSOURCE+'\\direct\\src\\directscripts\\packpanda.nsi"' + + print "" + print CMD + print "packing..." + subprocess.call(CMD) +else: + os.chdir(MYDIR) + os.system("mkdir -p %s/usr/bin" % TMPDIR) + os.system("mkdir -p %s/usr/share/games/%s" % (TMPDIR, BASENAME)) + os.system("mkdir -p %s/usr/lib/games/%s" % (TMPDIR, BASENAME)) + os.system("cp --recursive %s/direct %s/usr/share/games/%s/direct" % (PANDA, TMPDIR, BASENAME)) + os.system("cp --recursive %s/pandac %s/usr/share/games/%s/pandac" % (PANDA, TMPDIR, BASENAME)) + os.system("cp --recursive %s/models %s/usr/share/games/%s/models" % (PANDA, TMPDIR, BASENAME)) + os.system("cp --recursive %s/Pmw %s/usr/share/games/%s/Pmw" % (PANDA, TMPDIR, BASENAME)) + os.system("cp %s %s/usr/share/games/%s/LICENSE" % (LICENSE, TMPDIR, BASENAME)) + os.system("cp --recursive /usr/lib/panda3d/* %s/usr/lib/games/%s/" % (TMPDIR, BASENAME)) + + # Make the script to run the game + txt = RUN_SCRIPT[1:].replace("BASENAME",BASENAME).replace("PYTHONV",PYTHONV).replace("MAIN",MAIN) + WriteFile(TMPDIR+"/usr/bin/"+BASENAME, txt) + os.system("chmod +x "+TMPDIR+"/usr/bin/"+BASENAME) + + if (os.path.exists("/usr/bin/rpmbuild")): + os.system("rm -rf %s/DEBIAN" % TMPDIR) + os.system("rpm -E '%_target_cpu' > packpanda-TMP.txt") + ARCH=ReadFile("packpanda-TMP.txt").strip() + os.remove("packpanda-TMP.txt") + txt = INSTALLER_SPEC_FILE[1:].replace("VERSION",VER).replace("TMPDIR",TMPDIR) + txt = txt.replace("BASENAME",BASENAME).replace("NAME",NAME).replace("PYTHONV",PYTHONV) + WriteFile("packpanda-TMP.spec", txt) + os.system("rpmbuild --define '_rpmdir "+TMPDIR+"' -bb packpanda-TMP.spec") + os.system("mv "+ARCH+"/"+BASENAME+"-"+VER+"-1."+ARCH+".rpm .") + os.rmdir(ARCH) + os.remove("packpanda-TMP.spec") + + if (os.path.exists("/usr/bin/dpkg-deb")): + os.system("dpkg --print-architecture > packpanda-TMP.txt") + ARCH=ReadFile("packpanda-TMP.txt").strip() + os.remove("packpanda-TMP.txt") + txt = INSTALLER_DEB_FILE[1:].replace("VERSION",str(VER)).replace("PYTHONV",PYTHONV) + txt = txt.replace("BASENAME",BASENAME).replace("NAME",NAME).replace("ARCH",ARCH) + os.system("mkdir -p %s/DEBIAN" % TMPDIR) + os.system("cd %s ; (find usr -type f -exec md5sum {} \;) > DEBIAN/md5sums" % TMPDIR) + WriteFile(TMPDIR+"/DEBIAN/control",txt) + os.system("dpkg-deb -b "+TMPDIR+" "+BASENAME+"_"+VER+"_"+ARCH+".deb") + + if not(os.path.exists("/usr/bin/rpmbuild") or os.path.exists("/usr/bin/dpkg-deb")): + exit("To build an installer, either rpmbuild or dpkg-deb must be present on your system!")