~ubuntu-security/ubuntu-security-tools/trunk

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()