blob: 852aff77653fd58baf3cac3f7e8e3a1cdaffe8b0 [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"""Find missing stable and backported mainline fix patches in chromeos."""
9
10from __future__ import print_function
11import os
12import subprocess
13import sys
14import sqlite3
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -080015from enum import Enum
16
17import config
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080018from common import stabledb, UPSTREAMDB, stable_branch, chromeosdb, \
19 chromeos_branch, patch_link, patchdb_stable, patchdb_chromeos, createdb
20from patch import PatchEntry, Status, make_patch_table
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -080021
22
23class Path(Enum):
24 """Enum representing repo path as Stable or ChromeOS."""
25 stable = 1
26 chromeos = 2
27
28
29def get_status(sha):
30 """Check if patch needs to be applied to current branch.
31
32 The working directory and branch must be set when calling
33 this function.
34
35 Return 0 if the patch has already been applied,
36 1 if the patch is missing and applies cleanly,
37 2 if the patch is missing and fails to apply.
38 """
39 ret = 0
40
41 cmd = 'git reset --hard HEAD'
42 subprocess.run(cmd.split(' '), stdout=subprocess.DEVNULL,
43 stderr=subprocess.DEVNULL)
44
45 try:
46 # Returns 0 on success, else a non-zero status code
47 result = subprocess.call(['git', 'cherry-pick', '-n', sha],
48 stdout=subprocess.DEVNULL,
49 stderr=subprocess.DEVNULL)
50
51 if result:
52 ret = 2
53 else:
54 diff = subprocess.check_output(['git', 'diff', 'HEAD'])
55 if diff:
56 ret = 1
57 except subprocess.CalledProcessError:
58 ret = 2
59
60 cmd = 'git reset --hard HEAD'
61 subprocess.run(cmd.split(' '), stdout=subprocess.DEVNULL,
62 stderr=subprocess.DEVNULL)
63
64
65 return ret
66
67
68def usha_to_downstream_sha(sdb, usha):
69 """Retrieves chromeos/stable sha by indexing db.
70
71 Returns sha or None if upstream sha doesn't exist downstream.
72 """
73 cs = sdb.cursor()
74 cs.execute("SELECT sha from commits where usha is '%s'" % usha)
75 row = cs.fetchone()
76
77 return row[0] if row else None
78
79
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080080def get_context(bname, sdb, udb, pdb, usha, recursive):
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -080081 """Outputs dependency of patches and fixes needed in chromeOS."""
82 cs = sdb.cursor()
83 cu = udb.cursor()
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -080084 cp = pdb.cursor()
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -080085
86 cu.execute("select sha, description from commits where sha is '%s'" % usha)
87 found = False
88
89 for (sha, description) in cu.fetchall():
90 # usha -> sha maping should be 1:1
91 # If it isn't, skip duplicate entries.
92 if found:
93 print('Already found usha->sha mapping for %s , skipping row.' % sha)
94 continue
95 found = True
96 cu.execute("select fsha, patchid, ignore from fixes where sha='%s'" % usha)
97 # usha, however, may have multiple fixes
98 printed = recursive
99 for (fsha, patchid, ignore) in cu.fetchall():
100 if ignore:
101 continue
102 # Check if the fix (fsha) is in our code base or
103 # try to find it using its patch ID.
104 cs.execute("select sha, usha from commits \
105 where usha is '%s' or patchid is '%s'" % (fsha, patchid))
106 fix = cs.fetchone()
107 if not fix:
108 status = get_status(fsha)
109 if status != 0:
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800110 patch = PatchEntry(None, usha, fsha, None, None, None)
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -0800111 if not printed:
112 downstream_sha = usha_to_downstream_sha(sdb, usha)
113 print("\n[downstream_sha %s] [usha %s] ('%s')"
114 % (downstream_sha, usha, description))
115 printed = True
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800116
117 # Retrieve downstream changeid (stable will return None)
118 cs.execute("select changeid from commits \
119 where sha is '%s'" % downstream_sha)
120 downstream_changeid = cs.fetchone()
121 downstream_link = patch_link(downstream_changeid)
122
123 patch.set_downstream_sha(downstream_sha)
124
125 # Set the downstream link if dealing with chromeos branches
126 # since chromeos commits should have associated changeid
127 is_chromeos_branch = bname.startswith('chromeos')
128
129 # pylint: disable=expression-not-assigned
130 patch.set_downstream_link(downstream_link) if is_chromeos_branch else None
131
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -0800132 space_str = ' ' if recursive else ' '
133 print('%sCommit (upstream) %s fixed by commit (upstream) %s' %
134 (space_str, usha, fsha))
135 if status == 1:
136 print(' %sFix is missing from %s and applies cleanly'
137 % (space_str, bname))
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800138 # Create gerrit change ticket here
139 # if succesfully created set status to OPEN
140 fix_changeid = 0
141 fix_link = patch_link(fix_changeid)
142
143 patch.set_fix_link(fix_link)
144 patch.set_status(Status.NEW)
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -0800145 else:
146 print(' %sFix may be missing from %s; '
147 'trying to apply it results in conflicts/errors' %
148 (space_str, bname))
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800149
150 patch.set_status(Status.CONF)
151
152 cp.execute('INSERT INTO patches(downstream_sha, usha,' \
153 'fix_usha, downstream_link, fix_link, status)' \
154 ' VALUES (?, ?, ?, ?, ?, ?)',
155 (patch.downstream_sha, patch.usha,
156 patch.fsha, patch.downstream_link,
157 patch.fix_link, patch.status.name))
158 get_context(bname, sdb, udb, pdb, fsha, True)
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -0800159
160
161def missing(version, release):
162 """Look for missing Fixup commits in provided chromeos or stable release."""
163
164 bname = stable_branch(version) if release == Path.stable \
165 else chromeos_branch(version)
166
167 print('Checking branch %s' % bname)
168
169 subprocess.check_output(['git', 'checkout', bname], stderr=subprocess.DEVNULL)
170
171 chosen_db = stabledb(version) if release == Path.stable \
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800172 else chromeosdb(version)
173
174 patch_db = patchdb_stable(version) if release == Path.stable \
175 else patchdb_chromeos(version)
176
177 # resets patch table data since data may have changed
178 createdb(patch_db, make_patch_table)
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -0800179
180 sdb = sqlite3.connect(chosen_db)
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800181 pdb = sqlite3.connect(patch_db)
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -0800182 cs = sdb.cursor()
183 udb = sqlite3.connect(UPSTREAMDB)
184
185 cs.execute("select usha from commits where usha != ''")
186 for usha in cs.fetchall():
Hirthanan Subenderanb8402a12020-02-05 14:11:00 -0800187 get_context(bname, sdb, udb, pdb, usha[0], False)
188
189 pdb.commit()
190 pdb.close()
Hirthanan Subenderan3e884d62020-01-23 13:12:45 -0800191
192 udb.close()
193 sdb.close()
194
195
196def findmissing_helper(release):
197 """Helper to find missing patches in the stable and chromeos releases."""
198 if len(sys.argv) > 1:
199 branches = sys.argv[1:]
200 else:
201 branches = config.STABLE_BRANCHES if release == Path.stable \
202 else config.CHROMEOS_BRANCHES
203
204 path = config.STABLE_PATH if release == Path.stable \
205 else config.CHROMEOS_PATH
206 os.chdir(path)
207
208 for b in branches:
209 missing(b, release)
210
211
212def findmissing():
213 """Finds missing patches in stable and chromeos releases."""
214 cur_wd = os.getcwd()
215
216 print('--Missing patches from baseline -> stable.--')
217 findmissing_helper(Path.stable)
218
219 os.chdir(cur_wd)
220
221 print('--Missing patches from baseline -> chromeos.--')
222 findmissing_helper(Path.chromeos)
223
224
225if __name__ == '__main__':
226 findmissing()