blob: 81a086b241445c631ae3ef7d8ab9a4b1a0edc86e [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
8import macfs
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00009from Carbon import Res
Jack Jansen813c9971998-07-31 09:42:35 +000010import MACFS
11import 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
41
Jack Jansena4f8e582001-02-17 23:30:19 +000042def findtemplate(template=None):
Jack Jansen813c9971998-07-31 09:42:35 +000043 """Locate the applet template along sys.path"""
Jack Jansenb2e33fe2002-03-29 21:21:28 +000044 if MacOS.runtimemodel == 'macho':
45 if template:
46 return template
47 return findtemplate_macho()
Jack Jansena4f8e582001-02-17 23:30:19 +000048 if not template:
49 template=TEMPLATE
Jack Jansen813c9971998-07-31 09:42:35 +000050 for p in sys.path:
Jack Jansena4f8e582001-02-17 23:30:19 +000051 file = os.path.join(p, template)
Jack Jansen813c9971998-07-31 09:42:35 +000052 try:
Jack Jansena4f8e582001-02-17 23:30:19 +000053 file, d1, d2 = macfs.ResolveAliasFile(file)
Jack Jansen813c9971998-07-31 09:42:35 +000054 break
55 except (macfs.error, ValueError):
56 continue
57 else:
Jack Jansena4f8e582001-02-17 23:30:19 +000058 raise BuildError, "Template %s not found on sys.path" % `template`
59 file = file.as_pathname()
60 return file
Jack Jansenb2e33fe2002-03-29 21:21:28 +000061
62def findtemplate_macho():
63 execpath = sys.executable.split('/')
64 if not 'Contents' in execpath:
65 raise BuildError, "Not running from a .app bundle: %s" % sys.executable
66 i = execpath.index('Contents')
67 return '/'.join(execpath[:i])
Jack Jansen813c9971998-07-31 09:42:35 +000068
69
Jack Jansen388fbf32002-06-09 22:08:52 +000070def process(template, filename, destname, copy_codefragment,
71 rsrcname=None, others=[], raw=0, progress="default"):
Jack Jansen813c9971998-07-31 09:42:35 +000072
Jack Jansen388fbf32002-06-09 22:08:52 +000073 if progress == "default":
Jack Jansen813c9971998-07-31 09:42:35 +000074 progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120)
75 progress.label("Compiling...")
Jack Jansen388fbf32002-06-09 22:08:52 +000076 progress.inc(0)
Jack Jansen58ba80a2002-08-18 21:57:09 +000077 # check for the script name being longer than 32 chars. This may trigger a bug
78 # on OSX that can destroy your sourcefile.
79 if '#' in os.path.split(filename)[1]:
80 raise BuildError, "BuildApplet could destroy your sourcefile on OSX, please rename: %s" % filename
Jack Jansen813c9971998-07-31 09:42:35 +000081 # Read the source and compile it
82 # (there's no point overwriting the destination if it has a syntax error)
83
Jack Jansen5d099042002-06-20 20:42:07 +000084 fp = open(filename, 'rU')
Jack Jansen813c9971998-07-31 09:42:35 +000085 text = fp.read()
86 fp.close()
87 try:
Just van Rossum4e051d42003-01-09 10:47:20 +000088 code = compile(text + '\n', filename, "exec")
Jack Jansen2eb4b182002-08-02 14:04:15 +000089 except SyntaxError, arg:
90 raise BuildError, "Syntax error in script %s: %s" % (filename, arg)
91 except EOFError:
92 raise BuildError, "End-of-file in script %s" % (filename,)
Jack Jansen813c9971998-07-31 09:42:35 +000093
Jack Jansen388fbf32002-06-09 22:08:52 +000094 # Set the destination file name. Note that basename
95 # does contain the whole filepath, only a .py is stripped.
Jack Jansen813c9971998-07-31 09:42:35 +000096
97 if string.lower(filename[-3:]) == ".py":
Jack Jansen388fbf32002-06-09 22:08:52 +000098 basename = filename[:-3]
99 if MacOS.runtimemodel != 'macho' and not destname:
100 destname = basename
Jack Jansen813c9971998-07-31 09:42:35 +0000101 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000102 basename = filename
103
104 if not destname:
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000105 if MacOS.runtimemodel == 'macho':
Jack Jansen388fbf32002-06-09 22:08:52 +0000106 destname = basename + '.app'
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000107 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000108 destname = basename + '.applet'
109 if not rsrcname:
110 rsrcname = basename + '.rsrc'
111
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000112 # Try removing the output file. This fails in MachO, but it should
113 # do any harm.
Jack Jansen813c9971998-07-31 09:42:35 +0000114 try:
115 os.remove(destname)
116 except os.error:
117 pass
Jack Jansen388fbf32002-06-09 22:08:52 +0000118 process_common(template, progress, code, rsrcname, destname, 0,
119 copy_codefragment, raw, others)
Jack Jansen813c9971998-07-31 09:42:35 +0000120
121
122def update(template, filename, output):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000123 if MacOS.runtimemodel == 'macho':
124 raise BuildError, "No updating yet for MachO applets"
Jack Jansen388fbf32002-06-09 22:08:52 +0000125 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000126 progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120)
127 else:
128 progress = None
129 if not output:
130 output = filename + ' (updated)'
131
132 # Try removing the output file
133 try:
134 os.remove(output)
135 except os.error:
136 pass
137 process_common(template, progress, None, filename, output, 1, 1)
138
139
Jack Jansen388fbf32002-06-09 22:08:52 +0000140def process_common(template, progress, code, rsrcname, destname, is_update,
141 copy_codefragment, raw=0, others=[]):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000142 if MacOS.runtimemodel == 'macho':
Jack Jansen388fbf32002-06-09 22:08:52 +0000143 return process_common_macho(template, progress, code, rsrcname, destname,
144 is_update, raw, others)
145 if others:
146 raise BuildError, "Extra files only allowed for MachoPython applets"
Jack Jansen813c9971998-07-31 09:42:35 +0000147 # Create FSSpecs for the various files
148 template_fss = macfs.FSSpec(template)
149 template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
150 dest_fss = macfs.FSSpec(destname)
151
152 # Copy data (not resources, yet) from the template
Jack Jansen388fbf32002-06-09 22:08:52 +0000153 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000154 progress.label("Copy data fork...")
155 progress.set(10)
156
157 if copy_codefragment:
158 tmpl = open(template, "rb")
159 dest = open(destname, "wb")
160 data = tmpl.read()
161 if data:
162 dest.write(data)
163 dest.close()
164 tmpl.close()
165 del dest
166 del tmpl
167
168 # Open the output resource fork
169
Jack Jansen388fbf32002-06-09 22:08:52 +0000170 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000171 progress.label("Copy resources...")
172 progress.set(20)
173 try:
174 output = Res.FSpOpenResFile(dest_fss, WRITE)
175 except MacOS.Error:
Jack Jansen01a2d9e2001-01-29 15:32:00 +0000176 Res.FSpCreateResFile(destname, '????', 'APPL', MACFS.smAllScripts)
Jack Jansen813c9971998-07-31 09:42:35 +0000177 output = Res.FSpOpenResFile(dest_fss, WRITE)
178
179 # Copy the resources from the target specific resource template, if any
180 typesfound, ownertype = [], None
181 try:
182 input = Res.FSpOpenResFile(rsrcname, READ)
183 except (MacOS.Error, ValueError):
184 pass
Jack Jansen388fbf32002-06-09 22:08:52 +0000185 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000186 progress.inc(50)
187 else:
188 if is_update:
189 skip_oldfile = ['cfrg']
190 else:
191 skip_oldfile = []
192 typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress)
193 Res.CloseResFile(input)
194
195 # Check which resource-types we should not copy from the template
Jack Jansen81da9f11999-03-17 22:57:55 +0000196 skiptypes = []
197 if 'vers' in typesfound: skiptypes.append('vers')
Jack Jansen813c9971998-07-31 09:42:35 +0000198 if 'SIZE' in typesfound: skiptypes.append('SIZE')
199 if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4',
200 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
201 if not copy_codefragment:
202 skiptypes.append('cfrg')
Jack Jansen81da9f11999-03-17 22:57:55 +0000203## skipowner = (ownertype <> None)
Jack Jansen813c9971998-07-31 09:42:35 +0000204
205 # Copy the resources from the template
206
207 input = Res.FSpOpenResFile(template_fss, READ)
Jack Jansen81da9f11999-03-17 22:57:55 +0000208 dummy, tmplowner = copyres(input, output, skiptypes, 1, progress)
209
Jack Jansen813c9971998-07-31 09:42:35 +0000210 Res.CloseResFile(input)
Jack Jansen81da9f11999-03-17 22:57:55 +0000211## if ownertype == None:
212## raise BuildError, "No owner resource found in either resource file or template"
Jack Jansen813c9971998-07-31 09:42:35 +0000213 # Make sure we're manipulating the output resource file now
214
215 Res.UseResFile(output)
Jack Jansen81da9f11999-03-17 22:57:55 +0000216
217 if ownertype == None:
218 # No owner resource in the template. We have skipped the
219 # Python owner resource, so we have to add our own. The relevant
220 # bundle stuff is already included in the interpret/applet template.
221 newres = Res.Resource('\0')
222 newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource")
223 ownertype = DEFAULT_APPLET_CREATOR
Jack Jansen813c9971998-07-31 09:42:35 +0000224
225 if code:
226 # Delete any existing 'PYC ' resource named __main__
227
228 try:
229 res = Res.Get1NamedResource(RESTYPE, RESNAME)
230 res.RemoveResource()
231 except Res.Error:
232 pass
233
234 # Create the raw data for the resource from the code object
Jack Jansen388fbf32002-06-09 22:08:52 +0000235 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000236 progress.label("Write PYC resource...")
237 progress.set(120)
238
239 data = marshal.dumps(code)
240 del code
241 data = (MAGIC + '\0\0\0\0') + data
242
243 # Create the resource and write it
244
245 id = 0
246 while id < 128:
247 id = Res.Unique1ID(RESTYPE)
248 res = Res.Resource(data)
249 res.AddResource(RESTYPE, id, RESNAME)
Just van Rossum874f87b1999-01-30 22:31:26 +0000250 attrs = res.GetResAttrs()
251 attrs = attrs | 0x04 # set preload
252 res.SetResAttrs(attrs)
Jack Jansen813c9971998-07-31 09:42:35 +0000253 res.WriteResource()
254 res.ReleaseResource()
255
256 # Close the output file
257
258 Res.CloseResFile(output)
259
260 # Now set the creator, type and bundle bit of the destination
261 dest_finfo = dest_fss.GetFInfo()
262 dest_finfo.Creator = ownertype
263 dest_finfo.Type = 'APPL'
Jack Jansenb70699b1999-12-03 23:38:05 +0000264 dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle | MACFS.kIsShared
Jack Jansen813c9971998-07-31 09:42:35 +0000265 dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
266 dest_fss.SetFInfo(dest_finfo)
267
268 macostools.touched(dest_fss)
Jack Jansen388fbf32002-06-09 22:08:52 +0000269 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000270 progress.label("Done.")
Jack Jansen388fbf32002-06-09 22:08:52 +0000271 progress.inc(0)
Jack Jansen813c9971998-07-31 09:42:35 +0000272
Jack Jansen388fbf32002-06-09 22:08:52 +0000273def process_common_macho(template, progress, code, rsrcname, destname, is_update, raw=0, others=[]):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000274 # First make sure the name ends in ".app"
275 if destname[-4:] != '.app':
276 destname = destname + '.app'
277 # Now deduce the short name
278 shortname = os.path.split(destname)[1]
279 if shortname[-4:] == '.app':
280 # Strip the .app suffix
281 shortname = shortname[:-4]
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000282 # And deduce the .plist and .icns names
283 plistname = None
284 icnsname = None
285 if rsrcname and rsrcname[-5:] == '.rsrc':
286 tmp = rsrcname[:-5]
287 plistname = tmp + '.plist'
288 if os.path.exists(plistname):
289 icnsname = tmp + '.icns'
290 if not os.path.exists(icnsname):
291 icnsname = None
292 else:
293 plistname = None
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000294 # Start with copying the .app framework
295 if not is_update:
296 exceptlist = ["Contents/Info.plist",
297 "Contents/Resources/English.lproj/InfoPlist.strings",
Jack Jansenafb76322002-08-29 20:20:24 +0000298 "Contents/Resources/English.lproj/Documentation",
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000299 "Contents/Resources/python.rsrc",
300 ]
Jack Jansen388fbf32002-06-09 22:08:52 +0000301 copyapptree(template, destname, exceptlist, progress)
Jack Jansen25e61d92002-11-15 00:05:47 +0000302 # SERIOUS HACK. If we've just copied a symlink as the
303 # executable we assume we're running from the MacPython addon
304 # to 10.2 python. We remove the symlink again and install
305 # the appletrunner script.
306 executable = os.path.join(destname, "Contents/MacOS/python")
307 if os.path.islink(executable):
308 os.remove(executable)
309 dummyfp, appletrunner, d2 = imp.find_module('appletrunner')
310 del dummyfp
311 shutil.copy2(appletrunner, executable)
312 os.chmod(executable, 0775)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000313 # Now either use the .plist file or the default
Jack Jansen388fbf32002-06-09 22:08:52 +0000314 if progress:
315 progress.label('Create info.plist')
316 progress.inc(0)
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000317 if plistname:
Jack Jansen388fbf32002-06-09 22:08:52 +0000318 shutil.copy2(plistname, os.path.join(destname, 'Contents', 'Info.plist'))
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000319 if icnsname:
320 icnsdest = os.path.split(icnsname)[1]
321 icnsdest = os.path.join(destname,
Jack Jansen388fbf32002-06-09 22:08:52 +0000322 os.path.join('Contents', 'Resources', icnsdest))
Jack Jansen9aa8fd02002-03-29 23:44:37 +0000323 shutil.copy2(icnsname, icnsdest)
324 # XXXX Wrong. This should be parsed from plist file. Also a big hack:-)
325 if shortname == 'PythonIDE':
326 ownertype = 'Pide'
327 else:
328 ownertype = 'PytA'
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000329 # XXXX Should copy .icns file
330 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000331 cocoainfo = ''
332 for o in others:
333 if o[-4:] == '.nib':
334 nibname = os.path.split(o)[1][:-4]
335 cocoainfo = """
336 <key>NSMainNibFile</key>
337 <string>%s</string>
338 <key>NSPrincipalClass</key>
339 <string>NSApplication</string>""" % nibname
Jack Jansen94caa782002-08-05 22:06:29 +0000340 elif o[-6:] == '.lproj':
341 files = os.listdir(o)
342 for f in files:
343 if f[-4:] == '.nib':
344 nibname = os.path.split(f)[1][:-4]
345 cocoainfo = """
346 <key>NSMainNibFile</key>
347 <string>%s</string>
348 <key>NSPrincipalClass</key>
349 <string>NSApplication</string>""" % nibname
Jack Jansen388fbf32002-06-09 22:08:52 +0000350
351 plistname = os.path.join(template, 'Contents', 'Resources', 'Applet-Info.plist')
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000352 plistdata = open(plistname).read()
Jack Jansen388fbf32002-06-09 22:08:52 +0000353 plistdata = plistdata % {'appletname':shortname, 'cocoainfo':cocoainfo}
354 ofp = open(os.path.join(destname, 'Contents', 'Info.plist'), 'w')
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000355 ofp.write(plistdata)
356 ofp.close()
357 ownertype = 'PytA'
358 # Create the PkgInfo file
Jack Jansen388fbf32002-06-09 22:08:52 +0000359 if progress:
360 progress.label('Create PkgInfo')
361 progress.inc(0)
362 ofp = open(os.path.join(destname, 'Contents', 'PkgInfo'), 'wb')
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000363 ofp.write('APPL' + ownertype)
364 ofp.close()
365
366
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000367 # Copy the resources from the target specific resource template, if any
368 typesfound, ownertype = [], None
369 try:
370 input = macresource.open_pathname(rsrcname)
371 except (MacOS.Error, ValueError):
Jack Jansen388fbf32002-06-09 22:08:52 +0000372 if progress:
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000373 progress.inc(50)
374 else:
Jack Jansendde800e2002-11-07 23:07:05 +0000375 if progress:
376 progress.label("Copy resources...")
377 progress.set(20)
378 resfilename = 'python.rsrc' # XXXX later: '%s.rsrc' % shortname
379 try:
380 output = Res.FSOpenResourceFile(
381 os.path.join(destname, 'Contents', 'Resources', resfilename),
382 u'', WRITE)
383 except MacOS.Error:
384 fsr, dummy = Res.FSCreateResourceFile(
385 os.path.join(destname, 'Contents', 'Resources'),
386 unicode(resfilename), '')
387 output = Res.FSOpenResourceFile(fsr, u'', WRITE)
388
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000389 typesfound, ownertype = copyres(input, output, [], 0, progress)
390 Res.CloseResFile(input)
Jack Jansendde800e2002-11-07 23:07:05 +0000391 Res.CloseResFile(output)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000392
393 if code:
Jack Jansen388fbf32002-06-09 22:08:52 +0000394 if raw:
395 pycname = '__rawmain__.pyc'
396 else:
397 pycname = '__main__.pyc'
Jack Jansenba1c13d2002-08-02 14:57:43 +0000398 # And we also create __rawmain__.pyc
399 outputfilename = os.path.join(destname, 'Contents', 'Resources', '__rawmain__.pyc')
400 if progress:
401 progress.label('Creating __rawmain__.pyc')
402 progress.inc(0)
Jack Janseneb342292002-11-11 00:06:14 +0000403 rawsourcefp, rawsourcefile, d2 = imp.find_module('appletrawmain')
404 rawsource = rawsourcefp.read()
Jack Jansenba1c13d2002-08-02 14:57:43 +0000405 rawcode = compile(rawsource, rawsourcefile, 'exec')
406 writepycfile(rawcode, outputfilename)
407
Jack Jansen388fbf32002-06-09 22:08:52 +0000408 outputfilename = os.path.join(destname, 'Contents', 'Resources', pycname)
409 if progress:
410 progress.label('Creating '+pycname)
411 progress.inc(0)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000412 writepycfile(code, outputfilename)
Jack Jansen388fbf32002-06-09 22:08:52 +0000413 # Copy other files the user asked for
414 for osrc in others:
415 oname = os.path.split(osrc)[1]
416 odst = os.path.join(destname, 'Contents', 'Resources', oname)
417 if progress:
418 progress.label('Copy ' + oname)
419 progress.inc(0)
420 if os.path.isdir(osrc):
421 copyapptree(osrc, odst)
422 else:
423 shutil.copy2(osrc, odst)
424 if progress:
425 progress.label('Done.')
426 progress.inc(0)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000427
428## macostools.touched(dest_fss)
Jack Jansen813c9971998-07-31 09:42:35 +0000429
430# Copy resources between two resource file descriptors.
Jack Jansen81da9f11999-03-17 22:57:55 +0000431# skip a resource named '__main__' or (if skipowner is set) with ID zero.
Jack Jansen813c9971998-07-31 09:42:35 +0000432# Also skip resources with a type listed in skiptypes.
433#
434def copyres(input, output, skiptypes, skipowner, progress=None):
435 ctor = None
436 alltypes = []
437 Res.UseResFile(input)
438 ntypes = Res.Count1Types()
439 progress_type_inc = 50/ntypes
440 for itype in range(1, 1+ntypes):
441 type = Res.Get1IndType(itype)
442 if type in skiptypes:
443 continue
444 alltypes.append(type)
445 nresources = Res.Count1Resources(type)
446 progress_cur_inc = progress_type_inc/nresources
447 for ires in range(1, 1+nresources):
448 res = Res.Get1IndResource(type, ires)
449 id, type, name = res.GetResInfo()
450 lcname = string.lower(name)
Jack Jansen81da9f11999-03-17 22:57:55 +0000451
452 if lcname == OWNERNAME and id == 0:
Jack Jansen813c9971998-07-31 09:42:35 +0000453 if skipowner:
454 continue # Skip this one
455 else:
456 ctor = type
457 size = res.size
458 attrs = res.GetResAttrs()
Jack Jansen388fbf32002-06-09 22:08:52 +0000459 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000460 progress.label("Copy %s %d %s"%(type, id, name))
461 progress.inc(progress_cur_inc)
462 res.LoadResource()
463 res.DetachResource()
464 Res.UseResFile(output)
465 try:
466 res2 = Res.Get1Resource(type, id)
467 except MacOS.Error:
468 res2 = None
469 if res2:
Jack Jansen388fbf32002-06-09 22:08:52 +0000470 if progress:
Jack Jansen813c9971998-07-31 09:42:35 +0000471 progress.label("Overwrite %s %d %s"%(type, id, name))
Jack Jansen388fbf32002-06-09 22:08:52 +0000472 progress.inc(0)
Jack Jansen813c9971998-07-31 09:42:35 +0000473 res2.RemoveResource()
474 res.AddResource(type, id, name)
475 res.WriteResource()
476 attrs = attrs | res.GetResAttrs()
477 res.SetResAttrs(attrs)
478 Res.UseResFile(input)
479 return alltypes, ctor
480
Jack Jansen388fbf32002-06-09 22:08:52 +0000481def copyapptree(srctree, dsttree, exceptlist=[], progress=None):
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000482 names = []
483 if os.path.exists(dsttree):
484 shutil.rmtree(dsttree)
485 os.mkdir(dsttree)
486 todo = os.listdir(srctree)
487 while todo:
488 this, todo = todo[0], todo[1:]
489 if this in exceptlist:
490 continue
491 thispath = os.path.join(srctree, this)
492 if os.path.isdir(thispath):
493 thiscontent = os.listdir(thispath)
494 for t in thiscontent:
495 todo.append(os.path.join(this, t))
496 names.append(this)
497 for this in names:
498 srcpath = os.path.join(srctree, this)
499 dstpath = os.path.join(dsttree, this)
500 if os.path.isdir(srcpath):
501 os.mkdir(dstpath)
Jack Janseneb342292002-11-11 00:06:14 +0000502 elif os.path.islink(srcpath):
503 endpoint = os.readlink(srcpath)
504 os.symlink(endpoint, dstpath)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000505 else:
Jack Jansen388fbf32002-06-09 22:08:52 +0000506 if progress:
507 progress.label('Copy '+this)
508 progress.inc(0)
Jack Jansenb2e33fe2002-03-29 21:21:28 +0000509 shutil.copy2(srcpath, dstpath)
510
511def writepycfile(codeobject, cfile):
512 import marshal
513 fc = open(cfile, 'wb')
514 fc.write('\0\0\0\0') # MAGIC placeholder, written later
515 fc.write('\0\0\0\0') # Timestap placeholder, not needed
516 marshal.dump(codeobject, fc)
517 fc.flush()
518 fc.seek(0, 0)
519 fc.write(MAGIC)
520 fc.close()
Jack Jansen813c9971998-07-31 09:42:35 +0000521