findmissing: Improve SHA matching using SQL queries
SHAs provided by the command line need to be matched against kernel_sha
and fixedby_upstream_sha in the two fixes tables. So far we used
get_fix_status_and_changeid_from_list() to first evaluate if a SHA is
an upstream SHA (fixedby_upstream_sha) or a ChromeOS/stable release SHA
(kernel_sha). In general it is either/or. This means we can use SQL
queries "kernel_sha IN (sha_list)" and "fixedby_upstream_sha in
(sha_list)" to find the SHAs in the database. Only question is if to use
ther AND or the OR operator when searching for entries with kernel_sha
and/or fixedby_upstream_sha. As it turns out, this is straightforward:
- For "abandon" and "restore" commands, we have one or two SHAs.
- If the user provided one SHA, it can be a kernel_sha or a
fixedby_upstream_sha, and we need to use the OR operator.
- If the user provided two SHAs, expectation is that one is a kernel_sha
and one is a fixedby_upstream_sha. Use the AND operator in this case.
- For the "status" command, we want to list SHAs found anywhere.
Use the "OR" operator.
To implement this,
- Replace "kernel_sha" and "fixedby_upstream_sha" arguments to
get_fix_status_and_changeid() with a list of SHAs.
- Replace query
[kernel_sha = <kernel_sha>] [AND]
[fixedby_upstream_sha = <fixedby_upstream_sha>]
with
kernel_sha IN (sha_list) {AND,OR} fixedby_upstream_sha IN (sha_list)
- Pass "strict" argument to get_fix_status_and_changeid() to determine
if the search needs to match both kernel_sha and fixedby_upstream_sha
(AND) or if any match is sufficient (OR).
With this change, get_fix_status_and_changeid_from_list() and the query
of the linux_upstream table for each SHA is no longer needed. Also, we no
longer need to examine SHAs one by one in status_fix_cl() but can pass
the entire SHA list provided by the user to get_fix_status_and_changeid().
BUG=None
TEST=Run various findmissing commands
Change-Id: I959b80ec2e7eb7f428162aeab7c405ceecc6ce5f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/2319574
Commit-Queue: Guenter Roeck <groeck@chromium.org>
Tested-by: Guenter Roeck <groeck@chromium.org>
Reviewed-by: Curtis Malainey <cujomalainey@chromium.org>
diff --git a/contrib/findmissing/cloudsql_interface.py b/contrib/findmissing/cloudsql_interface.py
index f377956..a5874ad 100755
--- a/contrib/findmissing/cloudsql_interface.py
+++ b/contrib/findmissing/cloudsql_interface.py
@@ -47,21 +47,25 @@
return (row['kernel_sha'], row['fixedby_upstream_sha'])
-def get_fix_status_and_changeid(db, fixes_tables, kernel_sha, fixedby_upstream_sha):
+def get_fix_status_and_changeid(db, fixes_tables, sha_list, strict):
"""Get branch, fix_change_id, initial_status and status for one or more rows in fixes table."""
c = db.cursor(MySQLdb.cursors.DictCursor)
+ # If sha_list has only one entry, there will be only one database match.
+ # Use OR in the query if this is the case.
+ if len(sha_list) < 2:
+ strict = False
+
pre_q = """SELECT '{fixes_table}' AS 'table', branch, kernel_sha, fixedby_upstream_sha,
fix_change_id, initial_status, status
FROM {fixes_table}
WHERE """
- if kernel_sha:
- pre_q += ' kernel_sha = "%s"' % kernel_sha
- if fixedby_upstream_sha:
- pre_q += ' AND'
- if fixedby_upstream_sha:
- pre_q += ' fixedby_upstream_sha = "%s"' % fixedby_upstream_sha
+ joined_list = str(tuple(sha_list))
+
+ pre_q += ' kernel_sha IN %s' % joined_list
+ pre_q += ' AND' if strict else ' OR'
+ pre_q += ' fixedby_upstream_sha IN %s' % joined_list
q = pre_q.format(fixes_table=fixes_tables.pop(0))
while fixes_tables:
@@ -72,35 +76,6 @@
return c.fetchall()
-def get_fix_status_and_changeid_from_list(db, fixes_tables, sha_list):
- """Get branch, fix_change_id, initial_status and status for one or more rows in fixes table.
-
- The SHA or SHAs to identify commits are provided as anonymous SHA list. SHAs may either
- be from the upstream kernel or from the ChromeOS kernel. One or two SHAs must be provided.
- If there is one SHA, it must ieither be from the upstream kernel or from a ChromeOS branch.
- If there are two SHAs, one must be from the upstream kernel, the other must be from a ChromeOS
- branch.
- """
- c = db.cursor(MySQLdb.cursors.DictCursor)
- # find out which SHA is which
- kernel_sha = None
- fixedby_upstream_sha = None
- q = """SELECT sha FROM linux_upstream
- WHERE sha = %s"""
- c.execute(q, [sha_list[0]])
- if c.fetchone():
- # First SHA is upstream SHA
- fixedby_upstream_sha = sha_list[0]
- if len(sha_list) > 1:
- kernel_sha = sha_list[1]
- else:
- kernel_sha = sha_list[0]
- if len(sha_list) > 1:
- fixedby_upstream_sha = sha_list[1]
-
- return get_fix_status_and_changeid(db, fixes_tables, kernel_sha, fixedby_upstream_sha)
-
-
def update_change_abandoned(db, fixes_table, kernel_sha, fixedby_upstream_sha, reason=None):
"""Updates fixes_table unique fix row to indicate fix cl has been abandoned.
@@ -119,7 +94,7 @@
def update_change_restored(db, fixes_table, kernel_sha, fixedby_upstream_sha, reason=None):
"""Updates fixes_table unique fix row to indicate fix cl has been reopened."""
- rows = get_fix_status_and_changeid(db, [fixes_table], kernel_sha, fixedby_upstream_sha)
+ rows = get_fix_status_and_changeid(db, [fixes_table], [kernel_sha, fixedby_upstream_sha], True)
row = rows[0]
status = 'OPEN' if row['fix_change_id'] else row['initial_status']
diff --git a/contrib/findmissing/main.py b/contrib/findmissing/main.py
index c0abd42..9cf6713 100755
--- a/contrib/findmissing/main.py
+++ b/contrib/findmissing/main.py
@@ -57,7 +57,7 @@
row['branch'], row['kernel_sha'], row['fixedby_upstream_sha'], row['status']))
-def get_fixes_rows(cloudsql_db, fixes_table, sha_list):
+def get_fixes_rows(cloudsql_db, fixes_table, sha_list, strict):
"""Get all table rows for provided fixes table, or for both tables if none is proviced."""
if not fixes_table:
@@ -65,8 +65,8 @@
else:
fixes_tables = [fixes_table]
- return cloudsql_interface.get_fix_status_and_changeid_from_list(cloudsql_db, fixes_tables,
- sha_list)
+ return cloudsql_interface.get_fix_status_and_changeid(cloudsql_db, fixes_tables, sha_list,
+ strict)
@util.cloud_sql_proxy_decorator
@@ -76,7 +76,7 @@
cloudsql_db = MySQLdb.Connect(user='linux_patches_robot', host='127.0.0.1', db='linuxdb')
try:
- rows = get_fixes_rows(cloudsql_db, fixes_table, sha_list)
+ rows = get_fixes_rows(cloudsql_db, fixes_table, sha_list, True)
if not rows:
print('Patch identified by "%s" not found in fixes table(s)' % sha_list)
sys.exit(1)
@@ -120,8 +120,7 @@
rows = []
# Remove duplicate SHAs
sha_list = list(set(sha_list))
- for sha in sha_list:
- rows += get_fixes_rows(db, fixes_table, [sha])
+ rows = get_fixes_rows(db, fixes_table, sha_list, False)
if not rows:
print('No patches identified by "%s" found in fixes table(s)' % sha_list)
else:
@@ -136,7 +135,7 @@
"""Restores an abandoned change + updates database fix table."""
cloudsql_db = MySQLdb.Connect(user='linux_patches_robot', host='127.0.0.1', db='linuxdb')
try:
- rows = get_fixes_rows(cloudsql_db, fixes_table, sha_list)
+ rows = get_fixes_rows(cloudsql_db, fixes_table, sha_list, True)
if not rows:
print('Patch identified by "%s" not found in fixes table(s)' % sha_list)
sys.exit(1)