blob: cc4caad4f664c224e38a995a4809de81ac626663 [file] [log] [blame]
Daniel Dunbarab130612009-01-13 07:38:29 +00001#!/usr/bin/python
2
3import subprocess
4
5def splitArgs(s):
6 it = iter(s)
7 current = ''
8 inQuote = False
9 for c in it:
10 if c == '"':
11 if inQuote:
12 inQuote = False
13 yield current + '"'
14 else:
15 inQuote = True
16 current = '"'
17 elif inQuote:
18 if c == '\\':
19 current += c
20 current += it.next()
21 else:
22 current += c
23 elif not c.isspace():
24 yield c
25
26def insertMinimumPadding(a, b, dist):
27 """insertMinimumPadding(a,b) -> (a',b')
28
29 Return two lists of equal length, where some number of Nones have
30 been inserted into the shorter list such that sum(map(dist, a',
31 b')) is minimized.
32
33 Assumes dist(X, Y) -> int and non-negative.
34 """
35
36 # Yay for simplicity over complexity.
37
38 def extend(aElt, bElt, solution):
39 d0,(a0,b0) = solution
40 return d0 + dist(aElt,bElt), (([aElt]+a0),([bElt]+b0))
41
42 def f(a, b):
43 if len(a) == len(b):
44 return (sum(map(dist, a, b)), (a, b))
45
46 if not a or not b:
47 if not a:
48 a += [None] * len(b)
49 else:
50 b += [None] * len(a)
51 return (sum(map(dist, a, b)), (a, b))
52
53 if int(dist(a[0], b[0])) == 0:
54 # Non-negative condition implies maximum is satisfied
55 # taking this.
56 return extend(a[0], b[0], f(a[1:], b[1:]))
57
58 if len(a) < len(b):
59 return min(f([None] + a, b),
60 extend(a[0], b[0], f(a[1:], b[1:])))
61 else:
62 return min(f(a, [None] + b),
63 extend(a[0], b[0], f(a[1:], b[1:])))
64
65 return f(a, b)[1]
66
67class ZipperDiff(object):
68 """ZipperDiff - Simple (slow) diff only accomodating inserts."""
69
70 def __init__(self, a, b):
71 self.a = a
72 self.b = b
73
74 def dist(self, a, b):
75 return a != b
76
77 def getDiffs(self):
78 a,b = insertMinimumPadding(self.a, self.b, self.dist)
79 for aElt,bElt in zip(a,b):
80 if self.dist(aElt, bElt):
81 yield aElt,bElt
82
83class DriverZipperDiff(ZipperDiff):
84 def isTempFile(self, filename):
85 if filename[0] != '"' or filename[-1] != '"':
86 return False
87 return (filename.startswith('/tmp/', 1) or
88 filename.startswith('/var/', 1))
89
90 def dist(self, a, b):
91 if a and b and self.isTempFile(a) and self.isTempFile(b):
92 return 0
93 return super(DriverZipperDiff, self).dist(a,b)
94
95class CompileInfo:
96 def __init__(self, out, err, res):
97 self.commands = []
98
99 # Standard out isn't used for much.
100 self.stdout = out
101 self.stderr = ''
102
103 # FIXME: Compare error messages as well.
104 for ln in err.split('\n'):
105 if (ln == 'Using built-in specs.' or
106 ln.startswith('Target: ') or
107 ln.startswith('Configured with: ') or
108 ln.startswith('Thread model: ') or
109 ln.startswith('gcc version')):
110 pass
111 elif ln.strip().startswith('"'):
112 self.commands.append(list(splitArgs(ln)))
113 else:
114 self.stderr += ln + '\n'
115
116 self.stderr = self.stderr.strip()
117 self.exitCode = res
118
119def captureDriverInfo(cmd, args):
120 p = subprocess.Popen([cmd,'-###'] + args,
121 stdin=None,
122 stdout=subprocess.PIPE,
123 stderr=subprocess.PIPE)
124 out,err = p.communicate()
125 res = p.wait()
126 return CompileInfo(out,err,res)
127
128def main():
Daniel Dunbar2253dc42009-01-14 20:06:04 +0000129 import os, sys
Daniel Dunbarab130612009-01-13 07:38:29 +0000130
131 args = sys.argv[1:]
Daniel Dunbar2253dc42009-01-14 20:06:04 +0000132 driverA = os.getenv('DRIVER_A') or 'gcc'
133 driverB = os.getenv('DRIVER_B') or 'xcc'
Daniel Dunbarab130612009-01-13 07:38:29 +0000134
135 infoA = captureDriverInfo(driverA, args)
136 infoB = captureDriverInfo(driverB, args)
137
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000138 differ = False
139
Daniel Dunbarab130612009-01-13 07:38:29 +0000140 # Compare stdout.
141 if infoA.stdout != infoB.stdout:
142 print '-- STDOUT DIFFERS -'
143 print 'A: ',infoA.stdout
144 print 'B: ',infoB.stdout
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000145 differ = True
Daniel Dunbarab130612009-01-13 07:38:29 +0000146
147 # Compare stderr.
148 if infoA.stderr != infoB.stderr:
149 print '-- STDERR DIFFERS -'
150 print 'A: ',infoA.stderr
151 print 'B: ',infoB.stderr
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000152 differ = True
Daniel Dunbarab130612009-01-13 07:38:29 +0000153
154 # Compare commands.
155 for i,(a,b) in enumerate(zip(infoA.commands, infoB.commands)):
156 diff = DriverZipperDiff(a,b)
157 diffs = list(diff.getDiffs())
158 if diffs:
159 print '-- COMMAND %d DIFFERS -' % i
160 print 'A COMMAND:',' '.join(a)
161 print 'B COMMAND:',' '.join(b)
162 print
163 for i,(aElt,bElt) in enumerate(diffs):
164 if aElt is None:
165 print 'A missing: %s' % bElt
166 elif bElt is None:
167 print 'B missing: %s' % aElt
168 else:
169 print 'mismatch: A: %s' % aElt
170 print ' B: %s' % bElt
Daniel Dunbar06172d62009-01-20 00:47:24 +0000171 differ = True
Daniel Dunbarab130612009-01-13 07:38:29 +0000172
173 # Compare result codes.
174 if infoA.exitCode != infoB.exitCode:
175 print '-- EXIT CODES DIFFER -'
176 print 'A: ',infoA.exitCode
177 print 'B: ',infoB.exitCode
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000178 differ = True
179
180 if differ:
181 sys.exit(1)
Daniel Dunbarab130612009-01-13 07:38:29 +0000182
183if __name__ == '__main__':
184 main()