Implemented buildtools for MachoPython .app bundles. The API is compatible

enough that IDE and BuildApplet can create applets, yeah!
This commit is contained in:
Jack Jansen 2002-03-29 21:21:28 +00:00
parent 32f782c03c
commit b2e33fe285
1 changed files with 150 additions and 2 deletions

View 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()