4 # Read through a set of patches and see how many of them are fixes
7 # git log master..stable | stablefixes
9 # As with most gitdm stuff, this has been developed to the point where it
10 # solved the immediate task and no further. I hope it's useful, but can
13 # Copyright 2016 Eklektix, Inc.
14 # Copyright 2016 Jonathan Corbet <corbet@lwn.net>
16 # Redistributable under GPLv2
19 import sys, re, subprocess
30 # Patterns to snarf the info we're after.
31 # The {6,} in p_fixes is entirely to defend us against 8b9c6b28312cc,
32 # which reads "Fixes: 2.3.43".
34 p_fixes = re.compile(r'^\s+Fixes:\s+(commit\s+)?([0-9a-f]{6,}).*$')
35 p_revert = re.compile(r'This reverts commit ([0-9a-f]+)( +which is)?')
36 p_upstream = re.compile(r'commit ([0-9a-f]+) upstream', re.I)
37 p_upstream2 = re.compile(r'upstream commit ([0-9a-f]+)', re.I)
39 # Snarf the references to other patches.
41 def SaveFix(fixer, fixee):
43 if SameCommit(seen, fixer):
47 FixMap[fixer].append(fixee)
49 FixMap[fixer] = [ fixee ]
53 # Look for a straightforward Fixes: line.
55 for line in patch.taglines:
56 m = p_fixes.match(line)
58 SaveFix(patch.commit, m.group(2))
60 # Or perhaps this commit is a revert?
63 m = p_revert.search(patch.changelog)
65 SaveFix(patch.commit, m.group(1))
66 Reverts.append(patch.commit)
69 # In any case keep track of upstream patch corresponding to this one. But be
70 # careful about "this reverts ... which is ... upstream"
73 m = p_upstream.search(patch.changelog) or p_upstream2.search(patch.changelog)
75 Ids.append(m.group(1))
76 UpstreamMap[m.group(1)] = patch.commit
78 UpstreamMissing.append(patch.commit)
81 # See if two commit IDs match.
83 def SameCommit(c1, c2):
84 l = min(len(c1), len(c2))
85 return c1[:l] == c2[:l]
88 # What's the URL of a patch in the stable tree?
90 SBase = 'https://git.kernel.org/cgit/linux/kernel/git/stable/' + \
91 'linux-stable.git/commit?id='
96 # Get the version for a commit
98 repo = '/k/git/kernel'
99 def find_version(commit):
100 command = ['git', 'describe', '--contains', commit, '--match', 'v*']
101 p = subprocess.Popen(command, cwd = repo, stdout = subprocess.PIPE,
103 desc = p.stdout.readline().decode('utf8')
106 # The description line has the form:
110 tilde = desc.find('~')
119 # Go through the patch stream.
121 input = open(0, 'rb')
122 patch = gitlog.grabpatch(input)
125 Ids.append(patch.commit)
127 patch = gitlog.grabpatch(input)
129 TableHdr = '''<tr><th rowspan=2>Type</th>
130 <th colspan=2>Introduced</th>
131 <th colspan=2>Fixed</th></tr>
132 <tr><th>Release</th><th>Commit</th><th>Release</th><th>Commit</th></tr>
136 # Now see how many fixes have been seen before.
138 out = open('stable-fixes.html', 'w')
139 out.write('<!-- Found %d patches, %d fixes, %d reverts -->\n' % (Npatches, len(Fixes), len(Reverts)))
140 out.write('<!-- %d had no upstream reference -->\n' % (len(UpstreamMissing)))
141 out.write('<table class="OddEven">\n')
143 fixed_in_same = nfound = 0
145 # Go through all of the commit IDs we've seen (both stable and upstream)
146 # in reverse-time order.
148 def StablePatch(commit):
150 if SameCommit(commit, id):
152 return UpstreamMap[id]
158 for i in range(0, len(Fixes)):
160 print('Checking %d/%d, found %d ' % (i, len(Fixes), nfound), end = '\r')
164 # We know we have a fix, but does it fix something that showed up in stable?
166 for fixed in FixMap[fix]:
167 fixed = StablePatch(fixed)
170 v_id = find_version(fixed)
171 v_fixer = find_version(fix)
175 out.write('<tr><td>%s</td><td>%s</td>\n'
176 '<td><a href="%s"><tt>%s</tt></a></td>\n'
178 '<td><a href="%s"><tt>%s</tt></a></td></tr>\n'
179 % (type, v_id, StableURL(fixed), trim(fixed),
180 v_fixer, StableURL(fix), trim(fix)))
184 out.write('</table>')
185 out.write('<!-- Found %d refixes, %d in same release -->\n' % (nfound,