[Concept,2/7] qconfig: Auto-rebuild stale database for -f queries

Message ID 20260329111037.1352652-3-sjg@u-boot.org
State New
Headers
Series qconfig: Use kconfiglib for database build and defconfig sync |

Commit Message

Simon Glass March 29, 2026, 11:10 a.m. UTC
  From: Simon Glass <sjg@chromium.org>

The -f (find) option calls read_database() directly, which crashes if
the database does not exist and silently returns stale data if Kconfig
or defconfig files have changed since the last build.

Add a db_is_current() check that compares the database timestamp
against all Kconfig and defconfig files, similar to output_is_new() in
buildman/boards.py. Use this in ensure_database() so that both -f and
buildman's callers get automatic rebuilds when the database is stale.

Wire do_find_config() through ensure_database() instead of
read_database() so that -f benefits from this.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 tools/qconfig.py | 45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)
  

Patch

diff --git a/tools/qconfig.py b/tools/qconfig.py
index 4e06bfec88b..1e1f74a0c85 100755
--- a/tools/qconfig.py
+++ b/tools/qconfig.py
@@ -1289,9 +1289,11 @@  def find_config(dbase, config_list):
 
     return result
 
-def do_find_config(config_list, list_format):
+def do_find_config(config_list, list_format, jobs):
     """Find boards with a given combination of CONFIGs
 
+    Rebuilds the database automatically if it is missing or stale.
+
     Args:
         config_list (list of str): List of CONFIG options to check (each a regex
             consisting of a config option, with or without a CONFIG_ prefix. If
@@ -1299,11 +1301,12 @@  def do_find_config(config_list, list_format):
             otherwise it must be true)
         list_format (bool): True to write in 'list' format, one board name per
             line
+        jobs (int): Number of threads to use if the database needs rebuilding
 
     Returns:
         int: exit code (0 for success)
     """
-    dbase = read_database()
+    dbase = ensure_database(jobs)
     out = find_config(dbase, config_list)
     if not list_format:
         print(f'{len(out)} matches')
@@ -1840,11 +1843,37 @@  def do_tests():
     return 0
 
 
+def db_is_current():
+    """Check if the CONFIG database is up to date
+
+    Returns:
+        bool: True if the database exists and is newer than all Kconfig and
+            defconfig files
+    """
+    if not os.path.exists(CONFIG_DATABASE):
+        return False
+
+    db_time = os.path.getctime(CONFIG_DATABASE)
+
+    for dirpath, _, filenames in os.walk('configs'):
+        for fname in fnmatch.filter(filenames, '*_defconfig'):
+            if db_time < os.path.getctime(os.path.join(dirpath, fname)):
+                return False
+
+    for dirpath, _, filenames in os.walk('.'):
+        for fname in filenames:
+            if fname.startswith('Kconfig'):
+                if db_time < os.path.getctime(os.path.join(dirpath, fname)):
+                    return False
+
+    return True
+
+
 def ensure_database(threads):
-    """Return a qconfig database so that Kconfig options can be queried
+    """Return a qconfig database, rebuilding it if stale or missing
 
-    If a database exists, it is assumed to be up-to-date. If not, one is built,
-    which can take a few minutes.
+    Checks whether the database is newer than all Kconfig and defconfig files.
+    If not, it is rebuilt automatically.
 
     Args:
         threads (int): Number of threads to use when processing
@@ -1862,8 +1891,8 @@  def ensure_database(threads):
                 key: CONFIG option
                 value: set of boards using that option
     """
-    if not os.path.exists(CONFIG_DATABASE):
-        print('Building qconfig.db database')
+    if not db_is_current():
+        print('Building qconfig.db database...')
         args = Namespace(build_db=True, verbose=False, force_sync=False,
                          dry_run=False, exit_on_error=False, jobs=threads,
                          git_ref=None, defconfigs=None, defconfiglist=None,
@@ -1893,7 +1922,7 @@  def main():
             sys.exit(1)
         return 0
     if args.find:
-        return do_find_config(args.configs, args.list)
+        return do_find_config(args.configs, args.list, args.jobs)
 
     if args.build_db:
         config_db, progress = do_build_db(args)