blob: 3e2ee27f0e02f1187573bd203b947885740925de [file] [log] [blame]
Jack Jansenc9c99f21995-08-31 13:50:16 +00001#
2# Interactively decide what to distribute
3#
Jack Jansenc9c99f21995-08-31 13:50:16 +00004#
5# The exclude file signals files to always exclude,
Jack Jansen86288971996-08-28 14:18:58 +00006# The pattern file lines are of the form
7# *.c
8# This excludes all files ending in .c.
Jack Jansenc9c99f21995-08-31 13:50:16 +00009#
10# The include file signals files and directories to include.
11# Records are of the form
Jack Jansen86288971996-08-28 14:18:58 +000012# ('Tools:bgen:AE:AppleEvents.py', 'Lib:MacToolbox:AppleEvents.py')
13# This includes the specified file, putting it in the given place, or
14# ('Tools:bgen:AE:AppleEvents.py', None)
15# This excludes the specified file.
Jack Jansenc9c99f21995-08-31 13:50:16 +000016#
17from MkDistr_ui import *
18import fnmatch
Jack Jansenbe614ee2001-01-02 22:02:02 +000019import re
Jack Jansenc9c99f21995-08-31 13:50:16 +000020import os
21import sys
22import macfs
23import macostools
24
Jack Jansen73c804a1998-02-20 16:08:19 +000025DEBUG=0
26
Jack Jansenc9c99f21995-08-31 13:50:16 +000027SyntaxError='Include/exclude file syntax error'
28
29class Matcher:
30 """Include/exclude database, common code"""
31
Jack Jansen86288971996-08-28 14:18:58 +000032 def __init__(self, filename):
Jack Jansenc9c99f21995-08-31 13:50:16 +000033 self.filename = filename
34 self.rawdata = []
35 self.parse(filename)
36 self.rawdata.sort()
37 self.rebuild()
38 self.modified = 0
39
40 def parse(self, dbfile):
41 try:
42 fp = open(dbfile)
43 except IOError:
44 return
45 data = fp.readlines()
46 fp.close()
47 for d in data:
48 d = d[:-1]
49 if not d or d[0] == '#': continue
50 pat = self.parseline(d)
51 self.rawdata.append(pat)
52
Jack Jansenc9c99f21995-08-31 13:50:16 +000053 def save(self):
54 fp = open(self.filename, 'w')
Jack Jansen86288971996-08-28 14:18:58 +000055 self.savedata(fp, self.rawdata)
Jack Jansenc9c99f21995-08-31 13:50:16 +000056 self.modified = 0
57
58 def add(self, value):
Jack Jansen86288971996-08-28 14:18:58 +000059 if len(value) == 1:
Jack Jansenc9c99f21995-08-31 13:50:16 +000060 value = value + ('',)
61 self.rawdata.append(value)
62 self.rebuild1(value)
63 self.modified = 1
64
65 def delete(self, value):
66 key = value
67 for i in range(len(self.rawdata)):
Jack Jansen86288971996-08-28 14:18:58 +000068 if self.rawdata[i][0] == key:
Jack Jansenc9c99f21995-08-31 13:50:16 +000069 del self.rawdata[i]
70 self.unrebuild1(i, key)
71 self.modified = 1
72 return
73 print 'Not found!', key
74
75 def getall(self):
Jack Jansen86288971996-08-28 14:18:58 +000076 return map(lambda x: x[0], self.rawdata)
Jack Jansenc9c99f21995-08-31 13:50:16 +000077
78 def get(self, value):
Jack Jansen86288971996-08-28 14:18:58 +000079 for src, dst in self.rawdata:
Jack Jansenc9c99f21995-08-31 13:50:16 +000080 if src == value:
Jack Jansen86288971996-08-28 14:18:58 +000081 return src, dst
Jack Jansenc9c99f21995-08-31 13:50:16 +000082 print 'Not found!', value
83
84 def is_modified(self):
85 return self.modified
86
87class IncMatcher(Matcher):
88 """Include filename database and matching engine"""
89
90 def rebuild(self):
91 self.idict = {}
92 self.edict = {}
93 for v in self.rawdata:
94 self.rebuild1(v)
95
Jack Jansen86288971996-08-28 14:18:58 +000096 def parseline(self, line):
97 try:
98 data = eval(line)
99 except:
100 raise SyntaxError, line
101 if type(data) <> type(()) or len(data) not in (1,2):
102 raise SyntaxError, line
103 if len(data) == 1:
104 data = data + ('',)
105 return data
106
107 def savedata(self, fp, data):
108 for d in self.rawdata:
109 fp.write(`d`+'\n')
110
111 def rebuild1(self, (src, dst)):
112 if dst == '':
113 dst = src
114 if dst == None:
115 self.edict[src] = None
Jack Jansenc9c99f21995-08-31 13:50:16 +0000116 else:
Jack Jansen86288971996-08-28 14:18:58 +0000117 self.idict[src] = dst
Jack Jansenc9c99f21995-08-31 13:50:16 +0000118
119 def unrebuild1(self, num, src):
120 if self.idict.has_key(src):
121 del self.idict[src]
122 else:
123 del self.edict[src]
124
125 def match(self, patharg):
126 removed = []
127 # First check the include directory
128 path = patharg
129 while 1:
130 if self.idict.has_key(path):
131 # We know of this path (or initial piece of path)
132 dstpath = self.idict[path]
133 # We do want it distributed. Tack on the tail.
134 while removed:
135 dstpath = os.path.join(dstpath, removed[0])
136 removed = removed[1:]
137 # Finally, if the resultant string ends in a separator
138 # tack on our input filename
139 if dstpath[-1] == os.sep:
140 dir, file = os.path.split(path)
Jack Jansen86288971996-08-28 14:18:58 +0000141 dstpath = os.path.join(dstpath, file)
Jack Jansen73c804a1998-02-20 16:08:19 +0000142 if DEBUG:
143 print 'include', patharg, dstpath
Jack Jansenc9c99f21995-08-31 13:50:16 +0000144 return dstpath
Jack Janseneb43b302000-09-10 12:03:06 +0000145## path, lastcomp = os.path.split(path)
146## if not path:
147## break
148## removed[0:0] = [lastcomp]
149## # Next check the exclude directory
150## path = patharg
151## while 1:
Jack Jansenc9c99f21995-08-31 13:50:16 +0000152 if self.edict.has_key(path):
Jack Jansen73c804a1998-02-20 16:08:19 +0000153 if DEBUG:
154 print 'exclude', patharg, path
Jack Jansenc9c99f21995-08-31 13:50:16 +0000155 return ''
156 path, lastcomp = os.path.split(path)
157 if not path:
158 break
159 removed[0:0] = [lastcomp]
Jack Jansen73c804a1998-02-20 16:08:19 +0000160 if DEBUG:
161 print 'nomatch', patharg
Jack Jansenc9c99f21995-08-31 13:50:16 +0000162 return None
163
164 def checksourcetree(self):
165 rv = []
166 for name in self.idict.keys():
167 if not os.path.exists(name):
168 rv.append(name)
169 return rv
170
171class ExcMatcher(Matcher):
172 """Exclude pattern database and matching engine"""
173
174 def rebuild(self):
175 self.relist = []
176 for v in self.rawdata:
177 self.rebuild1(v)
178
Jack Jansen86288971996-08-28 14:18:58 +0000179 def parseline(self, data):
180 return (data, None)
181
182 def savedata(self, fp, data):
183 for d in self.rawdata:
184 fp.write(d[0]+'\n')
185
186 def rebuild1(self, (src, dst)):
187 pat = fnmatch.translate(src)
Jack Jansen73c804a1998-02-20 16:08:19 +0000188 if DEBUG:
189 print 'PATTERN', `src`, 'REGEX', `pat`
Jack Jansenbe614ee2001-01-02 22:02:02 +0000190 self.relist.append(re.compile(pat))
Jack Jansen86288971996-08-28 14:18:58 +0000191
Jack Jansenc9c99f21995-08-31 13:50:16 +0000192 def unrebuild1(self, num, src):
193 del self.relist[num]
194
195 def match(self, path):
196 comps = os.path.split(path)
197 file = comps[-1]
198 for pat in self.relist:
Jack Jansenbe614ee2001-01-02 22:02:02 +0000199 if pat and pat.match(file):
Jack Jansen73c804a1998-02-20 16:08:19 +0000200 if DEBUG:
201 print 'excmatch', file, pat
Jack Jansenc9c99f21995-08-31 13:50:16 +0000202 return 1
203 return 0
204
205
206class Main:
207 """The main program glueing it all together"""
208
209 def __init__(self):
210 InitUI()
Jack Jansen68552dd2000-05-05 23:07:43 +0000211 os.chdir(sys.prefix)
Jack Jansen230ad2c1996-10-23 15:52:56 +0000212 if not os.path.isdir(':Mac:Distributions'):
213 os.mkdir(':Mac:Distributions')
Jack Jansen68552dd2000-05-05 23:07:43 +0000214 self.typedist = GetType()
215 self.inc = IncMatcher(':Mac:Distributions:%s.include'%self.typedist)
216 self.exc = ExcMatcher(':Mac:Distributions:%s.exclude'%self.typedist)
Jack Jansenc9c99f21995-08-31 13:50:16 +0000217 self.ui = MkDistrUI(self)
218 self.ui.mainloop()
219
220 def check(self):
221 return self.checkdir(':', 1)
222
223 def checkdir(self, path, istop):
Jack Jansen73c804a1998-02-20 16:08:19 +0000224 if DEBUG:
225 print 'checkdir', path
Jack Jansenc9c99f21995-08-31 13:50:16 +0000226 files = os.listdir(path)
227 rv = []
228 todo = []
229 for f in files:
Jack Jansen73c804a1998-02-20 16:08:19 +0000230 if DEBUG:
231 print 'checkfile', f
Jack Jansenc9c99f21995-08-31 13:50:16 +0000232 if self.exc.match(f):
Jack Jansen73c804a1998-02-20 16:08:19 +0000233 if DEBUG:
234 print 'exclude match', f
Jack Jansenc9c99f21995-08-31 13:50:16 +0000235 continue
236 fullname = os.path.join(path, f)
Jack Jansen73c804a1998-02-20 16:08:19 +0000237 if DEBUG:
238 print 'checkpath', fullname
239 matchvalue = self.inc.match(fullname)
240 if matchvalue == None:
Jack Jansenc9c99f21995-08-31 13:50:16 +0000241 if os.path.isdir(fullname):
Jack Jansen73c804a1998-02-20 16:08:19 +0000242 if DEBUG:
243 print 'do dir', fullname
Jack Jansenc9c99f21995-08-31 13:50:16 +0000244 todo.append(fullname)
245 else:
Jack Jansen73c804a1998-02-20 16:08:19 +0000246 if DEBUG:
247 print 'include', fullname
Jack Jansenc9c99f21995-08-31 13:50:16 +0000248 rv.append(fullname)
Jack Jansen73c804a1998-02-20 16:08:19 +0000249 elif DEBUG:
250 print 'badmatch', matchvalue
Jack Jansenc9c99f21995-08-31 13:50:16 +0000251 for d in todo:
Jack Jansen6f69c501997-05-23 15:41:15 +0000252 if len(rv) > 500:
Jack Jansenc9c99f21995-08-31 13:50:16 +0000253 if istop:
254 rv.append('... and more ...')
255 return rv
256 rv = rv + self.checkdir(d, 0)
257 return rv
258
Jack Jansen68552dd2000-05-05 23:07:43 +0000259 def run(self):
Jack Jansenc9c99f21995-08-31 13:50:16 +0000260 missing = self.inc.checksourcetree()
261 if missing:
262 print '==== Missing source files ===='
263 for i in missing:
264 print i
265 print '==== Fix and retry ===='
266 return
Jack Jansencaaa9822000-05-06 22:34:20 +0000267 destprefix = os.path.join(sys.prefix, ':Mac:Distributions:(vise)')
Jack Jansen68552dd2000-05-05 23:07:43 +0000268 destprefix = os.path.join(destprefix, '%s Distribution'%self.typedist)
Jack Jansenc9c99f21995-08-31 13:50:16 +0000269 if not self.rundir(':', destprefix, 0):
270 return
271 self.rundir(':', destprefix, 1)
272
273 def rundir(self, path, destprefix, doit):
274 files = os.listdir(path)
275 todo = []
276 rv = 1
277 for f in files:
278 if self.exc.match(f):
279 continue
280 fullname = os.path.join(path, f)
281 if os.path.isdir(fullname):
282 todo.append(fullname)
283 else:
284 dest = self.inc.match(fullname)
285 if dest == None:
286 print 'Not yet resolved:', fullname
287 rv = 0
288 if dest:
289 if doit:
290 print 'COPY ', fullname
291 print ' -> ', os.path.join(destprefix, dest)
Jack Jansen73c804a1998-02-20 16:08:19 +0000292 try:
293 macostools.copy(fullname, os.path.join(destprefix, dest), 1)
294 except: #DBG
Jack Jansen36bcf9b2001-03-06 22:43:06 +0000295 print '*** Copy failed mysteriously, try again'
296 print '*** cwd', os.getcwd() #DBG
297 print '*** fsspec', macfs.FSSpec(fullname) #DBG
298 # Get rid of open files
299 try:
300 i = 1 / 0
301 except:
302 pass
303 macostools.copy(fullname, os.path.join(destprefix, dest), 1)
Jack Jansenc9c99f21995-08-31 13:50:16 +0000304 for d in todo:
305 if not self.rundir(d, destprefix, doit):
306 rv = 0
307 return rv
308
309 def save(self):
310 self.inc.save()
311 self.exc.save()
312
313 def is_modified(self):
314 return self.inc.is_modified() or self.exc.is_modified()
315
316if __name__ == '__main__':
317 Main()
318