[Python-checkins] python/dist/src/Mac/Lib bundlebuilder.py,1.1,1.2
jvr@users.sourceforge.net
jvr@users.sourceforge.net
Thu, 21 Nov 2002 15:19:39 -0800
Update of /cvsroot/python/python/dist/src/Mac/Lib
In directory sc8-pr-cvs1:/tmp/cvs-serv7855
Modified Files:
bundlebuilder.py
Log Message:
added command line interface; refactored a bit; little things.
Index: bundlebuilder.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Mac/Lib/bundlebuilder.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** bundlebuilder.py 21 Nov 2002 10:23:04 -0000 1.1
--- bundlebuilder.py 21 Nov 2002 23:19:37 -0000 1.2
***************
*** 4,16 ****
bundlebuilder.py -- Tools to assemble MacOS X (application) bundles.
! This module contains three classes to build so called "bundles" for
MacOS X. BundleBuilder is a general tool, AppBuilder is a subclass
! specialized in building application bundles. CocoaAppBuilder is a
! further specialization of AppBuilder.
! [Bundle|App|CocoaApp]Builder objects are instantiated with a bunch
! of keyword arguments, and have a build() method that will do all the
! work. See the class doc strings for a description of the constructor
! arguments.
"""
--- 4,25 ----
bundlebuilder.py -- Tools to assemble MacOS X (application) bundles.
! This module contains two classes to build so called "bundles" for
MacOS X. BundleBuilder is a general tool, AppBuilder is a subclass
! specialized in building application bundles.
! [Bundle|App]Builder objects are instantiated with a bunch of keyword
! arguments, and have a build() method that will do all the work. See
! the class doc strings for a description of the constructor arguments.
!
! The module contains a main program that can be used in two ways:
!
! % python bundlebuilder.py [options] build
! % python buildapp.py [options] build
!
! Where "buildapp.py" is a user-supplied setup.py-like script following
! this model:
!
! from bundlebuilder import buildapp
! buildapp(<lots-of-keyword-args>)
"""
***************
*** 18,32 ****
#
# XXX Todo:
- # - a command line interface, also for use with the buildapp() and
- # buildcocoaapp() convenience functions.
# - modulefinder support to build standalone apps
#
! __all__ = ["BundleBuilder", "AppBuilder", "CocoaAppBuilder",
! "buildapp", "buildcocoaapp"]
import sys
import os, errno, shutil
from plistlib import Plist
--- 27,40 ----
#
# XXX Todo:
# - modulefinder support to build standalone apps
+ # - consider turning this into a distutils extension
#
! __all__ = ["BundleBuilder", "AppBuilder", "buildapp"]
import sys
import os, errno, shutil
+ import getopt
from plistlib import Plist
***************
*** 63,83 ****
"""
! def __init__(self, name, plist=None, type="APPL", creator="????",
resources=None, files=None, builddir="build", platform="MacOS",
symlink=0, verbosity=1):
"""See the class doc string for a description of the arguments."""
- self.name, ext = os.path.splitext(name)
- if not ext:
- ext = ".bundle"
- self.bundleextension = ext
if plist is None:
plist = Plist()
self.plist = plist
self.type = type
self.creator = creator
- if files is None:
- files = []
- if resources is None:
- resources = []
self.resources = resources
self.files = files
--- 71,88 ----
"""
! def __init__(self, name=None, plist=None, type="APPL", creator="????",
resources=None, files=None, builddir="build", platform="MacOS",
symlink=0, verbosity=1):
"""See the class doc string for a description of the arguments."""
if plist is None:
plist = Plist()
+ if resources is None:
+ resources = []
+ if files is None:
+ files = []
+ self.name = name
self.plist = plist
self.type = type
self.creator = creator
self.resources = resources
self.files = files
***************
*** 85,94 ****
self.platform = platform
self.symlink = symlink
- # misc (derived) attributes
- self.bundlepath = pathjoin(builddir, self.name + self.bundleextension)
- self.execdir = pathjoin("Contents", platform)
- self.resdir = pathjoin("Contents", "Resources")
self.verbosity = verbosity
def build(self):
"""Build the bundle."""
--- 90,111 ----
self.platform = platform
self.symlink = symlink
self.verbosity = verbosity
+ def setup(self):
+ self.name, ext = os.path.splitext(self.name)
+ if not ext:
+ ext = ".bundle"
+ self.bundleextension = ext
+ # misc (derived) attributes
+ self.bundlepath = pathjoin(self.builddir, self.name + self.bundleextension)
+ self.execdir = pathjoin("Contents", self.platform)
+
+ plist = plistDefaults.copy()
+ plist.CFBundleName = self.name
+ plist.CFBundlePackageType = self.type
+ plist.CFBundleSignature = self.creator
+ plist.update(self.plist)
+ self.plist = plist
+
def build(self):
"""Build the bundle."""
***************
*** 125,135 ****
#
# Write Contents/Info.plist
- plist = plistDefaults.copy()
- plist.CFBundleName = self.name
- plist.CFBundlePackageType = self.type
- plist.CFBundleSignature = self.creator
- plist.update(self.plist)
infoplist = pathjoin(contents, "Info.plist")
! plist.write(infoplist)
def _copyFiles(self):
--- 142,147 ----
#
# Write Contents/Info.plist
infoplist = pathjoin(contents, "Info.plist")
! self.plist.write(infoplist)
def _copyFiles(self):
***************
*** 145,149 ****
msg = "Copying"
for src, dst in files:
! self.message("%s %s to %s" % (msg, src, dst), 2)
dst = pathjoin(self.bundlepath, dst)
if self.symlink:
--- 157,164 ----
msg = "Copying"
for src, dst in files:
! if os.path.isdir(src):
! self.message("%s %s/ to %s/" % (msg, src, dst), 2)
! else:
! self.message("%s %s to %s" % (msg, src, dst), 2)
dst = pathjoin(self.bundlepath, dst)
if self.symlink:
***************
*** 154,158 ****
def message(self, msg, level=0):
if level <= self.verbosity:
! sys.stderr.write(msg + "\n")
--- 169,181 ----
def message(self, msg, level=0):
if level <= self.verbosity:
! indent = ""
! if level > 1:
! indent = (level - 1) * " "
! sys.stderr.write(indent + msg + "\n")
!
! def report(self):
! # XXX something decent
! import pprint
! pprint.pprint(self.__dict__)
***************
*** 167,176 ****
assert os.path.exists(mainprogram)
argv.insert(1, mainprogram)
! %(executable)s
os.execve(executable, argv, os.environ)
"""
! executableTemplate = "executable = os.path.join(resources, \"%s\")"
!
class AppBuilder(BundleBuilder):
--- 190,201 ----
assert os.path.exists(mainprogram)
argv.insert(1, mainprogram)
! os.environ["PYTHONPATH"] = resources
! %(setpythonhome)s
! %(setexecutable)s
os.execve(executable, argv, os.environ)
"""
! setExecutableTemplate = """executable = os.path.join(resources, "%s")"""
! pythonhomeSnippet = """os.environ["home"] = resources"""
class AppBuilder(BundleBuilder):
***************
*** 178,182 ****
"""This class extends the BundleBuilder constructor with these
arguments:
!
mainprogram: A Python main program. If this argument is given,
the main executable in the bundle will be a small wrapper
--- 203,207 ----
"""This class extends the BundleBuilder constructor with these
arguments:
!
mainprogram: A Python main program. If this argument is given,
the main executable in the bundle will be a small wrapper
***************
*** 186,229 ****
be invoked by the wrapper program mentioned above. Else
it will simply be used as the main executable.
!
For the other keyword arguments see the BundleBuilder doc string.
"""
def __init__(self, name=None, mainprogram=None, executable=None,
! **kwargs):
"""See the class doc string for a description of the arguments."""
! if mainprogram is None and executable is None:
raise TypeError, ("must specify either or both of "
"'executable' and 'mainprogram'")
! if name is not None:
pass
! elif mainprogram is not None:
! name = os.path.splitext(os.path.basename(mainprogram))[0]
elif executable is not None:
! name = os.path.splitext(os.path.basename(executable))[0]
! if name[-4:] != ".app":
! name += ".app"
! self.mainprogram = mainprogram
! self.executable = executable
! BundleBuilder.__init__(self, name=name, **kwargs)
def preProcess(self):
! self.plist.CFBundleExecutable = self.name
if self.executable is not None:
if self.mainprogram is None:
execpath = pathjoin(self.execdir, self.name)
else:
! execpath = pathjoin(self.resdir, os.path.basename(self.executable))
self.files.append((self.executable, execpath))
# For execve wrapper
! executable = executableTemplate % os.path.basename(self.executable)
else:
! executable = "" # XXX for locals() call
if self.mainprogram is not None:
mainname = os.path.basename(self.mainprogram)
! self.files.append((self.mainprogram, pathjoin(self.resdir, mainname)))
# Create execve wrapper
mainprogram = self.mainprogram # XXX for locals() call
--- 211,267 ----
be invoked by the wrapper program mentioned above. Else
it will simply be used as the main executable.
! nibname: The name of the main nib, for Cocoa apps. Defaults
! to None, but must be specified when building a Cocoa app.
!
For the other keyword arguments see the BundleBuilder doc string.
"""
def __init__(self, name=None, mainprogram=None, executable=None,
! nibname=None, **kwargs):
"""See the class doc string for a description of the arguments."""
! self.mainprogram = mainprogram
! self.executable = executable
! self.nibname = nibname
! BundleBuilder.__init__(self, name=name, **kwargs)
!
! def setup(self):
! if self.mainprogram is None and self.executable is None:
raise TypeError, ("must specify either or both of "
"'executable' and 'mainprogram'")
!
! if self.name is not None:
pass
! elif self.mainprogram is not None:
! self.name = os.path.splitext(os.path.basename(self.mainprogram))[0]
elif executable is not None:
! self.name = os.path.splitext(os.path.basename(self.executable))[0]
! if self.name[-4:] != ".app":
! self.name += ".app"
! self.plist.CFBundleExecutable = self.name
! if self.nibname:
! self.plist.NSMainNibFile = self.nibname
! if not hasattr(self.plist, "NSPrincipalClass"):
! self.plist.NSPrincipalClass = "NSApplication"
! BundleBuilder.setup(self)
def preProcess(self):
! resdir = pathjoin("Contents", "Resources")
if self.executable is not None:
if self.mainprogram is None:
execpath = pathjoin(self.execdir, self.name)
else:
! execpath = pathjoin(resdir, os.path.basename(self.executable))
self.files.append((self.executable, execpath))
# For execve wrapper
! setexecutable = setExecutableTemplate % os.path.basename(self.executable)
else:
! setexecutable = "" # XXX for locals() call
if self.mainprogram is not None:
+ setpythonhome = "" # pythonhomeSnippet if we're making a standalone app
mainname = os.path.basename(self.mainprogram)
! self.files.append((self.mainprogram, pathjoin(resdir, mainname)))
# Create execve wrapper
mainprogram = self.mainprogram # XXX for locals() call
***************
*** 235,254 ****
- class CocoaAppBuilder(AppBuilder):
-
- """Tiny specialization of AppBuilder. It has an extra constructor
- argument called 'nibname' which defaults to 'MainMenu'. It will
- set the appropriate fields in the plist.
- """
-
- def __init__(self, nibname="MainMenu", **kwargs):
- """See the class doc string for a description of the arguments."""
- self.nibname = nibname
- AppBuilder.__init__(self, **kwargs)
- self.plist.NSMainNibFile = self.nibname
- if not hasattr(self.plist, "NSPrincipalClass"):
- self.plist.NSPrincipalClass = "NSApplication"
-
-
def copy(src, dst, mkdirs=0):
"""Copy a file or a directory."""
--- 273,276 ----
***************
*** 288,307 ****
! def buildapp(**kwargs):
! # XXX cmd line argument parsing
! builder = AppBuilder(**kwargs)
! builder.build()
! def buildcocoaapp(**kwargs):
! # XXX cmd line argument parsing
! builder = CocoaAppBuilder(**kwargs)
! builder.build()
if __name__ == "__main__":
! # XXX This test is meant to be run in the Examples/TableModel/ folder
! # of the pyobj project... It will go as soon as I've written a proper
! # main program.
! buildcocoaapp(mainprogram="TableModel.py",
! resources=["English.lproj", "nibwrapper.py"], verbosity=4)
--- 310,404 ----
! cmdline_doc = """\
! Usage:
! python [options] command
! python mybuildscript.py [options] command
+ Commands:
+ build build the application
+ report print a report
! Options:
! -b, --builddir=DIR the build directory; defaults to "build"
! -n, --name=NAME application name
! -r, --resource=FILE extra file or folder to be copied to Resources
! -e, --executable=FILE the executable to be used
! -m, --mainprogram=FILE the Python main program
! -p, --plist=FILE .plist file (default: generate one)
! --nib=NAME main nib name
! -c, --creator=CCCC 4-char creator code (default: '????')
! -l, --link symlink files/folder instead of copying them
! -v, --verbose increase verbosity level
! -q, --quiet decrease verbosity level
! -h, --help print this message
! """
!
! def usage(msg=None):
! if msg:
! print msg
! print cmdline_doc
! sys.exit(1)
!
! def main(builder=None):
! if builder is None:
! builder = AppBuilder(verbosity=1)
!
! shortopts = "b:n:r:e:m:c:plhvq"
! longopts = ("builddir=", "name=", "resource=", "executable=",
! "mainprogram=", "creator=", "nib=", "plist=", "link", "help",
! "verbose", "quiet")
!
! try:
! options, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
! except getopt.error:
! usage()
!
! for opt, arg in options:
! if opt in ('-b', '--builddir'):
! builder.builddir = arg
! elif opt in ('-n', '--name'):
! builder.name = arg
! elif opt in ('-r', '--resource'):
! builder.resources.append(arg)
! elif opt in ('-e', '--executable'):
! builder.executable = arg
! elif opt in ('-m', '--mainprogram'):
! builder.mainprogram = arg
! elif opt in ('-c', '--creator'):
! builder.creator = arg
! elif opt == "--nib":
! builder.nibname = arg
! elif opt in ('-p', '--plist'):
! builder.plist = Plist.fromFile(arg)
! elif opt in ('-l', '--link'):
! builder.symlink = 1
! elif opt in ('-h', '--help'):
! usage()
! elif opt in ('-v', '--verbose'):
! builder.verbosity += 1
! elif opt in ('-q', '--quiet'):
! builder.verbosity -= 1
!
! if len(args) != 1:
! usage("Must specify one command ('build', 'report' or 'help')")
! command = args[0]
!
! if command == "build":
! builder.setup()
! builder.build()
! elif command == "report":
! builder.setup()
! builder.report()
! elif command == "help":
! usage()
! else:
! usage("Unknown command '%s'" % command)
!
!
! def buildapp(**kwargs):
! builder = AppBuilder(**kwargs)
! main(builder)
if __name__ == "__main__":
! main()