1ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao#!/usr/bin/env python 2ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 3ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoimport os 4ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoimport re 5ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoimport subprocess 6ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoimport sys 7ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoimport tempfile 8ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 9ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao### 10ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 11ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoclass DeltaAlgorithm(object): 12ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def __init__(self): 13ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.cache = set() 14ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 15ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def test(self, changes): 16ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao abstract 17ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 18ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao ### 19ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 20ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def getTestResult(self, changes): 21ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # There is no reason to cache successful tests because we will 22ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # always reduce the changeset when we see one. 23ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 24ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao changeset = frozenset(changes) 25ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if changeset in self.cache: 26ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return False 27ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao elif not self.test(changes): 28ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.cache.add(changeset) 29ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return False 30ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao else: 31ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return True 32ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 33ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def run(self, changes, force=False): 34ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # Make sure the initial test passes, if not then (a) either 35ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # the user doesn't expect monotonicity, and we may end up 36ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # doing O(N^2) tests, or (b) the test is wrong. Avoid the 37ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # O(N^2) case unless user requests it. 38ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if not force: 39ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if not self.getTestResult(changes): 40ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao raise ValueError,'Initial test passed to delta fails.' 41ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 42ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # Check empty set first to quickly find poor test functions. 43ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if self.getTestResult(set()): 44ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return set() 45ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao else: 46ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return self.delta(changes, self.split(changes)) 47ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 48ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def split(self, S): 49ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao """split(set) -> [sets] 50ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 51ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao Partition a set into one or two pieces. 52ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao """ 53ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 54ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # There are many ways to split, we could do a better job with more 55ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # context information (but then the API becomes grosser). 56ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao L = list(S) 57ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao mid = len(L)//2 58ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if mid==0: 59ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return L, 60ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao else: 61ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return L[:mid],L[mid:] 62ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 63ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def delta(self, c, sets): 64ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # assert(reduce(set.union, sets, set()) == c) 65ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 66ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # If there is nothing left we can remove, we are done. 67ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if len(sets) <= 1: 68ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return c 69ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 70ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # Look for a passing subset. 71ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao res = self.search(c, sets) 72ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if res is not None: 73ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return res 74ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 75ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # Otherwise, partition sets if possible; if not we are done. 76ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao refined = sum(map(list, map(self.split, sets)), []) 77ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if len(refined) == len(sets): 78ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return c 79ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 80ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return self.delta(c, refined) 81ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 82ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def search(self, c, sets): 83ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for i,S in enumerate(sets): 84ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # If test passes on this subset alone, recurse. 85ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if self.getTestResult(S): 86ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return self.delta(S, self.split(S)) 87ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 88ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # Otherwise if we have more than two sets, see if test 89ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # pases without this subset. 90ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if len(sets) > 2: 91ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao complement = sum(sets[:i] + sets[i+1:],[]) 92ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if self.getTestResult(complement): 93ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return self.delta(complement, sets[:i] + sets[i+1:]) 94ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 95ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao### 96ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 97ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoclass Token: 98ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def __init__(self, type, data, flags, file, line, column): 99ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.type = type 100ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.data = data 101ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.flags = flags 102ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.file = file 103ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.line = line 104ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.column = column 105ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 106ea285162342df160e7860e26528bc7110bc6c0cdShih-wei LiaokTokenRE = re.compile(r"""([a-z_]+) '(.*)'\t(.*)\tLoc=<(.*):(.*):(.*)>""", 107ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao re.DOTALL | re.MULTILINE) 108ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 109ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaodef getTokens(path): 110ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao p = subprocess.Popen(['clang','-dump-raw-tokens',path], 111ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao stdin=subprocess.PIPE, 112ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao stdout=subprocess.PIPE, 113ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao stderr=subprocess.PIPE) 114ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao out,err = p.communicate() 115ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 116ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao tokens = [] 117ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao collect = None 118ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for ln in err.split('\n'): 119ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # Silly programmers refuse to print in simple machine readable 120ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # formats. Whatever. 121ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if collect is None: 122ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao collect = ln 123ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao else: 124ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao collect = collect + '\n' + ln 125ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if 'Loc=<' in ln and ln.endswith('>'): 126ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao ln,collect = collect,None 127ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao tokens.append(Token(*kTokenRE.match(ln).groups())) 128ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 129ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return tokens 130ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 131ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao### 132ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 133ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoclass TMBDDelta(DeltaAlgorithm): 134ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def __init__(self, testProgram, tokenLists, log): 135ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def patchName(name, suffix): 136ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao base,ext = os.path.splitext(name) 137ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return base + '.' + suffix + ext 138ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao super(TMBDDelta, self).__init__() 139ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.testProgram = testProgram 140ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.tokenLists = tokenLists 141ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.tempFiles = [patchName(f,'tmp') 142ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for f,_ in self.tokenLists] 143ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.targetFiles = [patchName(f,'ok') 144ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for f,_ in self.tokenLists] 145ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.log = log 146ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.numTests = 0 147ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 148ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def writeFiles(self, changes, fileNames): 149ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao assert len(fileNames) == len(self.tokenLists) 150ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao byFile = [[] for i in self.tokenLists] 151ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for i,j in changes: 152ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao byFile[i].append(j) 153ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 154ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for i,(file,tokens) in enumerate(self.tokenLists): 155ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao f = open(fileNames[i],'w') 156ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for j in byFile[i]: 157ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao f.write(tokens[j]) 158ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao f.close() 159ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 160ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return byFile 161ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 162ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def test(self, changes): 163ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.numTests += 1 164ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 165ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao byFile = self.writeFiles(changes, self.tempFiles) 166ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 167ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if self.log: 168ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print >>sys.stderr, 'TEST - ', 169ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if self.log > 1: 170ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for i,(file,_) in enumerate(self.tokenLists): 171ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao indices = byFile[i] 172ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if i: 173ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write('\n ') 174ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write('%s:%d tokens: [' % (file,len(byFile[i]))) 175ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao prev = None 176ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for j in byFile[i]: 177ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if prev is None or j != prev + 1: 178ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if prev: 179ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write('%d][' % prev) 180ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write(str(j)) 181ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write(':') 182ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao prev = j 183ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if byFile[i]: 184ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write(str(byFile[i][-1])) 185ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write('] ') 186ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao else: 187ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print >>sys.stderr, ', '.join(['%s:%d tokens' % (file, len(byFile[i])) 188ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for i,(file,_) in enumerate(self.tokenLists)]), 189ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 190ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao p = subprocess.Popen([self.testProgram] + self.tempFiles) 191ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao res = p.wait() == 0 192ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 193ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if res: 194ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.writeFiles(changes, self.targetFiles) 195ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 196ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if self.log: 197ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print >>sys.stderr, '=> %s' % res 198ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao else: 199ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if res: 200ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print '\nSUCCESS (%d tokens)' % len(changes) 201ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao else: 202ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao sys.stderr.write('.') 203ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 204ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return res 205ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 206ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao def run(self): 207ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao res = super(TMBDDelta, self).run([(i,j) 208ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for i,(file,tokens) in enumerate(self.tokenLists) 209ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for j in range(len(tokens))]) 210ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao self.writeFiles(res, self.targetFiles) 211ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if not self.log: 212ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print >>sys.stderr 213ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao return res 214ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 215ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaodef tokenBasedMultiDelta(program, files, log): 216ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao # Read in the lists of tokens. 217ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao tokenLists = [(file, [t.data for t in getTokens(file)]) 218ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao for file in files] 219ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 220ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao numTokens = sum([len(tokens) for _,tokens in tokenLists]) 221ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print "Delta on %s with %d tokens." % (', '.join(files), numTokens) 222ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 223ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao tbmd = TMBDDelta(program, tokenLists, log) 224ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 225ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao res = tbmd.run() 226ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 227ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print "Finished %s with %d tokens (in %d tests)." % (', '.join(tbmd.targetFiles), 228ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao len(res), 229ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao tbmd.numTests) 230ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 231ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaodef main(): 232ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao from optparse import OptionParser, OptionGroup 233ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao parser = OptionParser("%prog <test program> {files+}") 234ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao parser.add_option("", "--debug", dest="debugLevel", 235ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao help="set debug level [default %default]", 236ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao action="store", type=int, default=0) 237ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao (opts, args) = parser.parse_args() 238ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 239ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao if len(args) <= 1: 240ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao parser.error('Invalid number of arguments.') 241ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 242ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao program,files = args[0],args[1:] 243ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 244ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao md = tokenBasedMultiDelta(program, files, log=opts.debugLevel) 245ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao 246ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liaoif __name__ == '__main__': 247ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao try: 248ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao main() 249ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao except KeyboardInterrupt: 250ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao print >>sys.stderr,'Interrupted.' 251ea285162342df160e7860e26528bc7110bc6c0cdShih-wei Liao os._exit(1) # Avoid freeing our giant cache. 252