diff --git a/direct/src/p3d/InstallerMaker.py b/direct/src/p3d/InstallerMaker.py index bd71f6a9c0..1316064b9d 100644 --- a/direct/src/p3d/InstallerMaker.py +++ b/direct/src/p3d/InstallerMaker.py @@ -19,10 +19,11 @@ class InstallerMaker: self.shortname = shortname self.fullname = fullname self.version = str(version) - # All paths given must be OS-specific! - self.p3dfile = p3dfile self.licensename = "" - self.licensefile = "" + # All paths given must be a Filename instance! + assert isinstance(p3dfile, Filename) + self.p3dfile = p3dfile + self.licensefile = Filename() def build(self): """ Creates the installer. Call this after you have set all the parameters. """ @@ -48,15 +49,16 @@ class InstallerMaker: controlfile.close() os.makedirs(os.path.join(tempdir, "usr", "bin")) os.makedirs(os.path.join(tempdir, "usr", "share", "games", self.shortname)) - if self.licensefile != "": + if not self.licensefile.empty(): os.makedirs(os.path.join(tempdir, "usr", "share", "doc", self.shortname)) 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.write("/usr/bin/env panda3d /usr/share/games/%s/data.p3d\n" % self.shortname) launcherfile.close() - shutil.copyfile(self.p3dfile, os.path.join(tempdir, "usr", "share", "games", self.shortname, "data.p3d")) - if self.licensefile != "": - shutil.copyfile(self.licensefile, os.path.join(tempdir, "usr", "share", "doc", self.shortname, "copyright")) + os.chmod(os.path.join(tempdir, "usr", "bin", self.shortname), 0755) + shutil.copyfile(self.p3dfile.toOsSpecific(), os.path.join(tempdir, "usr", "share", "games", self.shortname, "data.p3d")) + if not self.licensefile.empty(): + shutil.copyfile(self.licensefile.toOsSpecific(), os.path.join(tempdir, "usr", "share", "doc", self.shortname, "copyright")) # Create a control.tar.gz file in memory controltargz = CachedFile() @@ -139,8 +141,8 @@ class InstallerMaker: nsi.write('\n') nsi.write('Var StartMenuFolder\n') nsi.write('!insertmacro MUI_PAGE_WELCOME\n') - if self.licensefile != "": - nsi.write('!insertmacro MUI_PAGE_LICENSE "%s"\n' % self.licensefile) + if not self.licensefile.empty(): + nsi.write('!insertmacro MUI_PAGE_LICENSE "%s"\n' % self.licensefile.toOsSpecific()) nsi.write('!insertmacro MUI_PAGE_DIRECTORY\n') nsi.write('!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder\n') nsi.write('!insertmacro MUI_PAGE_INSTFILES\n') diff --git a/direct/src/p3d/pdeploy.py b/direct/src/p3d/pdeploy.py new file mode 100644 index 0000000000..a25d573a20 --- /dev/null +++ b/direct/src/p3d/pdeploy.py @@ -0,0 +1,138 @@ +#! /usr/bin/env python + +""" + +This command will help you to distribute your Panda game, consisting +of a .p3d file, into an installable package or an HTML webpage. + +Usage: + + %s [opts] app.p3d installer|web + +Modes: + + installer + In this mode, installable packages will be created for as many + platforms as possible. To create Windows installers on + non-Windows platforms, you need to have the "makensis" utility + on your system PATH environment variable. + + web + An HTML webpage will be generated that can be used to view + the provided p3d file in a browser. + +Options: + + -v version_number + This should define the version number of your application + or game. In some deploy modes, this argument is required. + This should only contain alphanumeric characters, dots and + dashes, as the result of the deployment may be in valid + on some platforms otherwise. + + -n your_app + Short, lowercase name of the application or game. Can 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. + + -N "Your Application" + Full name of the application or game. This one will be used + to display to the end-user. + If omitted, the short name is used. + + -l "License Name" + Specifies the name of the software license that the game + or application is licensed under. + + -L licensefile.txt + This should point to a file that contains the full text + describing the software license that the game or application + is licensed under. + +""" + +DEPLOY_MODES = ["installer", "web"] + +import sys +import os +import getopt +from direct.p3d import InstallerMaker +from pandac.PandaModules import Filename + +class ArgumentError(StandardError): + pass + +def deployApp(args): + opts, args = getopt.getopt(args, 'l:L:n:N:v:h') + + version = "" + shortname = "" + fullname = "" + licensename = "" + licensefile = Filename() + + for option, value in opts: + if option == '-v': + version = value.strip() + if option == '-n': + shortname = value.strip() + elif option == '-L': + fullname = value.strip() + if option == '-l': + licensename = value + elif option == '-L': + licensefile = Filename.fromOsSpecific(value) + elif option == '-h': + print __doc__ % (os.path.split(sys.argv[0])[1]) + sys.exit(1) + + if not args or len(args) < 2: + raise ArgumentError, "No target app and/or deploy type specified. Use:\n%s app.p3d %s" % (os.path.split(sys.argv[0])[1], '|'.join(DEPLOY_MODES)) + + if len(args) > 2: + raise ArgumentError, "Too many arguments." + + appFilename = Filename.fromOsSpecific(args[0]) + if appFilename.getExtension().lower() != 'p3d': + raise ArgumentError, 'Application filename must end in ".p3d".' + + deploy_mode = args[1].lower() + if deploy_mode not in DEPLOY_MODES: + raise ArgumentError, 'Invalid deploy type, must be one of "%s".' % '", "'.join(DEPLOY_MODES) + + if shortname.lower() != shortname or ' ' in shortname: + raise ArgumentError, 'Provided short name should be lowercase, and may not contain spaces!' + + if shortname == '': + shortname = appFilename.getBasenameWoExtension() + + if fullname == '': + fullname = shortname + + if version == '' and deploy_mode == 'installer': + raise ArgumentError, 'A version number is required in "installer" mode!' + + try: + if deploy_mode == 'installer': + im = InstallerMaker.InstallerMaker(shortname, fullname, appFilename, version) + im.licensename = licensename + im.licensefile = licensefile + im.build() + elif deploy_mode == 'web': + raise NotImplementedError, 'The "web" mode is yet implemented.' + + except: raise + #except InstallerMaker.InstallerMakerError: + # # Just print the error message and exit gracefully. + # inst = sys.exc_info()[1] + # print inst.args[0] + # sys.exit(1) + +if __name__ == '__main__': + try: + deployApp(sys.argv[1:]) + except ArgumentError, e: + print e.args[0] + sys.exit(1) +