import sys import os import shutil import getopt def buildappbundle(executable, output=None, copyfunc=None, creator=None, plist=None, nib=None, resources=None): if not output: output = os.path.split(executable)[1] + '.app' if not copyfunc: copyfunc = shutil.copy2 if not creator: creator='????' if not resources: resources = [] if nib: resources = resources + [nib] # # Create the main directory structure # if not os.path.isdir(output): os.mkdir(output) contents = os.path.join(output, 'Contents') if not os.path.isdir(contents): os.mkdir(contents) macos = os.path.join(contents, 'MacOS') if not os.path.isdir(macos): os.mkdir(macos) # # Create the executable # shortname = os.path.split(executable)[1] execname = os.path.join(macos, shortname) try: os.remove(execname) except OSError: pass copyfunc(executable, execname) # # Create the PkgInfo file # pkginfo = os.path.join(contents, 'PkgInfo') open(pkginfo, 'wb').write('APPL'+creator) if plist: # A plist file is specified. Read it. plistdata = open(plist).read() else: # # If we have a main NIB we create the extra Cocoa specific info for the plist file # if not nib: nibname = "" else: nibname, ext = os.path.splitext(os.path.split(nib)[1]) if ext == '.lproj': # Special case: if the main nib is a .lproj we assum a directory # and use the first nib from there files = os.listdir(nib) for f in files: if f[-4:] == '.nib': nibname = os.path.split(f)[1][:-4] break else: nibname = "" if nibname: cocoainfo = """ NSMainNibFile %s NSPrincipalClass NSApplication""" % nibname else: cocoainfo = "" plistdata = \ """ CFBundleDevelopmentRegion English CFBundleExecutable %s CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleSignature %s CFBundleVersion 0.1 %s """ % (shortname, creator, cocoainfo) # # Next, we create the plist file # infoplist = os.path.join(contents, 'Info.plist') open(infoplist, 'w').write(plistdata) # # Finally, if there are nibs or other resources to copy we do so. # if resources: resdir = os.path.join(contents, 'Resources') if not os.path.isdir(resdir): os.mkdir(resdir) for src in resources: dst = os.path.join(resdir, os.path.split(src)[1]) if os.path.isdir(src): shutil.copytree(src, dst) else: shutil.copy2(src, dst) def usage(): print "buildappbundle creates an application bundle" print "Usage:" print " buildappbundle [options] executable" print "Options:" print " --output o Output file; default executable with .app appended, short -o" print " --link Symlink the executable (default: copy), short -l" print " --plist file Plist file (default: generate one), short -p" print " --nib file Main nib file or lproj folder for Cocoa program, short -n" print " --resource r Extra resource file to be copied to Resources, short -r" print " --creator c 4-char creator code (default: ????), short -c" print " --help This message, short -?" sys.exit(1) def main(): output=None copyfunc=None creator=None plist=None nib=None resources=[] SHORTOPTS = "o:ln:r:p:c:?" LONGOPTS=("output=", "link", "nib=", "resource=", "plist=", "creator=", "help") try: options, args = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS) except getopt.error: usage() if len(args) != 1: usage() for opt, arg in options: if opt in ('-o', '--output'): output = arg elif opt in ('-l', '--link'): copyfunc = os.symlink elif opt in ('-n', '--nib'): nib = arg elif opt in ('-r', '--resource'): resources.append(arg) elif opt in ('-c', '--creator'): creator = arg elif opt in ('-p', '--plist'): plist = arg elif opt in ('-?', '--help'): usage() buildappbundle(args[0], output=output, copyfunc=copyfunc, creator=creator, plist=plist, resources=resources) if __name__ == '__main__': main()