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