blob: cd059f47a911aae4546668e92eca86c35beffc63 [file] [log] [blame]
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -08001#!/usr/bin/env python3
2# -*- coding: utf-8 -*-"
3#
4# Copyright 2020 The Chromium OS Authors. All rights reserved.
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Module parses and stores mainline linux patches to be easily accessible."""
9
10from __future__ import print_function
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -080011import os
12import re
13import sqlite3
14import subprocess
Hirthanan Subenderan00f18042020-02-11 17:24:38 -080015
16from common import WORKDIR, UPSTREAMDB, createdb, UPSTREAM_PATH, SUPPORTED_KERNELS
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -080017
18
Hirthanan Subenderan00f18042020-02-11 17:24:38 -080019UPSTREAM_BASE = 'v' + SUPPORTED_KERNELS[0]
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -080020
21RF = re.compile(r'^\s*Fixes: (?:commit )*([0-9a-f]+).*')
22RDESC = re.compile(r'.* \("([^"]+)"\).*')
23
24
25def make_tables(c):
26 """Initializes the upstreamdb tables."""
27 # Upstream commits
28 c.execute('CREATE TABLE commits (sha text, description text)')
29 c.execute('CREATE UNIQUE INDEX commit_sha ON commits (sha)')
30
31 # Fixes associated with upstream commits. sha is the commit, fsha is its fix.
32 # Each sha may have multiple fixes associated with it.
33 c.execute('CREATE TABLE fixes \
34 (sha text, fsha text, patchid text, ignore integer)')
35 c.execute('CREATE INDEX sha ON fixes (sha)')
36
37
38def handle(start):
39 """Parses git logs and builds upstreamdb tables."""
40 conn = sqlite3.connect(UPSTREAMDB)
41 conn.text_factory = str
42 c = conn.cursor()
43 c2 = conn.cursor()
44
45 commits = subprocess.check_output(['git', 'log', '--abbrev=12', '--oneline',
46 '--no-merges', '--reverse', start+'..'])
47 for commit in commits.decode('utf-8').splitlines():
48 if commit != '':
49 elem = commit.split(' ', 1)
50 sha = elem[0]
51 last = sha
52
53 # skip if SHA is already in database. This will happen
54 # for the first SHA when the script is re-run.
55 c.execute("select sha from commits where sha is '%s'" % sha)
56 if c.fetchone():
57 continue
58
59 description = elem[1].rstrip('\n')
60 c.execute('INSERT INTO commits(sha, description) VALUES (?, ?)',
61 (sha, description))
62 # check if this patch fixes a previous patch.
63 subprocess_cmd = ['git', 'show', '-s', '--pretty=format:%b', sha]
64 description = subprocess.check_output(subprocess_cmd).decode('utf-8')
65 for d in description.splitlines():
66 m = RF.search(d)
67 fsha = None
68 if m and m.group(1):
69 try:
70 # Normalize fsha to 12 characters
71 cmd = 'git show -s --pretty=format:%%H %s' % m.group(1)
72 fsha = subprocess.check_output(cmd.split(' '),
73 stderr=subprocess.DEVNULL).decode('utf-8')
74 except subprocess.CalledProcessError:
75 print("Commit '%s' for SHA '%s': "
76 'Not found' % (m.group(0), sha))
77 m = RDESC.search(d)
78 if m:
79 desc = m.group(1)
80 desc = desc.replace("'", "''")
81 c2.execute('select sha from commits where '
82 "description is '%s'" % desc)
83 fsha = c2.fetchone()
84 if fsha:
85 fsha = fsha[0]
86 print(" Real SHA may be '%s'" % fsha)
87 # The Fixes: tag may be wrong. The sha may not be in the
88 # upstream kernel, or the format may be completely wrong
89 # and m.group(1) may not be a sha in the first place.
90 # In that case, do nothing.
91 if fsha:
92 print('Commit %s fixed by %s' % (fsha[0:12], sha))
93 # Calculate patch ID for fixing commit.
94 ps = subprocess.Popen(['git', 'show', sha],
95 stdout=subprocess.PIPE)
96 spid = subprocess.check_output(['git', 'patch-id'],
97 stdin=ps.stdout).decode('utf-8', errors='ignore')
98 patchid = spid.split(' ', 1)[0]
99
100 # Insert in reverse order: sha is fixed by fsha.
101 # patchid is the patch ID associated with fsha (in the db).
102 c.execute('INSERT into fixes (sha, fsha, patchid, ignore) '
103 'VALUES (?, ?, ?, ?)',
104 (fsha[0:12], sha, patchid, 0))
105
106 if last:
107 c.execute("UPDATE tip set sha='%s' where ref=1" % last)
108
109 conn.commit()
110 conn.close()
111
112
113def update_upstreamdb():
114 """Updates the upstreamdb database."""
115 start = UPSTREAM_BASE
116
117 try:
118 # see if we previously handled anything. If yes, use it.
119 # Otherwise re-create database
120 conn = sqlite3.connect(UPSTREAMDB)
121 conn.text_factory = str
122 c = conn.cursor()
123 c.execute('select sha from tip')
124 sha = c.fetchone()
125 conn.close()
126 if sha and sha[0] != '':
127 start = sha[0]
128 except sqlite3.Error:
129 createdb(UPSTREAMDB, make_tables)
130
131 os.chdir(UPSTREAM_PATH)
132 subprocess.check_output(['git', 'pull'])
133
134 handle(start)
135
136 os.chdir(WORKDIR)
137
138
139if __name__ == '__main__':
140 update_upstreamdb()