1813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen"""tools for BuildApplet and BuildApplication""" 2813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 3236819310db3fe6f2fb22d48b780fa6ec253b6c7Benjamin Petersonimport warnings 4a6864e0d9f1fc06c50db36ed913ac48a3d2ddde5Benjamin Petersonwarnings.warnpy3k("the buildtools module is deprecated and is removed in 3.0", 5a6864e0d9f1fc06c50db36ed913ac48a3d2ddde5Benjamin Peterson stacklevel=2) 6236819310db3fe6f2fb22d48b780fa6ec253b6c7Benjamin Peterson 7813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansenimport sys 8813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansenimport os 9813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansenimport string 10813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansenimport imp 11813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansenimport marshal 125a6fdcd3718927109592c6df692fe24a8fdaee31Jack Jansenfrom Carbon import Res 13cc94764c67f6fbb73caecec5afabef7327b15ac7Jack Jansenimport Carbon.Files 14cc94764c67f6fbb73caecec5afabef7327b15ac7Jack Jansenimport Carbon.File 15813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansenimport MacOS 16813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansenimport macostools 17b2e33fe285a1f998f477202e9379a39488ea518bJack Jansenimport macresource 182596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussorentry: 192596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren import EasyDialogs 202596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussorenexcept ImportError: 212596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren EasyDialogs = None 22b2e33fe285a1f998f477202e9379a39488ea518bJack Jansenimport shutil 23813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 24813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 25813c997b7663aaad296f6f221d2395b3fee4b422Jack JansenBuildError = "BuildError" 26813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 27813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# .pyc file (and 'PYC ' resource magic number) 28813c997b7663aaad296f6f221d2395b3fee4b422Jack JansenMAGIC = imp.get_magic() 29813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 30813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# Template file (searched on sys.path) 313b8052685c87e6564a3a4c37954ac2d96fcd6478Jack JansenTEMPLATE = "PythonInterpreter" 32813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 33813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# Specification of our resource 34813c997b7663aaad296f6f221d2395b3fee4b422Jack JansenRESTYPE = 'PYC ' 35813c997b7663aaad296f6f221d2395b3fee4b422Jack JansenRESNAME = '__main__' 36813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 37813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# A resource with this name sets the "owner" (creator) of the destination 3881da9f146c2223bc486197c2df03feda5126dcd5Jack Jansen# It should also have ID=0. Either of these alone is not enough. 39813c997b7663aaad296f6f221d2395b3fee4b422Jack JansenOWNERNAME = "owner resource" 40813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 4181da9f146c2223bc486197c2df03feda5126dcd5Jack Jansen# Default applet creator code 4281da9f146c2223bc486197c2df03feda5126dcd5Jack JansenDEFAULT_APPLET_CREATOR="Pyta" 4381da9f146c2223bc486197c2df03feda5126dcd5Jack Jansen 44813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# OpenResFile mode parameters 45813c997b7663aaad296f6f221d2395b3fee4b422Jack JansenREAD = 1 46813c997b7663aaad296f6f221d2395b3fee4b422Jack JansenWRITE = 2 47813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 48cc94764c67f6fbb73caecec5afabef7327b15ac7Jack Jansen# Parameter for FSOpenResourceFile 49cc94764c67f6fbb73caecec5afabef7327b15ac7Jack JansenRESOURCE_FORK_NAME=Carbon.File.FSGetResourceForkName() 50813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 51a4f8e580588b7ebd5fde61debab3fdb72f37cdecJack Jansendef findtemplate(template=None): 520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen """Locate the applet template along sys.path""" 530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if MacOS.runtimemodel == 'macho': 540ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen return None 550ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not template: 560ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen template=TEMPLATE 570ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen for p in sys.path: 580ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen file = os.path.join(p, template) 590ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 600ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen file, d1, d2 = Carbon.File.FSResolveAliasFile(file, 1) 610ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen break 620ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except (Carbon.File.Error, ValueError): 630ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen continue 640ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 6570a6b49821a3226f55e9716f32d802d06640cb89Walter Dörwald raise BuildError, "Template %r not found on sys.path" % (template,) 660ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen file = file.as_pathname() 670ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen return file 68182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 69182b5aca27d376b08a2904bed42b751496f932f3Tim Petersdef process(template, filename, destname, copy_codefragment=0, 70c77f6dfd923e469cd645a0f825509cf0e9c490a0Jack Jansen rsrcname=None, others=[], raw=0, progress="default", destroot=""): 71182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 720ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress == "default": 732596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren if EasyDialogs is None: 742596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren print "Compiling %s"%(os.path.split(filename)[1],) 752596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren process = None 762596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren else: 772596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120) 782596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren progress.label("Compiling...") 792596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren progress.inc(0) 800ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # check for the script name being longer than 32 chars. This may trigger a bug 810ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # on OSX that can destroy your sourcefile. 820ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if '#' in os.path.split(filename)[1]: 830ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen raise BuildError, "BuildApplet could destroy your sourcefile on OSX, please rename: %s" % filename 840ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Read the source and compile it 850ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # (there's no point overwriting the destination if it has a syntax error) 86182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 870ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fp = open(filename, 'rU') 880ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen text = fp.read() 890ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fp.close() 900ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 910ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen code = compile(text + '\n', filename, "exec") 920ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except SyntaxError, arg: 930ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen raise BuildError, "Syntax error in script %s: %s" % (filename, arg) 940ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except EOFError: 950ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen raise BuildError, "End-of-file in script %s" % (filename,) 96182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 970ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Set the destination file name. Note that basename 980ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # does contain the whole filepath, only a .py is stripped. 99182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1000ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if string.lower(filename[-3:]) == ".py": 1010ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen basename = filename[:-3] 1020ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if MacOS.runtimemodel != 'macho' and not destname: 1030ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen destname = basename 1040ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 1050ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen basename = filename 106182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1070ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not destname: 1080ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if MacOS.runtimemodel == 'macho': 1090ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen destname = basename + '.app' 1100ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 1110ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen destname = basename + '.applet' 1120ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not rsrcname: 1130ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen rsrcname = basename + '.rsrc' 114182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1150ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Try removing the output file. This fails in MachO, but it should 1160ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # do any harm. 1170ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 1180ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen os.remove(destname) 1190ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except os.error: 1200ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen pass 121182b5aca27d376b08a2904bed42b751496f932f3Tim Peters process_common(template, progress, code, rsrcname, destname, 0, 122c77f6dfd923e469cd645a0f825509cf0e9c490a0Jack Jansen copy_codefragment, raw, others, filename, destroot) 123182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 124813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 125813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansendef update(template, filename, output): 1260ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if MacOS.runtimemodel == 'macho': 1270ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen raise BuildError, "No updating yet for MachO applets" 1280ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 1292596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren if EasyDialogs is None: 1302596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren print "Updating %s"%(os.path.split(filename)[1],) 1312596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren progress = None 1322596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren else: 1332596758cb42cb592f2e3c33ef77bc9b02c995510Ronald Oussoren progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120) 1340ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 1350ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress = None 1360ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not output: 1370ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen output = filename + ' (updated)' 138182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1390ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Try removing the output file 1400ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 1410ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen os.remove(output) 1420ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except os.error: 1430ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen pass 1440ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen process_common(template, progress, None, filename, output, 1, 1) 145813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 146813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 147182b5aca27d376b08a2904bed42b751496f932f3Tim Petersdef process_common(template, progress, code, rsrcname, destname, is_update, 148c77f6dfd923e469cd645a0f825509cf0e9c490a0Jack Jansen copy_codefragment, raw=0, others=[], filename=None, destroot=""): 1490ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if MacOS.runtimemodel == 'macho': 1500ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen return process_common_macho(template, progress, code, rsrcname, destname, 151c77f6dfd923e469cd645a0f825509cf0e9c490a0Jack Jansen is_update, raw, others, filename, destroot) 1520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if others: 1530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen raise BuildError, "Extra files only allowed for MachoPython applets" 1540ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Create FSSpecs for the various files 1550ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen template_fsr, d1, d2 = Carbon.File.FSResolveAliasFile(template, 1) 1560ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen template = template_fsr.as_pathname() 157182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1580ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Copy data (not resources, yet) from the template 1590ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 1600ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label("Copy data fork...") 1610ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.set(10) 162182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1630ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if copy_codefragment: 1640ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen tmpl = open(template, "rb") 1650ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest = open(destname, "wb") 1660ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen data = tmpl.read() 1670ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if data: 1680ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest.write(data) 1690ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest.close() 1700ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen tmpl.close() 1710ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen del dest 1720ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen del tmpl 173182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1740ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Open the output resource fork 175182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1760ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 1770ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label("Copy resources...") 1780ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.set(20) 1790ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 1800ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE) 1810ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except MacOS.Error: 1820ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen destdir, destfile = os.path.split(destname) 1830ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.FSCreateResourceFile(destdir, unicode(destfile), RESOURCE_FORK_NAME) 1840ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen output = Res.FSOpenResourceFile(destname, RESOURCE_FORK_NAME, WRITE) 185182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 1860ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Copy the resources from the target specific resource template, if any 1870ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen typesfound, ownertype = [], None 1880ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 1890ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen input = Res.FSOpenResourceFile(rsrcname, RESOURCE_FORK_NAME, READ) 1900ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except (MacOS.Error, ValueError): 1910ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen pass 1920ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 1930ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.inc(50) 1940ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 1950ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if is_update: 1960ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen skip_oldfile = ['cfrg'] 1970ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 1980ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen skip_oldfile = [] 1990ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress) 2000ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.CloseResFile(input) 201182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2020ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Check which resource-types we should not copy from the template 2030ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen skiptypes = [] 2040ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if 'vers' in typesfound: skiptypes.append('vers') 2050ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if 'SIZE' in typesfound: skiptypes.append('SIZE') 206182b5aca27d376b08a2904bed42b751496f932f3Tim Peters if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', 2070ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#'] 2080ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not copy_codefragment: 2090ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen skiptypes.append('cfrg') 210a3a505076efc19ec23669370778c5fa22d030ffaMark Dickinson## skipowner = (ownertype != None) 211182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2120ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Copy the resources from the template 213182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2140ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen input = Res.FSOpenResourceFile(template, RESOURCE_FORK_NAME, READ) 2150ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dummy, tmplowner = copyres(input, output, skiptypes, 1, progress) 216182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2170ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.CloseResFile(input) 2185b63acd31e0e40c1a9a9e9762905b0054ff37994Benjamin Peterson## if ownertype is None: 2190ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen## raise BuildError, "No owner resource found in either resource file or template" 2200ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Make sure we're manipulating the output resource file now 221182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2220ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.UseResFile(output) 22381da9f146c2223bc486197c2df03feda5126dcd5Jack Jansen 2245b63acd31e0e40c1a9a9e9762905b0054ff37994Benjamin Peterson if ownertype is None: 2250ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # No owner resource in the template. We have skipped the 2260ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Python owner resource, so we have to add our own. The relevant 2270ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # bundle stuff is already included in the interpret/applet template. 2280ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen newres = Res.Resource('\0') 2290ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource") 2300ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen ownertype = DEFAULT_APPLET_CREATOR 231182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2320ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if code: 2330ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Delete any existing 'PYC ' resource named __main__ 234182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2350ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 2360ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res = Res.Get1NamedResource(RESTYPE, RESNAME) 2370ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.RemoveResource() 2380ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except Res.Error: 2390ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen pass 240182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2410ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Create the raw data for the resource from the code object 2420ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 2430ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label("Write PYC resource...") 2440ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.set(120) 245182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2460ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen data = marshal.dumps(code) 2470ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen del code 2480ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen data = (MAGIC + '\0\0\0\0') + data 249182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2500ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Create the resource and write it 251182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen id = 0 2530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen while id < 128: 2540ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen id = Res.Unique1ID(RESTYPE) 2550ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res = Res.Resource(data) 2560ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.AddResource(RESTYPE, id, RESNAME) 2570ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen attrs = res.GetResAttrs() 2580ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen attrs = attrs | 0x04 # set preload 2590ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.SetResAttrs(attrs) 2600ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.WriteResource() 2610ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.ReleaseResource() 262182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2630ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Close the output file 264182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2650ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.CloseResFile(output) 266182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2670ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Now set the creator, type and bundle bit of the destination. 2680ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Done with FSSpec's, FSRef FInfo isn't good enough yet (2.3a1+) 2690ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest_fss = Carbon.File.FSSpec(destname) 2700ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest_finfo = dest_fss.FSpGetFInfo() 2710ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest_finfo.Creator = ownertype 2720ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest_finfo.Type = 'APPL' 2730ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest_finfo.Flags = dest_finfo.Flags | Carbon.Files.kHasBundle | Carbon.Files.kIsShared 2740ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest_finfo.Flags = dest_finfo.Flags & ~Carbon.Files.kHasBeenInited 2750ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dest_fss.FSpSetFInfo(dest_finfo) 276182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 2770ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen macostools.touched(destname) 2780ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 2790ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label("Done.") 2800ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.inc(0) 281813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 282182b5aca27d376b08a2904bed42b751496f932f3Tim Petersdef process_common_macho(template, progress, code, rsrcname, destname, is_update, 283c77f6dfd923e469cd645a0f825509cf0e9c490a0Jack Jansen raw=0, others=[], filename=None, destroot=""): 2840ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Check that we have a filename 2850ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if filename is None: 2860ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen raise BuildError, "Need source filename on MacOSX" 2870ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # First make sure the name ends in ".app" 2880ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if destname[-4:] != '.app': 2890ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen destname = destname + '.app' 2900ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Now deduce the short name 2910ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen destdir, shortname = os.path.split(destname) 2920ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if shortname[-4:] == '.app': 2930ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # Strip the .app suffix 2940ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen shortname = shortname[:-4] 2950ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen # And deduce the .plist and .icns names 2960ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen plistname = None 2970ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen icnsname = None 2980ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if rsrcname and rsrcname[-5:] == '.rsrc': 2990ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen tmp = rsrcname[:-5] 3000ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen plistname = tmp + '.plist' 3010ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if os.path.exists(plistname): 3020ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen icnsname = tmp + '.icns' 3030ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not os.path.exists(icnsname): 3040ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen icnsname = None 3050ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 3060ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen plistname = None 307d69b74453192bed078946fbe0f2b06489a118121Jack Jansen if not icnsname: 308d69b74453192bed078946fbe0f2b06489a118121Jack Jansen dft_icnsname = os.path.join(sys.prefix, 'Resources/Python.app/Contents/Resources/PythonApplet.icns') 309d69b74453192bed078946fbe0f2b06489a118121Jack Jansen if os.path.exists(dft_icnsname): 310d69b74453192bed078946fbe0f2b06489a118121Jack Jansen icnsname = dft_icnsname 3110ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not os.path.exists(rsrcname): 3120ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen rsrcname = None 3130ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 3140ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label('Creating bundle...') 3150ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen import bundlebuilder 3160ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder = bundlebuilder.AppBuilder(verbosity=0) 3170ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.mainprogram = filename 3180ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.builddir = destdir 3190ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.name = shortname 320c77f6dfd923e469cd645a0f825509cf0e9c490a0Jack Jansen builder.destroot = destroot 3210ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if rsrcname: 3220ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen realrsrcname = macresource.resource_pathname(rsrcname) 323182b5aca27d376b08a2904bed42b751496f932f3Tim Peters builder.files.append((realrsrcname, 3240ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen os.path.join('Contents/Resources', os.path.basename(rsrcname)))) 3250ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen for o in others: 3260ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if type(o) == str: 3270ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.resources.append(o) 3280ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 3290ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.files.append(o) 3300ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if plistname: 3310ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen import plistlib 3320ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.plist = plistlib.Plist.fromFile(plistname) 3330ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if icnsname: 3340ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.iconfile = icnsname 3350ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if not raw: 3360ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.argv_emulation = 1 3370ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.setup() 3380ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen builder.build() 339182b5aca27d376b08a2904bed42b751496f932f3Tim Peters if progress: 3400ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label('Done.') 3410ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.inc(0) 342182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 3430ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen## macostools.touched(dest_fss) 344813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 345813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# Copy resources between two resource file descriptors. 34681da9f146c2223bc486197c2df03feda5126dcd5Jack Jansen# skip a resource named '__main__' or (if skipowner is set) with ID zero. 347813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# Also skip resources with a type listed in skiptypes. 348813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen# 349813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansendef copyres(input, output, skiptypes, skipowner, progress=None): 3500ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen ctor = None 3510ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen alltypes = [] 3520ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.UseResFile(input) 3530ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen ntypes = Res.Count1Types() 3540ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress_type_inc = 50/ntypes 3550ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen for itype in range(1, 1+ntypes): 3560ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen type = Res.Get1IndType(itype) 3570ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if type in skiptypes: 3580ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen continue 3590ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen alltypes.append(type) 3600ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen nresources = Res.Count1Resources(type) 3610ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress_cur_inc = progress_type_inc/nresources 3620ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen for ires in range(1, 1+nresources): 3630ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res = Res.Get1IndResource(type, ires) 3640ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen id, type, name = res.GetResInfo() 3650ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen lcname = string.lower(name) 36681da9f146c2223bc486197c2df03feda5126dcd5Jack Jansen 3670ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if lcname == OWNERNAME and id == 0: 3680ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if skipowner: 3690ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen continue # Skip this one 3700ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 3710ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen ctor = type 3720ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen size = res.size 3730ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen attrs = res.GetResAttrs() 3740ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 3750ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label("Copy %s %d %s"%(type, id, name)) 3760ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.inc(progress_cur_inc) 3770ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.LoadResource() 3780ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.DetachResource() 3790ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.UseResFile(output) 3800ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen try: 3810ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res2 = Res.Get1Resource(type, id) 3820ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen except MacOS.Error: 3830ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res2 = None 3840ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if res2: 3850ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 3860ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label("Overwrite %s %d %s"%(type, id, name)) 3870ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.inc(0) 3880ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res2.RemoveResource() 3890ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.AddResource(type, id, name) 3900ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.WriteResource() 3910ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen attrs = attrs | res.GetResAttrs() 3920ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen res.SetResAttrs(attrs) 3930ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen Res.UseResFile(input) 3940ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen return alltypes, ctor 395813c997b7663aaad296f6f221d2395b3fee4b422Jack Jansen 396388fbf3d4a624becfbdedf6ec1dd57b57a5642ecJack Jansendef copyapptree(srctree, dsttree, exceptlist=[], progress=None): 3970ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen names = [] 3980ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if os.path.exists(dsttree): 3990ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen shutil.rmtree(dsttree) 4000ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen os.mkdir(dsttree) 4010ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen todo = os.listdir(srctree) 4020ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen while todo: 4030ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen this, todo = todo[0], todo[1:] 4040ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if this in exceptlist: 4050ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen continue 4060ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen thispath = os.path.join(srctree, this) 4070ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if os.path.isdir(thispath): 4080ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen thiscontent = os.listdir(thispath) 4090ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen for t in thiscontent: 4100ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen todo.append(os.path.join(this, t)) 4110ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen names.append(this) 4120ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen for this in names: 4130ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen srcpath = os.path.join(srctree, this) 4140ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen dstpath = os.path.join(dsttree, this) 4150ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if os.path.isdir(srcpath): 4160ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen os.mkdir(dstpath) 4170ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen elif os.path.islink(srcpath): 4180ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen endpoint = os.readlink(srcpath) 4190ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen os.symlink(endpoint, dstpath) 4200ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen else: 4210ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen if progress: 4220ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.label('Copy '+this) 4230ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen progress.inc(0) 4240ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen shutil.copy2(srcpath, dstpath) 425182b5aca27d376b08a2904bed42b751496f932f3Tim Peters 426b2e33fe285a1f998f477202e9379a39488ea518bJack Jansendef writepycfile(codeobject, cfile): 4270ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen import marshal 4280ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fc = open(cfile, 'wb') 4290ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fc.write('\0\0\0\0') # MAGIC placeholder, written later 4300ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fc.write('\0\0\0\0') # Timestap placeholder, not needed 4310ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen marshal.dump(codeobject, fc) 4320ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fc.flush() 4330ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fc.seek(0, 0) 4340ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fc.write(MAGIC) 4350ae3220736f9b71820b01aee1f540d0afcceb9a6Jack Jansen fc.close() 436