summaryrefslogtreecommitdiffstats
path: root/aiaiai-diff-log-helper
blob: 464f6b92b43e8bdbdac7d56c2e919ced13049b99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Sort an compare 2 build logs.

Author: Ed Bartosh <eduard.bartosh@intel.com>
Licence: GPLv2
"""

# Sorts 2 build logs and compares them. Blocks can be as follows.
#
# 1. All consequitive lines starting with the same file prefix belong to one
# block, e.g.:
#
# drivers/s.c:472:22: warning: incorrect type in assignment (different address spaces) [sparse]
# drivers/s.c:472:22:    expected struct table_header *mapped_table [sparse]
# drivers/s.c:472:22:    got void [noderef] <asn:2>* [sparse]
#
# (the prefix is "drivers/s.c:472")
#
# 2. GCC 'In file included from' blocks look like this:
#
# In file included from include/linux/kernel.h:17:0,
#                  from include/linux/sched.h:55,
#                  from arch/arm/kernel/asm-offsets.c:13
# include/linux/bitops.h: In function 'hweight_long':
# include/linux/bitops.h:55:26: warning: signed and unsigned type in expression
#
# or
#
# In file included from arch/x86/include/asm/uaccess.h:570:0,
#                 from include/linux/uaccess.h:5,
#                 from include/linux/highmem.h:7,
#                 from include/linux/pagemap.h:10,
#                 from fs/binfmt_misc.c:26:
# In function ‘copy_from_user’,
#     inlined from ‘parse_command.part.0’ at fs/binfmt_misc.c:422:20:
# arch/x86/include/asm/uaccess_32.h:211:26: warning: call to ‘copy_from_user’
#
# 3. GCC 'In function' blocks look like this:
#
# drivers/i.c: In function ‘gluebi_erase’:
# drivers/i.c:177:2: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
#
# 4. Any other line comprises an independent block

import sys
import os
import re
import itertools

def gen_blocks(stream):
    """Parses input stream. Yields found blocks."""
    btype, prefix, block = "", "", []
    for line in stream:
        # append line to the current block if prefix matches
        if prefix and line.startswith(prefix):
            block.append(line)

        # Define prefix for cases 2 and 3 for further processing
        elif not prefix and btype in ("ifi", "infunc"):
            block.append(line)
            if re.match("^[^\s]+/[^\s]+:\d+:", line):
                prefix = ":".join(line.split(':')[:2])
        # 'In file inculded' block (case 2.)
        elif re.match("^In file included from .+", line):
            yield block
            btype = "ifi"
            prefix = ""
            block = [line]
        # 'In function' block (case 3.)
        elif re.match("^[^\s]+/[^\s]+: In function .+", line):
            yield block
            btype = "infunc"
            prefix = ""
            block = [line]
        # file prefixed block (case 1.)
        elif re.match("^[^\s]+/[^\s]+:\d+:", line):
            yield block
            prefix = ":".join(line.split(':')[:2])
            btype = "prefix"
            block = [line]
        # the rest (case 4.)
        else:
            yield block
            btype = "plain"
            prefix = ""
            block = [line]
    yield block

def main(argv):
    """Script entry point."""

    infile1, infile2 = open(argv[1]), open(argv[2])
    outfile = sys.stdout
    if len(argv) > 3:
        outfile = open(argv[3], "w")

    with open(argv[1]) as infile1, \
         open(argv[2]) as infile2:

        result = {}
        for blk1, blk2 in itertools.izip_longest(gen_blocks(infile1),
                              gen_blocks(infile2), fillvalue=[]):
            if blk1 == blk2:
                continue
            for block, sign in [(tuple(blk1), "-"), (tuple(blk2), "+")]:
                if block:
                    if block in result:
                        del result[block]
                    else:
                        result[block] = sign

        result = sorted(result.items())
        if result:
            print "--- before_patching.log"
            print "+++ after_patching.log"
            prefix = ""
            for block, sign in result:
                if not prefix or not block[0].startswith(prefix):
                    print "@@ @@"
                for line in block:
                    print "%s%s" % (sign, line),
                if re.match("^[^\s]+/[^\s]+:", block[0]):
                    prefix = block[0].split(':')[0]

    outfile.close()

if __name__ == "__main__":
    if len(sys.argv) == 1 or sys.argv[1] == "--help":
        print "Usage: %s <input log 1> <input log 2> [<diff file>]" % \
              os.path.basename(sys.argv[0])
        sys.exit(0)
    sys.exit(main(sys.argv))

# vim: ts=4 et sw=4 sts=4 ai sta: