[AUH][PATCH v3 4/4] upgrade-helper.py: Add resume option to skip already attempted recipes

<[email protected]>
Newsgroups org.yoctoproject.lists.yocto-patches
Message-ID <[email protected]>
From: Daniel Turull <[email protected]>

Add --resume option that checks the most recent run's succeed/ and
failed/ directories to determine which recipes were already attempted.

Symlinks in these directories are now created immediately after each
recipe is processed (rather than at the end of the run), so an
interrupted run still leaves behind the right state for --resume.

This allows restarting an interrupted run without re-processing recipes
that have already been handled, saving significant time on large runs
(e.g. 12h for 135 recipes).

Assisted-by: kiro:claude-opus-4.6
Signed-off-by: Daniel Turull <[email protected]>
---
 upgrade-helper.py | 48 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 10 deletions(-)

diff --git a/upgrade-helper.py b/upgrade-helper.py
index aecb207..e6ae77f 100755
--- a/upgrade-helper.py
+++ b/upgrade-helper.py
@@ -42,6 +42,7 @@ import re
 import signal
 import sys
 import configparser
+import glob
 from datetime import datetime
 from datetime import date
 import shutil
@@ -99,10 +100,12 @@ def parse_cmdline():
 
     parser.add_argument("-t", "--to_version",
                         help="version to upgrade the recipe to")
-
     parser.add_argument("--stable", action="store_true", default=False,
                         help="only upgrade to the next patch version within the stable branch (e.g. 1.2.3 -> 1.2.4)")
 
+    parser.add_argument("--resume", action="store_true", default=False,
+                        help="skip recipes already attempted in the last run")
+
     parser.add_argument("-d", "--debug-level", type=int, default=4, choices=range(1, 6),
                         help="set the debug level: CRITICAL=1, ERROR=2, WARNING=3, INFO=4, DEBUG=5")
     parser.add_argument("-e", "--send-emails", action="store_true", default=False,
@@ -493,10 +496,34 @@ class Updater(object):
         succeeded_pkggroups_ctx = []
         failed_pkggroups_ctx = []
         attempted_pkggroups = 0
+
+        # --resume: skip recipes already attempted in the most recent run
+        resume_skip = set()
+        if self.args.resume:
+            prev_runs = sorted(glob.glob(os.path.join(self.uh_dir, "20*")))
+            prev_runs = [r for r in prev_runs if r != self.uh_work_dir]
+            if prev_runs:
+                prev_dir = prev_runs[-1]
+                for d in ("succeed", "failed"):
+                    result_dir = os.path.join(prev_dir, d)
+                    if os.path.isdir(result_dir):
+                        resume_skip.update(os.listdir(result_dir))
+                if resume_skip:
+                    I(" --resume: skipping %d recipes from %s" %
+                      (len(resume_skip), prev_dir))
+            else:
+                W(" --resume: no previous run found, nothing to skip")
         for g in pkggroups_ctx:
             attempted_pkggroups += 1
             pkggroup_name = g["name"]
+
+            if g['name'] in resume_skip:
+                I(" SKIP PACKAGE GROUP %d/%d (already attempted): %s" %
+                  (attempted_pkggroups, total_pkggroups, pkggroup_name))
+                continue
+
             I(" ATTEMPT PACKAGE GROUP %d/%d" % (attempted_pkggroups, total_pkggroups))
+
             try:
                 for pkg_ctx in g['pkgs']:
                     I(" %s: Upgrading to %s" % (pkg_ctx['PN'], pkg_ctx['NPV']))
@@ -541,6 +568,15 @@ class Updater(object):
                     succeeded_pkggroups_ctx.remove(g)
                     failed_pkggroups_ctx.append(g)
 
+            # Create symlink immediately so --resume can find it
+            if 'workdir' in g:
+                if any(g['name'] == s['name'] for s in succeeded_pkggroups_ctx):
+                    link = os.path.join(self.uh_recipes_succeed_dir, g['name'])
+                else:
+                    link = os.path.join(self.uh_recipes_failed_dir, g['name'])
+                if not os.path.exists(link):
+                    os.symlink(g['workdir'], link)
+
         if self.opts['testimage']:
             ctxs = {}
             ctxs['succeeded'] = succeeded_pkggroups_ctx
@@ -551,15 +587,7 @@ class Updater(object):
 
             tim.run()
 
-        for g in pkggroups_ctx:
-
-            if g in succeeded_pkggroups_ctx:
-                os.symlink(g['workdir'], os.path.join( \
-                    self.uh_recipes_succeed_dir, g['name']))
-            else:
-                os.symlink(g['workdir'], os.path.join( \
-                    self.uh_recipes_failed_dir, g['name']))
-
+        for g in succeeded_pkggroups_ctx + failed_pkggroups_ctx:
             self.statistics.update(g)
             self.pkg_upgrade_handler(g)
 
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.