1+ #! /usr/bin/env python
2+
3+ # XXX This will be replaced by a main program in Mac/Lib/bundlebuilder.py,
4+ # but for now this is kept so Jack won't need to change his scripts...
5+
6+
7+ """\
8+ buildappbundle creates an application bundle
9+ Usage:
10+ buildappbundle [options] executable
11+ Options:
12+ --output o Output file; default executable with .app appended, short -o
13+ --link Symlink files instead of copying them, short -l
14+ --plist file Plist file (default: generate one), short -p
15+ --nib file Main nib file or lproj folder for Cocoa program, short -n
16+ --resource r Extra resource file to be copied to Resources, short -r
17+ --creator c 4-char creator code (default: '????'), short -c
18+ --verbose increase verbosity level (default: quiet), short -v
19+ --help This message, short -? or -h
20+ """
21+
22+
123import sys
224import os
3- import shutil
425import getopt
26+ from bundlebuilder import AppBuilder
27+ from plistlib import Plist
28+
529
6- def 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- if not os .path .isdir (resdir ):
105- os .mkdir (resdir )
106- for src in resources :
107- dst = os .path .join (resdir , os .path .split (src )[1 ])
108- if os .path .isdir (src ):
109- shutil .copytree (src , dst )
110- else :
111- shutil .copy2 (src , dst )
112-
11330def usage ():
114- print "buildappbundle creates an application bundle"
115- print "Usage:"
116- print " buildappbundle [options] executable"
117- print "Options:"
118- print " --output o Output file; default executable with .app appended, short -o"
119- print " --link Symlink the executable (default: copy), short -l"
120- print " --plist file Plist file (default: generate one), short -p"
121- print " --nib file Main nib file or lproj folder for Cocoa program, short -n"
122- print " --resource r Extra resource file to be copied to Resources, short -r"
123- print " --creator c 4-char creator code (default: ????), short -c"
124- print " --help This message, short -?"
31+ print __doc__
12532 sys .exit (1 )
12633
34+
12735def main ():
128- output = None
129- copyfunc = None
130- creator = None
131- plist = None
132- nib = None
133- resources = []
134- SHORTOPTS = "o:ln:r:p:c:?"
135- LONGOPTS = ("output=" , "link" , "nib=" , "resource=" , "plist=" , "creator=" , "help" )
36+ output = None
37+ symlink = 0
38+ creator = "????"
39+ plist = None
40+ nib = None
41+ resources = []
42+ verbosity = 0
43+ SHORTOPTS = "o:ln:r:p:c:v?h"
44+ LONGOPTS = ("output=" , "link" , "nib=" , "resource=" , "plist=" , "creator=" , "help" ,
45+ "verbose" )
13646 try :
13747 options , args = getopt .getopt (sys .argv [1 :], SHORTOPTS , LONGOPTS )
13848 except getopt .error :
13949 usage ()
14050 if len (args ) != 1 :
14151 usage ()
52+ executable = args [0 ]
14253 for opt , arg in options :
14354 if opt in ('-o' , '--output' ):
14455 output = arg
14556 elif opt in ('-l' , '--link' ):
146- copyfunc = os . symlink
57+ symlink = 1
14758 elif opt in ('-n' , '--nib' ):
14859 nib = arg
14960 elif opt in ('-r' , '--resource' ):
@@ -152,11 +63,42 @@ def main():
15263 creator = arg
15364 elif opt in ('-p' , '--plist' ):
15465 plist = arg
155- elif opt in ('-?' , '--help' ):
66+ elif opt in ('-v' , '--verbose' ):
67+ verbosity += 1
68+ elif opt in ('-?' , '-h' , '--help' ):
15669 usage ()
157- buildappbundle (args [0 ], output = output , copyfunc = copyfunc , creator = creator ,
158- plist = plist , resources = resources )
159-
70+ if output is not None :
71+ builddir , bundlename = os .path .split (output )
72+ else :
73+ builddir = os .curdir
74+ bundlename = None # will be derived from executable
75+ if plist is not None :
76+ plist = Plist .fromFile (plist )
77+
78+ builder = AppBuilder (name = bundlename , executable = executable ,
79+ builddir = builddir , creator = creator , plist = plist , resources = resources ,
80+ symlink = symlink , verbosity = verbosity )
81+
82+ if nib is not None :
83+ resources .append (nib )
84+ nibname , ext = os .path .splitext (os .path .basename (nib ))
85+ if ext == '.lproj' :
86+ # Special case: if the main nib is a .lproj we assum a directory
87+ # and use the first nib from there. XXX Look: an arbitrary pick ;-)
88+ files = os .listdir (nib )
89+ for f in files :
90+ if f [- 4 :] == '.nib' :
91+ nibname = os .path .split (f )[1 ][:- 4 ]
92+ break
93+ else :
94+ nibname = ""
95+ if nibname :
96+ builder .plist .NSMainNibFile = nibname
97+ if not hasattr (builder .plist , "NSPrincipalClass" ):
98+ builder .plist .NSPrincipalClass = "NSApplication"
99+ builder .setup ()
100+ builder .build ()
101+
102+
160103if __name__ == '__main__' :
161104 main ()
162-
0 commit comments