Fix the HTML tarball target to generate the HTML if needed instead of
[python/dscho.git] / Mac / Tools / macfreeze / macgen_bin.py
blobe293b63f892e87e13723f75218d34656a48f642c
1 """macgen_bin - Generate application from shared libraries"""
3 import os
4 import sys
5 import string
6 import types
7 import macfs
8 from MACFS import *
9 import Res
10 import py_resource
11 import cfmfile
12 import buildtools
15 def generate(input, output, module_dict = None, architecture = 'fat', debug=0):
16 # try to remove old file
17 try:
18 os.remove(output)
19 except:
20 pass
22 if module_dict is None:
23 import macmodulefinder
24 print "Searching for modules..."
25 module_dict = macmodulefinder.process(input, [], [], 1)
27 applettemplatepath = buildtools.findtemplate()
28 corepath = findpythoncore()
30 dynamicmodules, dynamicfiles, extraresfiles = findfragments(module_dict, architecture)
32 print "Adding ³__main__²"
33 buildtools.process(applettemplatepath, input, output, 0)
35 outputref = Res.OpenResFile(output)
36 try:
37 Res.UseResFile(outputref)
39 print "Adding Python modules"
40 addpythonmodules(module_dict)
42 print "Adding PythonCore resources"
43 copyres(corepath, outputref, ['cfrg', 'Popt', 'GU…I'], 1)
45 print "Adding resources from shared libraries"
46 for ppcpath, cfm68kpath in extraresfiles:
47 if os.path.exists(ppcpath):
48 copyres(ppcpath, outputref, ['cfrg'], 1)
49 elif os.path.exists(cfm68kpath):
50 copyres(cfm68kpath, outputref, ['cfrg'], 1)
52 print "Fixing sys.path prefs"
53 Res.UseResFile(outputref)
54 try:
55 res = Res.Get1Resource('STR#', 228) # from PythonCore
56 except Res.Error: pass
57 else:
58 res.RemoveResource()
59 # setting pref file name to empty string
60 res = Res.Get1NamedResource('STR ', "PythonPreferenceFileName")
61 res.data = Pstring("")
62 res.ChangedResource()
63 syspathpref = "$(APPLICATION)"
64 res = Res.Resource("\000\001" + Pstring(syspathpref))
65 res.AddResource("STR#", 229, "sys.path preference")
67 print "Creating 'PYD ' resources"
68 for modname, (ppcfrag, cfm68kfrag) in dynamicmodules.items():
69 res = Res.Resource(Pstring(ppcfrag) + Pstring(cfm68kfrag))
70 id = 0
71 while id < 128:
72 id = Res.Unique1ID('PYD ')
73 res.AddResource('PYD ', id, modname)
74 finally:
75 Res.CloseResFile(outputref)
76 print "Merging code fragments"
77 cfmfile.mergecfmfiles([applettemplatepath, corepath] + dynamicfiles.keys(),
78 output, architecture)
80 fss = macfs.FSSpec(output)
81 fss.SetCreatorType('Pyta', 'APPL')
82 print "done!"
85 def findfragments(module_dict, architecture):
86 dynamicmodules = {}
87 dynamicfiles = {}
88 extraresfiles = []
89 for name, module in module_dict.items():
90 if module.gettype() <> 'dynamic':
91 continue
92 path = resolvealiasfile(module.__file__)
93 dir, filename = os.path.split(path)
94 ppcfile, cfm68kfile = makefilenames(filename)
96 # ppc stuff
97 ppcpath = os.path.join(dir, ppcfile)
98 if architecture <> 'm68k':
99 ppcfrag, dynamicfiles = getfragname(ppcpath, dynamicfiles)
100 else:
101 ppcfrag = "_no_fragment_"
103 # 68k stuff
104 cfm68kpath = os.path.join(dir, cfm68kfile)
105 if architecture <> 'pwpc':
106 cfm68kfrag, dynamicfiles = getfragname(cfm68kpath, dynamicfiles)
107 else:
108 cfm68kfrag = "_no_fragment_"
110 dynamicmodules[name] = ppcfrag, cfm68kfrag
111 if (ppcpath, cfm68kpath) not in extraresfiles:
112 extraresfiles.append((ppcpath, cfm68kpath))
113 return dynamicmodules, dynamicfiles, extraresfiles
116 def getfragname(path, dynamicfiles):
117 if not dynamicfiles.has_key(path):
118 if os.path.exists(path):
119 lib = cfmfile.CfrgResource(path)
120 fragname = lib.fragments[0].name
121 else:
122 print "shared lib not found:", path
123 fragname = "_no_fragment_"
124 dynamicfiles[path] = fragname
125 else:
126 fragname = dynamicfiles[path]
127 return fragname, dynamicfiles
130 def addpythonmodules(module_dict):
131 # XXX should really use macgen_rsrc.generate(), this does the same, but skips __main__
132 items = module_dict.items()
133 items.sort()
134 for name, module in items:
135 mtype = module.gettype()
136 if mtype not in ['module', 'package'] or name == "__main__":
137 continue
138 location = module.__file__
140 if location[-4:] == '.pyc':
141 # Attempt corresponding .py
142 location = location[:-1]
143 if location[-3:] != '.py':
144 print '*** skipping', location
145 continue
147 print 'Adding module ³%s²' % name
148 id, name = py_resource.frompyfile(location, name, preload=0,
149 ispackage=mtype=='package')
151 def Pstring(str):
152 if len(str) > 255:
153 raise TypeError, "Str255 must be at most 255 chars long"
154 return chr(len(str)) + str
156 def makefilenames(name):
157 lname = string.lower(name)
158 pos = string.find(lname, ".ppc.")
159 if pos > 0:
160 return name, name[:pos] + '.CFM68K.' + name[pos+5:]
161 pos = string.find(lname, ".cfm68k.")
162 if pos > 0:
163 return name[:pos] + '.ppc.' + name[pos+8:], name
164 raise ValueError, "can't make ppc/cfm68k filenames"
166 def copyres(input, output, *args, **kwargs):
167 openedin = openedout = 0
168 if type(input) == types.StringType:
169 input = Res.OpenResFile(input)
170 openedin = 1
171 if type(output) == types.StringType:
172 output = Res.OpenResFile(output)
173 openedout = 1
174 try:
175 apply(buildtools.copyres, (input, output) + args, kwargs)
176 finally:
177 if openedin:
178 Res.CloseResFile(input)
179 if openedout:
180 Res.CloseResFile(output)
182 def findpythoncore():
183 """find the PythonCore shared library, possibly asking the user if we can't find it"""
185 vRefNum, dirID = macfs.FindFolder(kOnSystemDisk, kExtensionFolderType, 0)
186 extpath = macfs.FSSpec((vRefNum, dirID, "")).as_pathname()
187 version = string.split(sys.version)[0]
188 corepath = os.path.join(extpath, "PythonCore " + version)
189 if not os.path.exists(corepath):
190 fss, ok = macfs.PromptGetFile("Please locate PythonCore:", "shlb")
191 if not ok:
192 raise KeyboardInterrupt, "cancelled"
193 corepath = fss.as_pathname()
194 return resolvealiasfile(corepath)
196 def resolvealiasfile(path):
197 try:
198 fss, dummy1, dummy2 = macfs.ResolveAliasFile(path)
199 except macfs.error:
200 pass
201 else:
202 path = fss.as_pathname()
203 return path