diff mbox series

data: Fix expandKeys recursion issue

Message ID 20260810144653.2803105-1-richard.purdie@linuxfoundation.org
State New
Headers show
Series data: Fix expandKeys recursion issue | expand

Commit Message

Richard Purdie Aug. 10, 2026, 2:46 p.m. UTC
Using an variable expansion in override such as:

RDEPENDS:${PN}:append:pn-packagegroup-cross-canadian-${MACHINE} = ' XXX'

wasn't functioning correctly. Looking through the code, renameVar does
work correctly but it doesn't work if called multiple times on the sub
components of the variable.

expandKeys will already recurse variables so we need to ensure renameVar
doesn't also do that as things break if we do it multiple times.

Change the code to avoid recursion in renameVar which should also have
a small performance improvement.

Test case from Nguyen Minh Tien <zizuzacker@gmail.com>

[YOCTO #14867]

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/bb/data.py       |  2 +-
 lib/bb/data_smart.py |  5 +++--
 lib/bb/tests/data.py | 25 +++++++++++++++++++++++++
 3 files changed, 29 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/lib/bb/data.py b/lib/bb/data.py
index 7c01e6bf81c..f81f44eaccd 100644
--- a/lib/bb/data.py
+++ b/lib/bb/data.py
@@ -94,7 +94,7 @@  def expandKeys(alterdata, readdata = None):
             val = alterdata.getVar(key, False)
             if val is not None:
                 bb.warn("Variable key %s (%s) replaces original key %s (%s)." % (key, val, ekey, newval))
-        alterdata.renameVar(key, ekey)
+        alterdata.renameVar(key, ekey, recurse=False)
 
 def inheritFromOS(d, savedenv, permitted):
     """Inherit variables from the initial environment."""
diff --git a/lib/bb/data_smart.py b/lib/bb/data_smart.py
index 9961269a3f8..cbace852021 100644
--- a/lib/bb/data_smart.py
+++ b/lib/bb/data_smart.py
@@ -661,7 +661,7 @@  class DataSmart(MutableMapping):
     def getVar(self, var, expand=True, noweakdefault=False, parsing=False):
         return self.getVarFlag(var, "_content", expand, noweakdefault, parsing)
 
-    def renameVar(self, key, newkey, **loginfo):
+    def renameVar(self, key, newkey, recurse=True, **loginfo):
         """
         Rename the variable key to newkey
         """
@@ -698,7 +698,8 @@  class DataSmart(MutableMapping):
             self.overridedata[newkey] = []
             for (v, o) in self.overridedata[key]:
                 self.overridedata[newkey].append([v.replace(key, newkey), o])
-                self.renameVar(v, v.replace(key, newkey))
+                if recurse:
+                    self.renameVar(v, v.replace(key, newkey))
 
         if not found:
             # No variable to rename so not worth the work in writing extra
diff --git a/lib/bb/tests/data.py b/lib/bb/tests/data.py
index a83c71e2c25..49177474778 100644
--- a/lib/bb/tests/data.py
+++ b/lib/bb/tests/data.py
@@ -406,6 +406,31 @@  class TestOverrides(unittest.TestCase):
         bb.data.expandKeys(self.d)
         self.assertEqual(self.d.getVar("VERSION"), "2")
 
+    # Test an :append whose override name is only resolved by key expansion
+    def test_append_in_expanded_override(self):
+        self.d.setVar("MACHINE", "qemux86")
+        self.d.setVar("PN", "gizmo")
+        self.d.setVar("OVERRIDES", "gizmo:pn-gizmo-qemux86")
+        self.d.setVar("TEST:${PN}", "base")
+        self.d.setVar("TEST:${PN}:append:pn-gizmo-${MACHINE}", " appended")
+        bb.data.expandKeys(self.d)
+        self.assertEqual(self.d.getVar("TEST"), "base appended")
+
+    # Test renaming to a key which is itself not expanded yet, as native.bbclass
+    # does. The dependent override keys must be left for expandKeys() to rename.
+    def test_rename_to_unexpanded_key_with_override(self):
+        self.d.setVar("BPN", "gizmo")
+        self.d.setVar("PN", "gizmo-native")
+        self.d.setVar("OVERRIDES", "class-target")
+        self.d.setVar("TEST:${PN}-lib", "base")
+        self.d.setVar("TEST:${PN}-lib:class-target", "target")
+        with LogRecord() as logs:
+            self.d.renameVar("TEST:${PN}-lib", "TEST:${BPN}-lib-native")
+            bb.data.expandKeys(self.d)
+            self.assertFalse(logContains("renameVar with equivalent keys", logs))
+            self.assertFalse(logContains("replaces original key", logs))
+        self.assertEqual(self.d.getVar("TEST:gizmo-lib-native"), "target")
+
     def test_remove_with_override(self):
         self.d.setVar("TEST:bar", "testvalue2")
         self.d.setVar("TEST:some_val", "testvalue3 testvalue5")