[Python-checkins] CVS: python/dist/src/Mac/Lib buildtools.py,1.9,1.10

Jack Jansen jackjansen@users.sourceforge.net
Fri, 29 Mar 2002 13:21:31 -0800


Update of /cvsroot/python/python/dist/src/Mac/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv29893

Modified Files:
	buildtools.py 
Log Message:
Implemented buildtools for MachoPython .app bundles. The API is compatible
enough that IDE and BuildApplet can create applets, yeah!


Index: buildtools.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Mac/Lib/buildtools.py,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** buildtools.py	25 Aug 2001 12:01:58 -0000	1.9
--- buildtools.py	29 Mar 2002 21:21:28 -0000	1.10
***************
*** 11,15 ****
--- 11,17 ----
  import MacOS
  import macostools
+ import macresource
  import EasyDialogs
+ import shutil
  
  
***************
*** 43,46 ****
--- 45,52 ----
  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
***************
*** 56,59 ****
--- 62,72 ----
  	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])
  
  
***************
*** 83,87 ****
  		rsrcname = destname + '.rsrc'
  	else:
! 		destname = filename + ".applet"
  		rsrcname = filename + '.rsrc'
  	
--- 96,103 ----
  		rsrcname = destname + '.rsrc'
  	else:
! 		if MacOS.runtimemodel == 'macho':
! 			destname = filename + '.app'
! 		else:
! 			destname = filename + ".applet"
  		rsrcname = filename + '.rsrc'
  	
***************
*** 89,93 ****
  		destname = output
  	
! 	# Try removing the output file
  	try:
  		os.remove(destname)
--- 105,110 ----
  		destname = output
  	
! 	# Try removing the output file. This fails in MachO, but it should
! 	# do any harm.
  	try:
  		os.remove(destname)
***************
*** 98,101 ****
--- 115,120 ----
  
  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)
***************
*** 114,117 ****
--- 133,138 ----
  
  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)
***************
*** 239,242 ****
--- 260,356 ----
  		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.
***************
*** 290,292 ****
--- 404,440 ----
  	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()