mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			318 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#
 | 
						|
# Interactively decide what to distribute
 | 
						|
#
 | 
						|
#
 | 
						|
# The exclude file signals files to always exclude,
 | 
						|
# The pattern file lines are of the form
 | 
						|
# *.c
 | 
						|
# This excludes all files ending in .c.
 | 
						|
#
 | 
						|
# The include file signals files and directories to include.
 | 
						|
# Records are of the form
 | 
						|
# ('Tools:bgen:AE:AppleEvents.py', 'Lib:MacToolbox:AppleEvents.py')
 | 
						|
# This includes the specified file, putting it in the given place, or
 | 
						|
# ('Tools:bgen:AE:AppleEvents.py', None)
 | 
						|
# This excludes the specified file.
 | 
						|
#
 | 
						|
from MkDistr_ui import *
 | 
						|
import fnmatch
 | 
						|
import re
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import macfs
 | 
						|
import macostools
 | 
						|
 | 
						|
DEBUG=0
 | 
						|
 | 
						|
SyntaxError='Include/exclude file syntax error'
 | 
						|
 | 
						|
class Matcher:
 | 
						|
	"""Include/exclude database, common code"""
 | 
						|
	
 | 
						|
	def __init__(self, filename):
 | 
						|
		self.filename = filename
 | 
						|
		self.rawdata = []
 | 
						|
		self.parse(filename)
 | 
						|
		self.rawdata.sort()
 | 
						|
		self.rebuild()
 | 
						|
		self.modified = 0
 | 
						|
 | 
						|
	def parse(self, dbfile):
 | 
						|
		try:
 | 
						|
			fp = open(dbfile)
 | 
						|
		except IOError:
 | 
						|
			return
 | 
						|
		data = fp.readlines()
 | 
						|
		fp.close()
 | 
						|
		for d in data:
 | 
						|
			d = d[:-1]
 | 
						|
			if not d or d[0] == '#': continue
 | 
						|
			pat = self.parseline(d)
 | 
						|
			self.rawdata.append(pat)
 | 
						|
				
 | 
						|
	def save(self):
 | 
						|
		fp = open(self.filename, 'w')
 | 
						|
		self.savedata(fp, self.rawdata)
 | 
						|
		self.modified = 0
 | 
						|
			
 | 
						|
	def add(self, value):
 | 
						|
		if len(value) == 1:
 | 
						|
			value = value + ('',)
 | 
						|
		self.rawdata.append(value)
 | 
						|
		self.rebuild1(value)
 | 
						|
		self.modified = 1
 | 
						|
		
 | 
						|
	def delete(self, value):
 | 
						|
		key = value
 | 
						|
		for i in range(len(self.rawdata)):
 | 
						|
			if self.rawdata[i][0] == key:
 | 
						|
				del self.rawdata[i]
 | 
						|
				self.unrebuild1(i, key)
 | 
						|
				self.modified = 1
 | 
						|
				return
 | 
						|
		print 'Not found!', key
 | 
						|
				
 | 
						|
	def getall(self):
 | 
						|
		return map(lambda x: x[0], self.rawdata)
 | 
						|
	
 | 
						|
	def get(self, value):
 | 
						|
		for src, dst in self.rawdata:
 | 
						|
			if src == value:
 | 
						|
				return src, dst
 | 
						|
		print 'Not found!', value
 | 
						|
				
 | 
						|
	def is_modified(self):
 | 
						|
		return self.modified
 | 
						|
							
 | 
						|
class IncMatcher(Matcher):
 | 
						|
	"""Include filename database and matching engine"""
 | 
						|
 | 
						|
	def rebuild(self):
 | 
						|
		self.idict = {}
 | 
						|
		self.edict = {}
 | 
						|
		for v in self.rawdata:
 | 
						|
			self.rebuild1(v)
 | 
						|
			
 | 
						|
	def parseline(self, line):
 | 
						|
		try:
 | 
						|
			data = eval(line)
 | 
						|
		except:
 | 
						|
			raise SyntaxError, line
 | 
						|
		if type(data) <> type(()) or len(data) not in (1,2):
 | 
						|
			raise SyntaxError, line
 | 
						|
		if len(data) == 1:
 | 
						|
			data = data + ('',)
 | 
						|
		return data
 | 
						|
		
 | 
						|
	def savedata(self, fp, data):
 | 
						|
		for d in self.rawdata:
 | 
						|
			fp.write(`d`+'\n')
 | 
						|
		
 | 
						|
	def rebuild1(self, (src, dst)):
 | 
						|
		if dst == '':
 | 
						|
			dst = src
 | 
						|
		if dst == None:
 | 
						|
			self.edict[src] = None
 | 
						|
		else:
 | 
						|
			self.idict[src] = dst
 | 
						|
			
 | 
						|
	def unrebuild1(self, num, src):
 | 
						|
		if self.idict.has_key(src):
 | 
						|
			del self.idict[src]
 | 
						|
		else:
 | 
						|
			del self.edict[src]
 | 
						|
	
 | 
						|
	def match(self, patharg):
 | 
						|
		removed = []
 | 
						|
		# First check the include directory
 | 
						|
		path = patharg
 | 
						|
		while 1:
 | 
						|
			if self.idict.has_key(path):
 | 
						|
				# We know of this path (or initial piece of path)
 | 
						|
				dstpath = self.idict[path]
 | 
						|
				# We do want it distributed. Tack on the tail.
 | 
						|
				while removed:
 | 
						|
					dstpath = os.path.join(dstpath, removed[0])
 | 
						|
					removed = removed[1:]
 | 
						|
				# Finally, if the resultant string ends in a separator
 | 
						|
				# tack on our input filename
 | 
						|
				if dstpath[-1] == os.sep:
 | 
						|
					dir, file = os.path.split(path)
 | 
						|
					dstpath = os.path.join(dstpath, file)
 | 
						|
				if DEBUG:
 | 
						|
					print 'include', patharg, dstpath
 | 
						|
				return dstpath
 | 
						|
##			path, lastcomp = os.path.split(path)
 | 
						|
##			if not path:
 | 
						|
##				break
 | 
						|
##			removed[0:0] = [lastcomp]
 | 
						|
##		# Next check the exclude directory
 | 
						|
##		path = patharg
 | 
						|
##		while 1:
 | 
						|
			if self.edict.has_key(path):
 | 
						|
				if DEBUG:
 | 
						|
					print 'exclude', patharg, path
 | 
						|
				return ''
 | 
						|
			path, lastcomp = os.path.split(path)
 | 
						|
			if not path:
 | 
						|
				break
 | 
						|
			removed[0:0] = [lastcomp]
 | 
						|
		if DEBUG:
 | 
						|
			print 'nomatch', patharg
 | 
						|
		return None
 | 
						|
			
 | 
						|
	def checksourcetree(self):
 | 
						|
		rv = []
 | 
						|
		for name in self.idict.keys():
 | 
						|
			if not os.path.exists(name):
 | 
						|
				rv.append(name)
 | 
						|
		return rv
 | 
						|
				
 | 
						|
class ExcMatcher(Matcher):
 | 
						|
	"""Exclude pattern database and matching engine"""
 | 
						|
 | 
						|
	def rebuild(self):
 | 
						|
		self.relist = []
 | 
						|
		for v in self.rawdata:
 | 
						|
			self.rebuild1(v)
 | 
						|
		
 | 
						|
	def parseline(self, data):
 | 
						|
		return (data, None)
 | 
						|
 | 
						|
	def savedata(self, fp, data):
 | 
						|
		for d in self.rawdata:
 | 
						|
			fp.write(d[0]+'\n')		
 | 
						|
		
 | 
						|
	def rebuild1(self, (src, dst)):
 | 
						|
		pat = fnmatch.translate(src)
 | 
						|
		if DEBUG:
 | 
						|
			print 'PATTERN', `src`, 'REGEX', `pat`
 | 
						|
		self.relist.append(re.compile(pat))
 | 
						|
		
 | 
						|
	def unrebuild1(self, num, src):
 | 
						|
		del self.relist[num]
 | 
						|
	
 | 
						|
	def match(self, path):
 | 
						|
		comps = os.path.split(path)
 | 
						|
		file = comps[-1]
 | 
						|
		for pat in self.relist:
 | 
						|
			if pat and pat.match(file):
 | 
						|
				if DEBUG:
 | 
						|
					print 'excmatch', file, pat
 | 
						|
				return 1
 | 
						|
		return 0		
 | 
						|
		 
 | 
						|
		
 | 
						|
class Main:
 | 
						|
	"""The main program glueing it all together"""
 | 
						|
	
 | 
						|
	def __init__(self):
 | 
						|
		InitUI()
 | 
						|
		os.chdir(sys.prefix)
 | 
						|
		if not os.path.isdir(':Mac:Distributions'):
 | 
						|
			os.mkdir(':Mac:Distributions')
 | 
						|
		self.typedist = GetType()
 | 
						|
		self.inc = IncMatcher(':Mac:Distributions:%s.include'%self.typedist)
 | 
						|
		self.exc = ExcMatcher(':Mac:Distributions:%s.exclude'%self.typedist)
 | 
						|
		self.ui = MkDistrUI(self)
 | 
						|
		self.ui.mainloop()
 | 
						|
		
 | 
						|
	def check(self):
 | 
						|
		return self.checkdir(':', 1)
 | 
						|
		
 | 
						|
	def checkdir(self, path, istop):
 | 
						|
		if DEBUG:
 | 
						|
			print 'checkdir', path
 | 
						|
		files = os.listdir(path)
 | 
						|
		rv = []
 | 
						|
		todo = []
 | 
						|
		for f in files:
 | 
						|
			if DEBUG:
 | 
						|
				print 'checkfile', f
 | 
						|
			if self.exc.match(f):
 | 
						|
				if DEBUG:
 | 
						|
					print 'exclude match', f
 | 
						|
				continue
 | 
						|
			fullname = os.path.join(path, f)
 | 
						|
			if DEBUG:
 | 
						|
				print 'checkpath', fullname
 | 
						|
			matchvalue = self.inc.match(fullname)
 | 
						|
			if matchvalue == None:
 | 
						|
				if os.path.isdir(fullname):
 | 
						|
					if DEBUG:
 | 
						|
						print 'do dir', fullname
 | 
						|
					todo.append(fullname)
 | 
						|
				else:
 | 
						|
					if DEBUG:
 | 
						|
						print 'include', fullname
 | 
						|
					rv.append(fullname)
 | 
						|
			elif DEBUG:
 | 
						|
				print 'badmatch', matchvalue
 | 
						|
		for d in todo:
 | 
						|
			if len(rv) > 500:
 | 
						|
				if istop:
 | 
						|
					rv.append('... and more ...')
 | 
						|
				return rv
 | 
						|
			rv = rv + self.checkdir(d, 0)
 | 
						|
		return rv
 | 
						|
		
 | 
						|
	def run(self):
 | 
						|
		missing = self.inc.checksourcetree()
 | 
						|
		if missing:
 | 
						|
			print '==== Missing source files ===='
 | 
						|
			for i in missing:
 | 
						|
				print i
 | 
						|
			print '==== Fix and retry ===='
 | 
						|
			return
 | 
						|
		destprefix = os.path.join(sys.prefix, ':Mac:Distributions:(vise)')
 | 
						|
		destprefix = os.path.join(destprefix, '%s Distribution'%self.typedist)
 | 
						|
		if not self.rundir(':', destprefix, 0):
 | 
						|
			return
 | 
						|
		self.rundir(':', destprefix, 1)
 | 
						|
 | 
						|
	def rundir(self, path, destprefix, doit):
 | 
						|
		files = os.listdir(path)
 | 
						|
		todo = []
 | 
						|
		rv = 1
 | 
						|
		for f in files:
 | 
						|
			if self.exc.match(f):
 | 
						|
				continue
 | 
						|
			fullname = os.path.join(path, f)
 | 
						|
			if os.path.isdir(fullname):
 | 
						|
				todo.append(fullname)
 | 
						|
			else:
 | 
						|
				dest = self.inc.match(fullname)
 | 
						|
				if dest == None:
 | 
						|
					print 'Not yet resolved:', fullname
 | 
						|
					rv = 0
 | 
						|
				if dest:
 | 
						|
					if doit:
 | 
						|
						print 'COPY ', fullname
 | 
						|
						print '  -> ', os.path.join(destprefix, dest)
 | 
						|
						try:
 | 
						|
							macostools.copy(fullname, os.path.join(destprefix, dest), 1)
 | 
						|
						except: #DBG
 | 
						|
							print '*** Copy failed mysteriously, try again'
 | 
						|
							print '*** cwd', os.getcwd() #DBG
 | 
						|
							print '*** fsspec', macfs.FSSpec(fullname) #DBG
 | 
						|
							# Get rid of open files
 | 
						|
							try:
 | 
						|
								i = 1 / 0
 | 
						|
							except:
 | 
						|
								pass
 | 
						|
							macostools.copy(fullname, os.path.join(destprefix, dest), 1)
 | 
						|
		for d in todo:
 | 
						|
			if not self.rundir(d, destprefix, doit):
 | 
						|
				rv = 0
 | 
						|
		return rv
 | 
						|
		
 | 
						|
	def save(self):
 | 
						|
		self.inc.save()
 | 
						|
		self.exc.save()
 | 
						|
		
 | 
						|
	def is_modified(self):
 | 
						|
		return self.inc.is_modified() or self.exc.is_modified()
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
	Main()
 | 
						|
	
 |