]> granicus.if.org Git - python/commitdiff
Implemented buildtools for MachoPython .app bundles. The API is compatible
authorJack Jansen <jack.jansen@cwi.nl>
Fri, 29 Mar 2002 21:21:28 +0000 (21:21 +0000)
committerJack Jansen <jack.jansen@cwi.nl>
Fri, 29 Mar 2002 21:21:28 +0000 (21:21 +0000)
enough that IDE and BuildApplet can create applets, yeah!

Mac/Lib/buildtools.py

index da43d096d95b2219e446ff6aa3eb4fa4e3583b00..25f77e63ed2cfc54b0153baab885cccba040f5ac 100644 (file)
@@ -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()