mirror of https://github.com/python/cpython
Implemented buildtools for MachoPython .app bundles. The API is compatible
enough that IDE and BuildApplet can create applets, yeah!
This commit is contained in:
parent
32f782c03c
commit
b2e33fe285
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in New Issue