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