blob: 93ef14b4831a887a7cfbc7d7f1fe0172991d93ed [file] [log] [blame]
Jack Jansen65fe8dd2002-11-06 23:15:51 +00001import sys
2import os
3import shutil
4import getopt
5
6def buildappbundle(executable, output=None, copyfunc=None, creator=None,
7 plist=None, nib=None, resources=None):
8 if not output:
9 output = os.path.split(executable)[1] + '.app'
10 if not copyfunc:
11 copyfunc = shutil.copy2
12 if not creator:
13 creator='????'
14 if not resources:
15 resources = []
16 if nib:
17 resources = resources + [nib]
18 #
19 # Create the main directory structure
20 #
21 if not os.path.isdir(output):
22 os.mkdir(output)
23 contents = os.path.join(output, 'Contents')
24 if not os.path.isdir(contents):
25 os.mkdir(contents)
26 macos = os.path.join(contents, 'MacOS')
27 if not os.path.isdir(macos):
28 os.mkdir(macos)
29 #
30 # Create the executable
31 #
32 shortname = os.path.split(executable)[1]
33 execname = os.path.join(macos, shortname)
34 try:
35 os.remove(execname)
36 except OSError:
37 pass
38 copyfunc(executable, execname)
39 #
40 # Create the PkgInfo file
41 #
42 pkginfo = os.path.join(contents, 'PkgInfo')
43 open(pkginfo, 'wb').write('APPL'+creator)
44 if plist:
45 # A plist file is specified. Read it.
46 plistdata = open(plist).read()
47 else:
48 #
49 # If we have a main NIB we create the extra Cocoa specific info for the plist file
50 #
51 if not nib:
52 nibname = ""
53 else:
54 nibname, ext = os.path.splitext(os.path.split(nib)[1])
55 if ext == '.lproj':
56 # Special case: if the main nib is a .lproj we assum a directory
57 # and use the first nib from there
58 files = os.listdir(nib)
59 for f in files:
60 if f[-4:] == '.nib':
61 nibname = os.path.split(f)[1][:-4]
62 break
63 else:
64 nibname = ""
65 if nibname:
66 cocoainfo = """
67 <key>NSMainNibFile</key>
68 <string>%s</string>
69 <key>NSPrincipalClass</key>
70 <string>NSApplication</string>""" % nibname
71 else:
72 cocoainfo = ""
73 plistdata = \
74"""<?xml version="1.0" encoding="UTF-8"?>
75<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
76<plist version="0.9">
77<dict>
78 <key>CFBundleDevelopmentRegion</key>
79 <string>English</string>
80 <key>CFBundleExecutable</key>
81 <string>%s</string>
82 <key>CFBundleInfoDictionaryVersion</key>
83 <string>6.0</string>
84 <key>CFBundlePackageType</key>
85 <string>APPL</string>
86 <key>CFBundleSignature</key>
87 <string>%s</string>
88 <key>CFBundleVersion</key>
89 <string>0.1</string>
90 %s
91</dict>
92</plist>
93""" % (shortname, creator, cocoainfo)
94 #
95 # Next, we create the plist file
96 #
97 infoplist = os.path.join(contents, 'Info.plist')
98 open(infoplist, 'w').write(plistdata)
99 #
100 # Finally, if there are nibs or other resources to copy we do so.
101 #
102 if resources:
103 resdir = os.path.join(contents, 'Resources')
104 for src in resources:
105 dst = os.path.join(resdir, os.path.split(src)[1])
106 if os.path.isdir(src):
107 shutil.copytree(src, dst)
108 else:
109 shutil.copy2(src, dst)
110
111def usage():
112 print "buildappbundle creates an application bundle"
113 print "Usage:"
114 print " buildappbundle [options] executable"
115 print "Options:"
116 print " --output o Output file; default executable with .app appended, short -o"
117 print " --link Symlink the executable (default: copy), short -l"
118 print " --plist file Plist file (default: generate one), short -p"
119 print " --nib file Main nib file or lproj folder for Cocoa program, short -n"
120 print " --resource r Extra resource file to be copied to Resources, short -r"
121 print " --creator c 4-char creator code (default: ????), short -c"
122 print " --help This message, short -?"
123 sys.exit(1)
124
125def main():
126 output=None
127 copyfunc=None
128 creator=None
129 plist=None
130 nib=None
131 resources=[]
132 SHORTOPTS = "o:ln:r:p:c:?"
133 LONGOPTS=("output=", "link", "nib=", "resource=", "plist=", "creator=", "help")
134 try:
135 options, args = getopt.getopt(sys.argv[1:], SHORTOPTS, LONGOPTS)
136 except getopt.error:
137 usage()
138 if len(args) != 1:
139 usage()
140 for opt, arg in options:
141 if opt in ('-o', '--output'):
142 output = arg
143 elif opt in ('-l', '--link'):
144 copyfunc = os.symlink
145 elif opt in ('-n', '--nib'):
146 nib = arg
147 elif opt in ('-r', '--resource'):
148 resources.append(arg)
149 elif opt in ('-c', '--creator'):
150 creator = arg
151 elif opt in ('-p', '--plist'):
152 plist = arg
153 elif opt in ('-?', '--help'):
154 usage()
155 buildappbundle(args[0], output=output, copyfunc=copyfunc, creator=creator,
156 plist=plist, resources=resources)
157
158if __name__ == '__main__':
159 main()
160