blob: 4cea10fc98c70387b1c1f786ec2a25a24139db94 [file] [log] [blame]
Jack Jansen813c9971998-07-31 09:42:35 +00001"""tools for BuildApplet and BuildApplication"""
2
3import sys
4import os
5import string
6import imp
7import marshal
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00008from Carbon import Res
Jack Jansencc947642003-02-02 23:03:50 +00009import Carbon.Files
10import Carbon.File
Jack Jansen813c9971998-07-31 09:42:35 +000011import MacOS
12import macostools
Jack Jansenb2e33fe2002-03-29 21:21:28 +000013import macresource
Jack Jansen813c9971998-07-31 09:42:35 +000014import EasyDialogs
Jack Jansenb2e33fe2002-03-29 21:21:28 +000015import shutil
Jack Jansen813c9971998-07-31 09:42:35 +000016
17
18BuildError = "BuildError"
19
Jack Jansen813c9971998-07-31 09:42:35 +000020# .pyc file (and 'PYC ' resource magic number)
21MAGIC = imp.get_magic()
22
23# Template file (searched on sys.path)
Jack Jansen3b805261999-02-14 23:12:06 +000024TEMPLATE = "PythonInterpreter"
Jack Jansen813c9971998-07-31 09:42:35 +000025
26# Specification of our resource
27RESTYPE = 'PYC '
28RESNAME = '__main__'
29
30# A resource with this name sets the "owner" (creator) of the destination
Jack Jansen81da9f11999-03-17 22:57:55 +000031# It should also have ID=0. Either of these alone is not enough.
Jack Jansen813c9971998-07-31 09:42:35 +000032OWNERNAME = "owner resource"
33
Jack Jansen81da9f11999-03-17 22:57:55 +000034# Default applet creator code
35DEFAULT_APPLET_CREATOR="Pyta"
36
Jack Jansen813c9971998-07-31 09:42:35 +000037# OpenResFile mode parameters
38READ = 1
39WRITE = 2
40
Jack Jansencc947642003-02-02 23:03:50 +000041# Parameter for FSOpenResourceFile
42RESOURCE_FORK_NAME=Carbon.File.FSGetResourceForkName()
Jack Jansen813c9971998-07-31 09:42:35 +000043
Jack Jansena4f8e582001-02-17 23:30:19 +000044def findtemplate(template=None):
Jack Jansen813c9971998-07-31 09:42:35 +000045 """Locate the applet template along sys.path"""
Jack Jansenb2e33fe2002-03-29 21:21:28 +000046 if MacOS.runtimemodel == 'macho':
47 if template:
48 return template
49 return findtemplate_macho()
Jack Jansena4f8e582001-02-17 23:30:19 +000050 if not template:
51 template=TEMPLATE
Jack Jansen813c9971998-07-31 09:42:35 +000052 for p in sys.path:
Jack Jansena4f8e582001-02-17 23:30:19 +000053 file = os.path.join(p, template)
Jack Jansen813c9971998-07-31 09:42:35 +000054 try:
Jack Jansencc947642003-02-02 23:03:50 +000055 file, d1, d2 = Carbon.File.FSResolveAliasFile(file, 1)
Jack Jansen813c9971998-07-31 09:42:35 +000056 break
Jack Jansencc947642003-02-02 23:03:50 +000057 except (Carbon.File.error, ValueError):
Jack Jansen813c9971998-07-31 09:42:35 +000058 continue
59 else:
Jack Jansena4f8e582001-02-17 23:30:19 +000060 raise BuildError, "Template %s not found on sys.path" % `template`
61 file = file.as_pathname()
62 return file
Jack Jansenb2e33fe2002-03-29 21:21:28 +000063
64def findtemplate_macho():
65 execpath = sys.executable.split('/')
66 if not 'Contents' in execpath:
67 raise BuildError, "Not running from a .app bundle: %s" % sys.executable
68 i = execpath.index('Contents')
69 return '/'.join(execpath[:i])
Jack Jansen813c9971998-07-31 09:42:35 +000070
71
Jack Jansen388fbf32002-06-09 22:08:52 +000072def process(template, filename, destname, copy_codefragment,
73 rsrcname=None, others=[], raw=0, progress="default"):
Jack Jansen813c9971998-07-31 09:42:35 +000074
Jack Jansen388fbf32002-06-09 22:08:52 +000075 if progress == "default":
Jack Jansen813c9971998-07-31 09:42:35 +000076 progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120)
77 progress.label("Compiling...")
Jack Jansen388fbf32002-06-09 22:08:52 +000078 progress.inc(0)
Jack Jansen58ba80a2002-08-18 21:57:09 +000079 # check for the script name being longer than 32 chars. This may trigger a bug
80 # on OSX that can destroy your sourcefile.
81 if '#' in os.path.split(filename)[1]:
82 raise BuildError, "BuildApplet could destroy your sourcefile on OSX, please rename: %s" % filename
Jack Jansen813c9971998-07-31 09:42:35 +000083 # Read the source and compile it
84 # (there's no point overwriting the destination if it has a syntax error)
85
Jack Jansen5d099042002-06-20 20:42:07 +000086 fp = open(filename, 'rU')
Jack Jansen813c9971998-07-31 09:42:35 +000087 text = fp.read()
88 fp.close()
89 try:
Just van Rossum4e051d42003-01-09 10:47:20 +000090 code = compile(text + '\n', filename, "exec")
Jack Jansen2eb4b182002-08-02 14:04:15 +000091 except SyntaxError, arg:
92 raise BuildError, "Syntax error in script %s: %s" % (filename, arg)
93 except EOFError:
94 raise BuildError, "End-of-file in script %s" % (filename,)
Jack Jansen813c9971998-07-31 09:42:35 +000095
Jack Jansen388fbf32002-06-09 22:08:52 +000096 # Set the destination file name. Note that basename
97 # does contain the whole filepath, only a .py is stripped.
Jack Jansen813c9971998-07-31 09:42:35 +000098
99 if string.lower(filename[-3:]) == ".py":
Jack Jansen388fbf32002-06-09 22:08:52 +0000100 basename = filename[:-3]
101 if MacOS.runtimemodel != 'macho' and not destname:
102 destname = basename
Jack Jansen813c9971998-07-31 09:42:35 +0000103 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000104 basename = filename
105
106 if not destname:
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000107 if MacOS.runtimemodel == 'macho':
Jack Jansen388fbf32002-06-09 22:08:52 +0000108 destname = basename + '.app'
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000109 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000110 destname = basename + '.applet'
111 if not rsrcname:
112 rsrcname = basename + '.rsrc'
113
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000114 # Try removing the output file. This fails in MachO, but it should
115 # do any harm.
Jack Jansen813c9971998-07-31 09:42:35 +0000116 try:
117 os.remove(destname)
118 except os.error:
119 pass
Jack Jansen388fbf32002-06-09 22:08:52 +0000120 process_common(template, progress, code, rsrcname, destname, 0,
121 copy_codefragment, raw, others)
Jack Jansen813c9971998-07-31 09:42:35 +0000122
123
124def update(template, filename, output):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000125 if MacOS.runtimemodel == 'macho':
126 raise BuildError, "No updating yet for MachO applets"
Jack Jansen388fbf32002-06-09 22:08:52 +0000127 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000128 progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120)
129 else:
130 progress = None
131 if not output:
132 output = filename + ' (updated)'
133
134 # Try removing the output file
135 try:
136 os.remove(output)
137 except os.error:
138 pass
139 process_common(template, progress, None, filename, output, 1, 1)
140
141
Jack Jansen388fbf32002-06-09 22:08:52 +0000142def process_common(template, progress, code, rsrcname, destname, is_update,
143 copy_codefragment, raw=0, others=[]):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000144 if MacOS.runtimemodel == 'macho':
Jack Jansen388fbf32002-06-09 22:08:52 +0000145 return process_common_macho(template, progress, code, rsrcname, destname,
146 is_update, raw, others)
147 if others:
148 raise BuildError, "Extra files only allowed for MachoPython applets"
Jack Jansen813c9971998-07-31 09:42:35 +0000149 # Create FSSpecs for the various files
Jack Jansencc947642003-02-02 23:03:50 +0000150 template_fsr, d1, d2 = Carbon.File.FSResolveAliasFile(template, 1)
151 template = template_fsr.as_pathname()
Jack Jansen813c9971998-07-31 09:42:35 +0000152
153 # Copy data (not resources, yet) from the template
Jack Jansen388fbf32002-06-09 22:08:52 +0000154 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000155 progress.label("Copy data fork...")
156 progress.set(10)
157
158 if copy_codefragment:
159 tmpl = open(template, "rb")
160 dest = open(destname, "wb")
161 data = tmpl.read()
162 if data:
163 dest.write(data)
164 dest.close()
165 tmpl.close()
166 del dest
167 del tmpl
168
169 # Open the output resource fork
170
Jack Jansen388fbf32002-06-09 22:08:52 +0000171 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000172 progress.label("Copy resources...")
173 progress.set(20)
174 try:
Jack Jansencc947642003-02-02 23:03:50 +0000175 output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
Jack Jansen813c9971998-07-31 09:42:35 +0000176 except MacOS.Error:
Jack Jansencc947642003-02-02 23:03:50 +0000177 destdir, destfile = os.path.split(destname)
178 Res.FSCreateResourceFile(destdir, destfile, RESOURCE_FORK_NAME)
179 output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE)
Jack Jansen813c9971998-07-31 09:42:35 +0000180
181 # Copy the resources from the target specific resource template, if any
182 typesfound, ownertype = [], None
183 try:
Jack Jansencc947642003-02-02 23:03:50 +0000184 input = Res.FSOpenResourceFile(rsrcname, RESOURCE_FORK_NAME, READ)
Jack Jansen813c9971998-07-31 09:42:35 +0000185 except (MacOS.Error, ValueError):
186 pass
Jack Jansen388fbf32002-06-09 22:08:52 +0000187 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000188 progress.inc(50)
189 else:
190 if is_update:
191 skip_oldfile = ['cfrg']
192 else:
193 skip_oldfile = []
194 typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress)
195 Res.CloseResFile(input)
196
197 # Check which resource-types we should not copy from the template
Jack Jansen81da9f11999-03-17 22:57:55 +0000198 skiptypes = []
199 if 'vers' in typesfound: skiptypes.append('vers')
Jack Jansen813c9971998-07-31 09:42:35 +0000200 if 'SIZE' in typesfound: skiptypes.append('SIZE')
201 if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4',
202 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
203 if not copy_codefragment:
204 skiptypes.append('cfrg')
Jack Jansen81da9f11999-03-17 22:57:55 +0000205## skipowner = (ownertype <> None)
Jack Jansen813c9971998-07-31 09:42:35 +0000206
207 # Copy the resources from the template
208
Jack Jansencc947642003-02-02 23:03:50 +0000209 input = Res.FSOpenResourceFile(template, RESOURCE_FORK_NAME, READ)
Jack Jansen81da9f11999-03-17 22:57:55 +0000210 dummy, tmplowner = copyres(input, output, skiptypes, 1, progress)
211
Jack Jansen813c9971998-07-31 09:42:35 +0000212 Res.CloseResFile(input)
Jack Jansen81da9f11999-03-17 22:57:55 +0000213## if ownertype == None:
214## raise BuildError, "No owner resource found in either resource file or template"
Jack Jansen813c9971998-07-31 09:42:35 +0000215 # Make sure we're manipulating the output resource file now
216
217 Res.UseResFile(output)
Jack Jansen81da9f11999-03-17 22:57:55 +0000218
219 if ownertype == None:
220 # No owner resource in the template. We have skipped the
221 # Python owner resource, so we have to add our own. The relevant
222 # bundle stuff is already included in the interpret/applet template.
223 newres = Res.Resource('\0')
224 newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource")
225 ownertype = DEFAULT_APPLET_CREATOR
Jack Jansen813c9971998-07-31 09:42:35 +0000226
227 if code:
228 # Delete any existing 'PYC ' resource named __main__
229
230 try:
231 res = Res.Get1NamedResource(RESTYPE, RESNAME)
232 res.RemoveResource()
233 except Res.Error:
234 pass
235
236 # Create the raw data for the resource from the code object
Jack Jansen388fbf32002-06-09 22:08:52 +0000237 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000238 progress.label("Write PYC resource...")
239 progress.set(120)
240
241 data = marshal.dumps(code)
242 del code
243 data = (MAGIC + '\0\0\0\0') + data
244
245 # Create the resource and write it
246
247 id = 0
248 while id < 128:
249 id = Res.Unique1ID(RESTYPE)
250 res = Res.Resource(data)
251 res.AddResource(RESTYPE, id, RESNAME)
Just van Rossum874f87b1999-01-30 22:31:26 +0000252 attrs = res.GetResAttrs()
253 attrs = attrs | 0x04 # set preload
254 res.SetResAttrs(attrs)
Jack Jansen813c9971998-07-31 09:42:35 +0000255 res.WriteResource()
256 res.ReleaseResource()
257
258 # Close the output file
259
260 Res.CloseResFile(output)
261
Jack Jansencc947642003-02-02 23:03:50 +0000262 # Now set the creator, type and bundle bit of the destination.
263 # Done with FSSpec's, FSRef FInfo isn't good enough yet (2.3a1+)
264 dset_fss = Carbon.File.FSSpec(destname)
265 dest_finfo = dest_fss.FSpGetFInfo()
Jack Jansen813c9971998-07-31 09:42:35 +0000266 dest_finfo.Creator = ownertype
267 dest_finfo.Type = 'APPL'
Jack Jansencc947642003-02-02 23:03:50 +0000268 dest_finfo.Flags = dest_finfo.Flags | Carbon.Files.kHasBundle | Carbon.Files.kIsShared
269 dest_finfo.Flags = dest_finfo.Flags & ~Carbon.Files.kHasBeenInited
270 dest_fss.FSpSetFInfo(dest_finfo)
Jack Jansen813c9971998-07-31 09:42:35 +0000271
Jack Jansencc947642003-02-02 23:03:50 +0000272 macostools.touched(destname)
Jack Jansen388fbf32002-06-09 22:08:52 +0000273 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000274 progress.label("Done.")
Jack Jansen388fbf32002-06-09 22:08:52 +0000275 progress.inc(0)
Jack Jansen813c9971998-07-31 09:42:35 +0000276
Jack Jansen388fbf32002-06-09 22:08:52 +0000277def process_common_macho(template, progress, code, rsrcname, destname, is_update, raw=0, others=[]):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000278 # First make sure the name ends in ".app"
279 if destname[-4:] != '.app':
280 destname = destname + '.app'
281 # Now deduce the short name
282 shortname = os.path.split(destname)[1]
283 if shortname[-4:] == '.app':
284 # Strip the .app suffix
285 shortname = shortname[:-4]
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000286 # And deduce the .plist and .icns names
287 plistname = None
288 icnsname = None
289 if rsrcname and rsrcname[-5:] == '.rsrc':
290 tmp = rsrcname[:-5]
291 plistname = tmp + '.plist'
292 if os.path.exists(plistname):
293 icnsname = tmp + '.icns'
294 if not os.path.exists(icnsname):
295 icnsname = None
296 else:
297 plistname = None
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000298 # Start with copying the .app framework
299 if not is_update:
300 exceptlist = ["Contents/Info.plist",
301 "Contents/Resources/English.lproj/InfoPlist.strings",
Jack Jansenafb76322002-08-29 20:20:24 +0000302 "Contents/Resources/English.lproj/Documentation",
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000303 "Contents/Resources/python.rsrc",
304 ]
Jack Jansen388fbf32002-06-09 22:08:52 +0000305 copyapptree(template, destname, exceptlist, progress)
Jack Jansen25e61d92002-11-15 00:05:47 +0000306 # SERIOUS HACK. If we've just copied a symlink as the
307 # executable we assume we're running from the MacPython addon
308 # to 10.2 python. We remove the symlink again and install
309 # the appletrunner script.
310 executable = os.path.join(destname, "Contents/MacOS/python")
311 if os.path.islink(executable):
312 os.remove(executable)
313 dummyfp, appletrunner, d2 = imp.find_module('appletrunner')
314 del dummyfp
315 shutil.copy2(appletrunner, executable)
316 os.chmod(executable, 0775)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000317 # Now either use the .plist file or the default
Jack Jansen388fbf32002-06-09 22:08:52 +0000318 if progress:
319 progress.label('Create info.plist')
320 progress.inc(0)
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000321 if plistname:
Jack Jansen388fbf32002-06-09 22:08:52 +0000322 shutil.copy2(plistname, os.path.join(destname, 'Contents', 'Info.plist'))
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000323 if icnsname:
324 icnsdest = os.path.split(icnsname)[1]
325 icnsdest = os.path.join(destname,
Jack Jansen388fbf32002-06-09 22:08:52 +0000326 os.path.join('Contents', 'Resources', icnsdest))
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000327 shutil.copy2(icnsname, icnsdest)
328 # XXXX Wrong. This should be parsed from plist file. Also a big hack:-)
329 if shortname == 'PythonIDE':
330 ownertype = 'Pide'
331 else:
332 ownertype = 'PytA'
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000333 # XXXX Should copy .icns file
334 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000335 cocoainfo = ''
336 for o in others:
337 if o[-4:] == '.nib':
338 nibname = os.path.split(o)[1][:-4]
339 cocoainfo = """
340 <key>NSMainNibFile</key>
341 <string>%s</string>
342 <key>NSPrincipalClass</key>
343 <string>NSApplication</string>""" % nibname
Jack Jansen94caa782002-08-05 22:06:29 +0000344 elif o[-6:] == '.lproj':
345 files = os.listdir(o)
346 for f in files:
347 if f[-4:] == '.nib':
348 nibname = os.path.split(f)[1][:-4]
349 cocoainfo = """
350 <key>NSMainNibFile</key>
351 <string>%s</string>
352 <key>NSPrincipalClass</key>
353 <string>NSApplication</string>""" % nibname
Jack Jansen388fbf32002-06-09 22:08:52 +0000354
355 plistname = os.path.join(template, 'Contents', 'Resources', 'Applet-Info.plist')
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000356 plistdata = open(plistname).read()
Jack Jansen388fbf32002-06-09 22:08:52 +0000357 plistdata = plistdata % {'appletname':shortname, 'cocoainfo':cocoainfo}
358 ofp = open(os.path.join(destname, 'Contents', 'Info.plist'), 'w')
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000359 ofp.write(plistdata)
360 ofp.close()
361 ownertype = 'PytA'
362 # Create the PkgInfo file
Jack Jansen388fbf32002-06-09 22:08:52 +0000363 if progress:
364 progress.label('Create PkgInfo')
365 progress.inc(0)
366 ofp = open(os.path.join(destname, 'Contents', 'PkgInfo'), 'wb')
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000367 ofp.write('APPL' + ownertype)
368 ofp.close()
369
370
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000371 # Copy the resources from the target specific resource template, if any
372 typesfound, ownertype = [], None
373 try:
374 input = macresource.open_pathname(rsrcname)
375 except (MacOS.Error, ValueError):
Jack Jansen388fbf32002-06-09 22:08:52 +0000376 if progress:
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000377 progress.inc(50)
378 else:
Jack Jansendde800e2002-11-07 23:07:05 +0000379 if progress:
380 progress.label("Copy resources...")
381 progress.set(20)
382 resfilename = 'python.rsrc' # XXXX later: '%s.rsrc' % shortname
383 try:
384 output = Res.FSOpenResourceFile(
385 os.path.join(destname, 'Contents', 'Resources', resfilename),
386 u'', WRITE)
387 except MacOS.Error:
388 fsr, dummy = Res.FSCreateResourceFile(
389 os.path.join(destname, 'Contents', 'Resources'),
390 unicode(resfilename), '')
391 output = Res.FSOpenResourceFile(fsr, u'', WRITE)
392
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000393 typesfound, ownertype = copyres(input, output, [], 0, progress)
394 Res.CloseResFile(input)
Jack Jansendde800e2002-11-07 23:07:05 +0000395 Res.CloseResFile(output)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000396
397 if code:
Jack Jansen388fbf32002-06-09 22:08:52 +0000398 if raw:
399 pycname = '__rawmain__.pyc'
400 else:
401 pycname = '__main__.pyc'
Jack Jansenba1c13d2002-08-02 14:57:43 +0000402 # And we also create __rawmain__.pyc
403 outputfilename = os.path.join(destname, 'Contents', 'Resources', '__rawmain__.pyc')
404 if progress:
405 progress.label('Creating __rawmain__.pyc')
406 progress.inc(0)
Jack Janseneb342292002-11-11 00:06:14 +0000407 rawsourcefp, rawsourcefile, d2 = imp.find_module('appletrawmain')
408 rawsource = rawsourcefp.read()
Jack Jansenba1c13d2002-08-02 14:57:43 +0000409 rawcode = compile(rawsource, rawsourcefile, 'exec')
410 writepycfile(rawcode, outputfilename)
411
Jack Jansen388fbf32002-06-09 22:08:52 +0000412 outputfilename = os.path.join(destname, 'Contents', 'Resources', pycname)
413 if progress:
414 progress.label('Creating '+pycname)
415 progress.inc(0)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000416 writepycfile(code, outputfilename)
Jack Jansen388fbf32002-06-09 22:08:52 +0000417 # Copy other files the user asked for
418 for osrc in others:
419 oname = os.path.split(osrc)[1]
420 odst = os.path.join(destname, 'Contents', 'Resources', oname)
421 if progress:
422 progress.label('Copy ' + oname)
423 progress.inc(0)
424 if os.path.isdir(osrc):
425 copyapptree(osrc, odst)
426 else:
427 shutil.copy2(osrc, odst)
428 if progress:
429 progress.label('Done.')
430 progress.inc(0)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000431
432## macostools.touched(dest_fss)
Jack Jansen813c9971998-07-31 09:42:35 +0000433
434# Copy resources between two resource file descriptors.
Jack Jansen81da9f11999-03-17 22:57:55 +0000435# skip a resource named '__main__' or (if skipowner is set) with ID zero.
Jack Jansen813c9971998-07-31 09:42:35 +0000436# Also skip resources with a type listed in skiptypes.
437#
438def copyres(input, output, skiptypes, skipowner, progress=None):
439 ctor = None
440 alltypes = []
441 Res.UseResFile(input)
442 ntypes = Res.Count1Types()
443 progress_type_inc = 50/ntypes
444 for itype in range(1, 1+ntypes):
445 type = Res.Get1IndType(itype)
446 if type in skiptypes:
447 continue
448 alltypes.append(type)
449 nresources = Res.Count1Resources(type)
450 progress_cur_inc = progress_type_inc/nresources
451 for ires in range(1, 1+nresources):
452 res = Res.Get1IndResource(type, ires)
453 id, type, name = res.GetResInfo()
454 lcname = string.lower(name)
Jack Jansen81da9f11999-03-17 22:57:55 +0000455
456 if lcname == OWNERNAME and id == 0:
Jack Jansen813c9971998-07-31 09:42:35 +0000457 if skipowner:
458 continue # Skip this one
459 else:
460 ctor = type
461 size = res.size
462 attrs = res.GetResAttrs()
Jack Jansen388fbf32002-06-09 22:08:52 +0000463 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000464 progress.label("Copy %s %d %s"%(type, id, name))
465 progress.inc(progress_cur_inc)
466 res.LoadResource()
467 res.DetachResource()
468 Res.UseResFile(output)
469 try:
470 res2 = Res.Get1Resource(type, id)
471 except MacOS.Error:
472 res2 = None
473 if res2:
Jack Jansen388fbf32002-06-09 22:08:52 +0000474 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000475 progress.label("Overwrite %s %d %s"%(type, id, name))
Jack Jansen388fbf32002-06-09 22:08:52 +0000476 progress.inc(0)
Jack Jansen813c9971998-07-31 09:42:35 +0000477 res2.RemoveResource()
478 res.AddResource(type, id, name)
479 res.WriteResource()
480 attrs = attrs | res.GetResAttrs()
481 res.SetResAttrs(attrs)
482 Res.UseResFile(input)
483 return alltypes, ctor
484
Jack Jansen388fbf32002-06-09 22:08:52 +0000485def copyapptree(srctree, dsttree, exceptlist=[], progress=None):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000486 names = []
487 if os.path.exists(dsttree):
488 shutil.rmtree(dsttree)
489 os.mkdir(dsttree)
490 todo = os.listdir(srctree)
491 while todo:
492 this, todo = todo[0], todo[1:]
493 if this in exceptlist:
494 continue
495 thispath = os.path.join(srctree, this)
496 if os.path.isdir(thispath):
497 thiscontent = os.listdir(thispath)
498 for t in thiscontent:
499 todo.append(os.path.join(this, t))
500 names.append(this)
501 for this in names:
502 srcpath = os.path.join(srctree, this)
503 dstpath = os.path.join(dsttree, this)
504 if os.path.isdir(srcpath):
505 os.mkdir(dstpath)
Jack Janseneb342292002-11-11 00:06:14 +0000506 elif os.path.islink(srcpath):
507 endpoint = os.readlink(srcpath)
508 os.symlink(endpoint, dstpath)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000509 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000510 if progress:
511 progress.label('Copy '+this)
512 progress.inc(0)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000513 shutil.copy2(srcpath, dstpath)
514
515def writepycfile(codeobject, cfile):
516 import marshal
517 fc = open(cfile, 'wb')
518 fc.write('\0\0\0\0') # MAGIC placeholder, written later
519 fc.write('\0\0\0\0') # Timestap placeholder, not needed
520 marshal.dump(codeobject, fc)
521 fc.flush()
522 fc.seek(0, 0)
523 fc.write(MAGIC)
524 fc.close()
Jack Jansen813c9971998-07-31 09:42:35 +0000525