diff options
| author | Jack Jansen <jack.jansen@cwi.nl> | 2002-03-29 21:21:28 +0000 | 
|---|---|---|
| committer | Jack Jansen <jack.jansen@cwi.nl> | 2002-03-29 21:21:28 +0000 | 
| commit | b2e33fe285a1f998f477202e9379a39488ea518b (patch) | |
| tree | 34ece096bcd39d22fb793dc4b9886c1ab55c7ea0 /Mac/Lib/buildtools.py | |
| parent | 32f782c03c5e47b5822ce9387176e38123475834 (diff) | |
| download | cpython-git-b2e33fe285a1f998f477202e9379a39488ea518b.tar.gz | |
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.py | 152 | 
1 files changed, 150 insertions, 2 deletions
| diff --git a/Mac/Lib/buildtools.py b/Mac/Lib/buildtools.py index da43d096d9..25f77e63ed 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() | 
