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:
|