blob: 54209843df7f95e3f0afea22b1c0e31223c788cb [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.
Daniel Dunbar163f31a2009-01-21 23:34:23 +0000155 for i,(a,b) in enumerate(map(None, infoA.commands, infoB.commands)):
156 if a is None:
157 print 'A MISSING:',' '.join(b)
158 differ = True
159 continue
160 elif b is None:
161 print 'B MISSING:',' '.join(a)
162 differ = True
163 continue
164
Daniel Dunbarab130612009-01-13 07:38:29 +0000165 diff = DriverZipperDiff(a,b)
166 diffs = list(diff.getDiffs())
167 if diffs:
168 print '-- COMMAND %d DIFFERS -' % i
169 print 'A COMMAND:',' '.join(a)
170 print 'B COMMAND:',' '.join(b)
171 print
172 for i,(aElt,bElt) in enumerate(diffs):
173 if aElt is None:
174 print 'A missing: %s' % bElt
175 elif bElt is None:
176 print 'B missing: %s' % aElt
177 else:
178 print 'mismatch: A: %s' % aElt
179 print ' B: %s' % bElt
Daniel Dunbar06172d62009-01-20 00:47:24 +0000180 differ = True
Daniel Dunbar163f31a2009-01-21 23:34:23 +0000181
Daniel Dunbarab130612009-01-13 07:38:29 +0000182 # Compare result codes.
183 if infoA.exitCode != infoB.exitCode:
184 print '-- EXIT CODES DIFFER -'
185 print 'A: ',infoA.exitCode
186 print 'B: ',infoB.exitCode
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000187 differ = True
188
189 if differ:
190 sys.exit(1)
Daniel Dunbarab130612009-01-13 07:38:29 +0000191
192if __name__ == '__main__':
193 main()