blob: 97c91a8209156bee1b33507a162c7f864cf3aa25 [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
Daniel Dunbar76715912009-01-28 19:26:20 +0000109 ln.startswith('gcc version') or
110 ln.startswith('ccc version')):
Daniel Dunbarab130612009-01-13 07:38:29 +0000111 pass
112 elif ln.strip().startswith('"'):
113 self.commands.append(list(splitArgs(ln)))
114 else:
115 self.stderr += ln + '\n'
116
117 self.stderr = self.stderr.strip()
118 self.exitCode = res
119
120def captureDriverInfo(cmd, args):
121 p = subprocess.Popen([cmd,'-###'] + args,
122 stdin=None,
123 stdout=subprocess.PIPE,
124 stderr=subprocess.PIPE)
125 out,err = p.communicate()
126 res = p.wait()
127 return CompileInfo(out,err,res)
128
129def main():
Daniel Dunbar2253dc42009-01-14 20:06:04 +0000130 import os, sys
Daniel Dunbarab130612009-01-13 07:38:29 +0000131
132 args = sys.argv[1:]
Daniel Dunbar2253dc42009-01-14 20:06:04 +0000133 driverA = os.getenv('DRIVER_A') or 'gcc'
134 driverB = os.getenv('DRIVER_B') or 'xcc'
Daniel Dunbarab130612009-01-13 07:38:29 +0000135
136 infoA = captureDriverInfo(driverA, args)
137 infoB = captureDriverInfo(driverB, args)
138
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000139 differ = False
140
Daniel Dunbarab130612009-01-13 07:38:29 +0000141 # Compare stdout.
142 if infoA.stdout != infoB.stdout:
143 print '-- STDOUT DIFFERS -'
144 print 'A: ',infoA.stdout
145 print 'B: ',infoB.stdout
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000146 differ = True
Daniel Dunbarab130612009-01-13 07:38:29 +0000147
148 # Compare stderr.
149 if infoA.stderr != infoB.stderr:
150 print '-- STDERR DIFFERS -'
151 print 'A: ',infoA.stderr
152 print 'B: ',infoB.stderr
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000153 differ = True
Daniel Dunbarab130612009-01-13 07:38:29 +0000154
155 # Compare commands.
Daniel Dunbar163f31a2009-01-21 23:34:23 +0000156 for i,(a,b) in enumerate(map(None, infoA.commands, infoB.commands)):
157 if a is None:
158 print 'A MISSING:',' '.join(b)
159 differ = True
160 continue
161 elif b is None:
162 print 'B MISSING:',' '.join(a)
163 differ = True
164 continue
165
Daniel Dunbarab130612009-01-13 07:38:29 +0000166 diff = DriverZipperDiff(a,b)
167 diffs = list(diff.getDiffs())
168 if diffs:
169 print '-- COMMAND %d DIFFERS -' % i
170 print 'A COMMAND:',' '.join(a)
171 print 'B COMMAND:',' '.join(b)
172 print
173 for i,(aElt,bElt) in enumerate(diffs):
174 if aElt is None:
175 print 'A missing: %s' % bElt
176 elif bElt is None:
177 print 'B missing: %s' % aElt
178 else:
179 print 'mismatch: A: %s' % aElt
180 print ' B: %s' % bElt
Daniel Dunbar06172d62009-01-20 00:47:24 +0000181 differ = True
Daniel Dunbar163f31a2009-01-21 23:34:23 +0000182
Daniel Dunbarab130612009-01-13 07:38:29 +0000183 # Compare result codes.
184 if infoA.exitCode != infoB.exitCode:
185 print '-- EXIT CODES DIFFER -'
186 print 'A: ',infoA.exitCode
187 print 'B: ',infoB.exitCode
Daniel Dunbarc97c05f2009-01-17 00:50:45 +0000188 differ = True
189
190 if differ:
191 sys.exit(1)
Daniel Dunbarab130612009-01-13 07:38:29 +0000192
193if __name__ == '__main__':
194 main()