|
1
by Kees Cook
initial re-check-in |
1 |
#!/usr/bin/python
|
2 |
# This tool attempts to balance out +/- lines in the same or
|
|
3 |
# adjacent diff chunks. When doing parallel builds, output
|
|
4 |
# frequently gets out of order, needlessly filling the diff
|
|
5 |
# with harmless changes. This, in theory, will help to reduce
|
|
6 |
# that kind of noise when run on the output of
|
|
7 |
# $UST/build-tools/buildlog-compare
|
|
8 |
#
|
|
9 |
# Copyright (C) 2009, Canonical Ltd.
|
|
10 |
# Author: Kees Cook <kees@ubuntu.com>
|
|
11 |
import sys |
|
12 |
||
13 |
def plus_minus_lines(hunk): |
|
14 |
plus = [] |
|
15 |
minus = [] |
|
16 |
ready = False |
|
17 |
for line in hunk.splitlines(): |
|
18 |
if line.startswith('@@'): |
|
19 |
ready = True |
|
20 |
continue
|
|
21 |
if not ready: |
|
22 |
continue
|
|
23 |
if line.startswith('-'): |
|
24 |
minus.append(line[1:]) |
|
25 |
elif line.startswith('+'): |
|
26 |
plus.append(line[1:]) |
|
27 |
return plus, minus |
|
28 |
||
29 |
class Hunk(object): |
|
30 |
def __init__(self, text): |
|
31 |
self.lines = text.splitlines() |
|
32 |
self.plus, self.minus = plus_minus_lines(text) |
|
33 |
# collapse against self
|
|
34 |
self.collapse(None) |
|
35 |
||
36 |
def has_plus(self, line): |
|
37 |
return (line in self.plus) |
|
38 |
||
39 |
def has_minus(self, line): |
|
40 |
return (line in self.minus) |
|
41 |
||
42 |
def is_empty(self): |
|
43 |
return (len(self.plus) + len(self.minus) == 0) |
|
44 |
||
45 |
def collapse(self, other): |
|
|
13
by Kees Cook
allow hunk collapse to reach back into full history |
46 |
reduced = False |
|
1
by Kees Cook
initial re-check-in |
47 |
#print >>sys.stderr, "Collapsing self to %s" % (other)
|
48 |
#self.dump("\tself: ")
|
|
49 |
#if other:
|
|
50 |
# other.dump("\tother: ")
|
|
51 |
lines = []+self.plus |
|
52 |
for line in lines: |
|
53 |
if self.has_minus(line): |
|
54 |
#print >>sys.stderr, "Dropping self '%s'" % (line.replace('\n',''))
|
|
55 |
self.drop_line('+'+line) |
|
56 |
self.drop_line('-'+line) |
|
57 |
#self.dump("\t")
|
|
|
13
by Kees Cook
allow hunk collapse to reach back into full history |
58 |
reduced = True |
|
1
by Kees Cook
initial re-check-in |
59 |
if other != None: |
60 |
lines = []+self.plus |
|
61 |
for line in lines: |
|
62 |
if other.has_minus(line): |
|
63 |
#print >>sys.stderr, "Dropping other '%s'" % (line.replace('\n',''))
|
|
64 |
self.drop_line('+'+line) |
|
65 |
other.drop_line('-'+line) |
|
66 |
#self.dump("\tself: ")
|
|
67 |
#other.dump("\tother: ")
|
|
|
13
by Kees Cook
allow hunk collapse to reach back into full history |
68 |
reduced = True |
|
1
by Kees Cook
initial re-check-in |
69 |
lines = []+self.minus |
70 |
for line in lines: |
|
71 |
if other.has_plus(line): |
|
72 |
#print >>sys.stderr, "Dropping other '%s'" % (line.replace('\n',''))
|
|
73 |
self.drop_line('-'+line) |
|
74 |
other.drop_line('+'+line) |
|
75 |
#self.dump("\tself: ")
|
|
76 |
#other.dump("\tother: ")
|
|
|
13
by Kees Cook
allow hunk collapse to reach back into full history |
77 |
reduced = True |
78 |
return reduced |
|
|
1
by Kees Cook
initial re-check-in |
79 |
|
80 |
def drop_line(self, line): |
|
81 |
# Remove from diff lines
|
|
82 |
index = self.lines.index(line) |
|
83 |
if index<0: |
|
84 |
return
|
|
85 |
self.lines.pop(index) |
|
86 |
||
87 |
# Remove from plus/minus arrays
|
|
88 |
if line.startswith('-'): |
|
89 |
index = self.minus.index(line[1:]) |
|
90 |
if index>=0: |
|
91 |
self.minus.pop(index) |
|
92 |
elif line.startswith('+'): |
|
93 |
index = self.plus.index(line[1:]) |
|
94 |
if index>=0: |
|
95 |
self.plus.pop(index) |
|
96 |
||
97 |
def dump(self, prefix=""): |
|
98 |
ready = False |
|
99 |
for line in self.lines: |
|
100 |
if line.startswith('@@') and self.is_empty(): |
|
101 |
break
|
|
102 |
print prefix + line |
|
103 |
||
104 |
collector = "" |
|
105 |
minus = 0 |
|
106 |
plus = 0 |
|
107 |
counting = False |
|
108 |
||
|
13
by Kees Cook
allow hunk collapse to reach back into full history |
109 |
hunks = [] |
|
1
by Kees Cook
initial re-check-in |
110 |
|
111 |
for line in sys.stdin: |
|
112 |
if line.startswith('@@'): |
|
113 |
at1, minus, plus, at2 = line.split(' ') |
|
114 |
minus = int(minus.split(',')[1]) |
|
115 |
plus = int(plus.split(',')[1]) |
|
116 |
collector += line |
|
117 |
counting = True |
|
118 |
continue
|
|
119 |
if not counting: |
|
120 |
collector += line |
|
121 |
continue
|
|
122 |
else: |
|
123 |
collector += line |
|
124 |
if line.startswith('-'): |
|
125 |
minus = minus - 1 |
|
126 |
elif line.startswith('+'): |
|
127 |
plus = plus - 1 |
|
128 |
elif line.startswith(' '): |
|
129 |
minus = minus - 1 |
|
130 |
plus = plus - 1 |
|
131 |
else: |
|
132 |
# Broken patch!
|
|
133 |
raise ValueError, "Corrupted patch? '%s'" % (line.replace('\n','')) |
|
134 |
if minus == 0 and plus == 0: |
|
135 |
# HUNK FINISHED
|
|
136 |
counting = False |
|
|
13
by Kees Cook
allow hunk collapse to reach back into full history |
137 |
hunks.append(Hunk(collector)) |
|
1
by Kees Cook
initial re-check-in |
138 |
collector = "" |
|
13
by Kees Cook
allow hunk collapse to reach back into full history |
139 |
|
140 |
while len(hunks)>1 and hunks[-1].collapse(hunks[-2]): |
|
141 |
# Remove prior hunks if they become empty
|
|
142 |
if hunks[-2].is_empty(): |
|
143 |
hunks.pop(-2) |
|
144 |
# Remove empty hunks from the end
|
|
145 |
while len(hunks)>0 and hunks[-1].is_empty(): |
|
146 |
hunks.pop() |
|
147 |
||
148 |
for i in range(0, len(hunks)): |
|
149 |
hunks[i].dump() |