diff options
author | Jack Jansen <jack.jansen@cwi.nl> | 2002-03-29 21:21:28 (GMT) |
---|---|---|
committer | Jack Jansen <jack.jansen@cwi.nl> | 2002-03-29 21:21:28 (GMT) |
commit | b2e33fe285a1f998f477202e9379a39488ea518b (patch) | |
tree | 34ece096bcd39d22fb793dc4b9886c1ab55c7ea0 /Mac | |
parent | 32f782c03c5e47b5822ce9387176e38123475834 (diff) | |
download | cpython-b2e33fe285a1f998f477202e9379a39488ea518b.zip cpython-b2e33fe285a1f998f477202e9379a39488ea518b.tar.gz cpython-b2e33fe285a1f998f477202e9379a39488ea518b.tar.bz2 |
Implemented buildtools for MachoPython .app bundles. The API is compatible
enough that IDE and BuildApplet can create applets, yeah!
Diffstat (limited to 'Mac')
-rw-r--r-- | Mac/Lib/buildtools.py | 152 |
1 files changed, 150 insertions, 2 deletions
diff --git a/Mac/Lib/buildtools.py b/Mac/Lib/buildtools.py index da43d09..25f77e6 100644 --- a/Mac/Lib/buildtools.py +++ b/Mac/Lib/buildtools.py @@ -10,7 +10,9 @@ from Carbon import Res import MACFS import MacOS import macostools +import macresource import EasyDialogs +import shutil BuildError = "BuildError" @@ -42,6 +44,10 @@ WRITE = 2 def findtemplate(template=None): """Locate the applet template along sys.path""" + if MacOS.runtimemodel == 'macho': + if template: + return template + return findtemplate_macho() if not template: template=TEMPLATE for p in sys.path: @@ -55,6 +61,13 @@ def findtemplate(template=None): raise BuildError, "Template %s not found on sys.path" % `template` file = file.as_pathname() return file + +def findtemplate_macho(): + execpath = sys.executable.split('/') + if not 'Contents' in execpath: + raise BuildError, "Not running from a .app bundle: %s" % sys.executable + i = execpath.index('Contents') + return '/'.join(execpath[:i]) def process(template, filename, output, copy_codefragment): @@ -82,13 +95,17 @@ def process(template, filename, output, copy_codefragment): destname = filename[:-3] rsrcname = destname + '.rsrc' else: - destname = filename + ".applet" + if MacOS.runtimemodel == 'macho': + destname = filename + '.app' + else: + destname = filename + ".applet" rsrcname = filename + '.rsrc' if output: destname = output - # Try removing the output file + # Try removing the output file. This fails in MachO, but it should + # do any harm. try: os.remove(destname) except os.error: @@ -97,6 +114,8 @@ def process(template, filename, output, copy_codefragment): def update(template, filename, output): + if MacOS.runtimemodel == 'macho': + raise BuildError, "No updating yet for MachO applets" if DEBUG: progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120) else: @@ -113,6 +132,8 @@ def update(template, filename, output): def process_common(template, progress, code, rsrcname, destname, is_update, copy_codefragment): + if MacOS.runtimemodel == 'macho': + return process_common_macho(template, progress, code, rsrcname, destname, is_update) # Create FSSpecs for the various files template_fss = macfs.FSSpec(template) template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss) @@ -238,6 +259,99 @@ def process_common(template, progress, code, rsrcname, destname, is_update, copy if DEBUG: progress.label("Done.") +def process_common_macho(template, progress, code, rsrcname, destname, is_update): + # First make sure the name ends in ".app" + if destname[-4:] != '.app': + destname = destname + '.app' + # Now deduce the short name + shortname = os.path.split(destname)[1] + if shortname[-4:] == '.app': + # Strip the .app suffix + shortname = shortname[:-4] + plistname = shortname + '.plist' + # Start with copying the .app framework + if not is_update: + exceptlist = ["Contents/Info.plist", + "Contents/Resources/English.lproj/InfoPlist.strings", + "Contents/Resources/python.rsrc", + ] + copyapptree(template, destname, exceptlist) + # Now either use the .plist file or the default + if plistname and os.path.exists(plistname): + shutil.copy2(plistname, os.path.join(destname, 'Contents/Info.plist')) + # XXXX Wrong. This should be parsed from plist file + # icnsname = 'PythonApplet.icns' + ownertype = 'PytA' + # XXXX Should copy .icns file + else: + plistname = os.path.join(template, 'Contents/Resources/Applet-Info.plist') + plistdata = open(plistname).read() + plistdata = plistdata % {'appletname':shortname} + ofp = open(os.path.join(destname, 'Contents/Info.plist'), 'w') + ofp.write(plistdata) + ofp.close() + ownertype = 'PytA' + # Create the PkgInfo file + ofp = open(os.path.join(destname, 'Contents/PkgInfo'), 'wb') + ofp.write('APPL' + ownertype) + ofp.close() + + + if DEBUG: + progress.label("Copy resources...") + progress.set(20) + resfilename = '%s.rsrc' % shortname + respartialpathname = 'Contents/Resources/%s' % resfilename + try: + output = Res.FSOpenResourceFile( + os.path.join(destname, respartialpathname), + u'', WRITE) + except MacOS.Error: + fsr, dummy = Res.FSCreateResourceFile( + os.path.join(destname, 'Contents/Resources'), + unicode(resfilename), '') + output = Res.FSOpenResourceFile(fsr, u'', WRITE) + + # Copy the resources from the target specific resource template, if any + typesfound, ownertype = [], None + try: + input = macresource.open_pathname(rsrcname) + except (MacOS.Error, ValueError): + pass + if DEBUG: + progress.inc(50) + else: + typesfound, ownertype = copyres(input, output, [], 0, progress) + Res.CloseResFile(input) + + # Check which resource-types we should not copy from the template + skiptypes = [] +## if 'vers' in typesfound: skiptypes.append('vers') +## if 'SIZE' in typesfound: skiptypes.append('SIZE') +## if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', +## 'icl8', 'ics4', 'ics8', 'ICN#', 'ics#'] +## if not copy_codefragment: +## skiptypes.append('cfrg') +## skipowner = (ownertype <> None) + + # Copy the resources from the template + + input = Res.FSOpenResourceFile( + os.path.join(template, 'Contents/Resources/python.rsrc'), u'', READ) + dummy, tmplowner = copyres(input, output, skiptypes, 1, progress) + + Res.CloseResFile(input) +## if ownertype == None: +## raise BuildError, "No owner resource found in either resource file or template" + # Make sure we're manipulating the output resource file now + + Res.CloseResFile(output) + + if code: + outputfilename = os.path.join(destname, 'Contents/Resources/__main__.pyc') + writepycfile(code, outputfilename) + +## macostools.touched(dest_fss) # Copy resources between two resource file descriptors. # skip a resource named '__main__' or (if skipowner is set) with ID zero. @@ -289,4 +403,38 @@ def copyres(input, output, skiptypes, skipowner, progress=None): Res.UseResFile(input) return alltypes, ctor +def copyapptree(srctree, dsttree, exceptlist=[]): + names = [] + if os.path.exists(dsttree): + shutil.rmtree(dsttree) + os.mkdir(dsttree) + todo = os.listdir(srctree) + while todo: + this, todo = todo[0], todo[1:] + if this in exceptlist: + continue + thispath = os.path.join(srctree, this) + if os.path.isdir(thispath): + thiscontent = os.listdir(thispath) + for t in thiscontent: + todo.append(os.path.join(this, t)) + names.append(this) + for this in names: + srcpath = os.path.join(srctree, this) + dstpath = os.path.join(dsttree, this) + if os.path.isdir(srcpath): + os.mkdir(dstpath) + else: + shutil.copy2(srcpath, dstpath) + +def writepycfile(codeobject, cfile): + import marshal + fc = open(cfile, 'wb') + fc.write('\0\0\0\0') # MAGIC placeholder, written later + fc.write('\0\0\0\0') # Timestap placeholder, not needed + marshal.dump(codeobject, fc) + fc.flush() + fc.seek(0, 0) + fc.write(MAGIC) + fc.close() |