diff mbox series

[AUH,v2,1/9] upgrade-helper.py: Add compatibility with Yocto scarthgap

Message ID 20260424114603.2444938-2-daniel.turull@ericsson.com
State New
Headers show
Series upgrade_helper: scarthgap compatibility, stable updates and changelog extraction | expand

Commit Message

Daniel Turull April 24, 2026, 11:45 a.m. UTC
From: Daniel Turull <daniel.turull@ericsson.com>

- Handle flat tuple format from get_recipe_upgrade_status (scarthgap)
  in addition to the list-of-dicts format (master)
- Fallback to MACHINE env var when bitbake-config-build is not available
- Resolve symlinks in recipe_dir with os.path.realpath()

Signed-off-by: Daniel Turull <daniel.turull@ericsson.com>
Assisted-by: Claude, Anthropic
---
 modules/steps.py         | 2 +-
 modules/utils/bitbake.py | 8 ++++++--
 upgrade-helper.py        | 9 +++++++++
 3 files changed, 16 insertions(+), 3 deletions(-)

Comments

Alexander Kanavin April 27, 2026, 11:01 a.m. UTC | #1
On Fri, 24 Apr 2026 at 13:46, <daniel.turull@ericsson.com> wrote:
> -        pkg_ctx['recipe_dir'] = os.path.dirname(pkg_ctx['env']['FILE'])
> +        pkg_ctx['recipe_dir'] = os.path.realpath(os.path.dirname(pkg_ctx['env']['FILE']))

This needs to be further explained.

> -        bb.process.run("bitbake-config-build enable-fragment machine/{}".format(machine))
> -        return self._cmd(recipe, env_var=env)
> +        try:
> +            bb.process.run("bitbake-config-build enable-fragment machine/{}".format(machine))
> +        except bb.process.ExecutionError:
> +            # bitbake-config-build not available (e.g. scarthgap), use MACHINE env var
> +            env = "MACHINE={} {}".format(machine, env).strip()
> +        return self._cmd(recipe, env_var=env if env else None)

The condition needs to be 'bitbake-config-build doesn't exist', not
that it failed to execute (e.g. returned a non-zero).

>              for group in pkggroups:
> +
> +                # Scarthgap returns flat tuples; normalize to list-of-dicts
> +                # so the existing loop handles both formats.
> +                if not isinstance(group, (list, tuple)) or not group or not isinstance(group[0], dict):
> +                    pn, status, cur_ver, next_ver, maintainer, revision, no_upgrade_reason = group
> +                    group = [{'pn': pn, 'status': status, 'cur_ver': cur_ver,
> +                              'next_ver': next_ver, 'maintainer': maintainer,
> +                              'revision': revision, 'no_upgrade_reason': no_upgrade_reason}]

Can the condition be inverted, e.g. be checked for the 'old' format?
I'm not sure I understand why 'old' format is determined by any of
three different conditions being true, especially 'not group' looks
incorrect.

Alex
Daniel Turull April 27, 2026, 1:34 p.m. UTC | #2
> -----Original Message-----
> From: Alexander Kanavin <alex.kanavin@gmail.com>
> Sent: Monday, 27 April 2026 13:02
> To: Daniel Turull <daniel.turull@ericsson.com>
> Cc: yocto-patches@lists.yoctoproject.org; paul@pbarker.dev;
> ross.burton@arm.com; yoann.congal@smile.fr
> Subject: Re: [AUH][PATCH v2 1/9] upgrade-helper.py: Add compatibility with
> Yocto scarthgap
> 
> On Fri, 24 Apr 2026 at 13:46, <daniel.turull@ericsson.com> wrote:
> > -        pkg_ctx['recipe_dir'] = os.path.dirname(pkg_ctx['env']['FILE'])
> > +        pkg_ctx['recipe_dir'] =
> > + os.path.realpath(os.path.dirname(pkg_ctx['env']['FILE']))
> 
> This needs to be further explained.

In our layout, meta is a symlink (meta -> openembedded-core/meta), so pkg_ctx['env']['FILE'] returns a path through the symlink. Later, git add on that path fails because the git repo is at the resolved openembedded-core/ path. I'll expand the commit message to explain this.
> 
> > -        bb.process.run("bitbake-config-build enable-fragment
> machine/{}".format(machine))
> > -        return self._cmd(recipe, env_var=env)
> > +        try:
> > +            bb.process.run("bitbake-config-build enable-fragment
> machine/{}".format(machine))
> > +        except bb.process.ExecutionError:
> > +            # bitbake-config-build not available (e.g. scarthgap), use MACHINE
> env var
> > +            env = "MACHINE={} {}".format(machine, env).strip()
> > +        return self._cmd(recipe, env_var=env if env else None)
> 
> The condition needs to be 'bitbake-config-build doesn't exist', not that it
> failed to execute (e.g. returned a non-zero).

I'll change it to check shutil.which('bitbake-config-build') instead of catching ExecutionError.

> 
> >              for group in pkggroups:
> > +
> > +                # Scarthgap returns flat tuples; normalize to list-of-dicts
> > +                # so the existing loop handles both formats.
> > +                if not isinstance(group, (list, tuple)) or not group or not
> isinstance(group[0], dict):
> > +                    pn, status, cur_ver, next_ver, maintainer, revision,
> no_upgrade_reason = group
> > +                    group = [{'pn': pn, 'status': status, 'cur_ver': cur_ver,
> > +                              'next_ver': next_ver, 'maintainer': maintainer,
> > +                              'revision': revision,
> > + 'no_upgrade_reason': no_upgrade_reason}]
> 
> Can the condition be inverted, e.g. be checked for the 'old' format?
> I'm not sure I understand why 'old' format is determined by any of three
> different conditions being true, especially 'not group' looks incorrect.

Sure, Scarthgap's _get_recipe_upgrade_status returns a flat tuple of 7 elements, while master returns a list of dicts. I'll simplify it.
> 
> Alex

Thanks for the feedback. I'll updated in v3

Daniel
diff mbox series

Patch

diff --git a/modules/steps.py b/modules/steps.py
index a6ec341..b3ec61c 100644
--- a/modules/steps.py
+++ b/modules/steps.py
@@ -36,7 +36,7 @@  def load_env(devtool, bb, git, opts, group):
     os.mkdir(group['workdir'])
     for pkg_ctx in group['pkgs']:
         pkg_ctx['env'] = bb.env(pkg_ctx['PN'])
-        pkg_ctx['recipe_dir'] = os.path.dirname(pkg_ctx['env']['FILE'])
+        pkg_ctx['recipe_dir'] = os.path.realpath(os.path.dirname(pkg_ctx['env']['FILE']))
 
 def buildhistory_init(devtool, bb, git, opts, group):
     if not opts['buildhistory']:
diff --git a/modules/utils/bitbake.py b/modules/utils/bitbake.py
index 5514c98..f6821bc 100644
--- a/modules/utils/bitbake.py
+++ b/modules/utils/bitbake.py
@@ -123,8 +123,12 @@  class Bitbake(object):
             env = "TCLIBC={}".format(libc)
         else:
             env = ""
-        bb.process.run("bitbake-config-build enable-fragment machine/{}".format(machine))
-        return self._cmd(recipe, env_var=env)
+        try:
+            bb.process.run("bitbake-config-build enable-fragment machine/{}".format(machine))
+        except bb.process.ExecutionError:
+            # bitbake-config-build not available (e.g. scarthgap), use MACHINE env var
+            env = "MACHINE={} {}".format(machine, env).strip()
+        return self._cmd(recipe, env_var=env if env else None)
 
     def dependency_graph(self, package_list):
         return self._cmd(package_list, "-g")
diff --git a/upgrade-helper.py b/upgrade-helper.py
index 40f31c4..aef7ed1 100755
--- a/upgrade-helper.py
+++ b/upgrade-helper.py
@@ -714,6 +714,15 @@  class UniverseUpdater(Updater):
             pkggroups = oe.recipeutils.get_recipe_upgrade_status(layer_recipes)
 
             for group in pkggroups:
+
+                # Scarthgap returns flat tuples; normalize to list-of-dicts
+                # so the existing loop handles both formats.
+                if not isinstance(group, (list, tuple)) or not group or not isinstance(group[0], dict):
+                    pn, status, cur_ver, next_ver, maintainer, revision, no_upgrade_reason = group
+                    group = [{'pn': pn, 'status': status, 'cur_ver': cur_ver,
+                              'next_ver': next_ver, 'maintainer': maintainer,
+                              'revision': revision, 'no_upgrade_reason': no_upgrade_reason}]
+
                 upgrade_group = []
                 for pkg in group:
                     maintainer = pkg['maintainer']