summaryrefslogtreecommitdiffstats
path: root/Mac/Lib/buildtools.py
diff options
context:
space:
mode:
authorJack Jansen <jack.jansen@cwi.nl>2002-03-29 21:21:28 (GMT)
committerJack Jansen <jack.jansen@cwi.nl>2002-03-29 21:21:28 (GMT)
commitb2e33fe285a1f998f477202e9379a39488ea518b (patch)
tree34ece096bcd39d22fb793dc4b9886c1ab55c7ea0 /Mac/Lib/buildtools.py
parent32f782c03c5e47b5822ce9387176e38123475834 (diff)
downloadcpython-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/Lib/buildtools.py')
-rw-r--r--Mac/Lib/buildtools.py152
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()