diff mbox series

[kirkstone] bitbake: bitbake/codeparser.py fix python 3.6 compatibilty

Message ID 20240519143025.72402-1-adrian.freihofer@gmail.com
State New
Headers show
Series [kirkstone] bitbake: bitbake/codeparser.py fix python 3.6 compatibilty | expand

Commit Message

Adrian Freihofer May 19, 2024, 2:30 p.m. UTC
From: Adrian Freihofer <adrian.freihofer@siemens.com>

Commits
- d4ad54a401031346727ec6c1337f4b0211b5cc47
- 8ec4f29e432feec9d8deedc06bfb90d57e7436cf
break compatibility with Python 3.6. However, kirkstone is supposed to
be backward compatible which this old version.

Restore the old code if the Python version is less than 3.8. This adds
some not so nice code dublication. But the implementation like:
  if sys.version_info[:3] < (3,8,0):
      old code
  else:
      new code
makes it possible to fix the problem without much thought and without
the risk of new problems.

The issue can be reproduced e.g. in an old Ubuntu container by running:
  bitbake-selftest bb.tests.codeparser.PythonReferenceTest

It works with an older version of bibake:

$ git checkout kirkstone-4.0.16
$ podman run --rm -it --security-opt label=disable --userns=keep-id \
  -v /home/adrian/projets/oss/poky-wt-1:/home/yoctouser/workdir \
  crops/yocto:ubuntu-18.04-base

$ python3 --version
Python 3.6.9

$ cd workdir/
$ . oe-init-build-env
$ bitbake-selftest bb.tests.codeparser.PythonReferenceTest
...............
----------------------------------------------------------------------
Ran 15 tests in 0.001s
OK

The same with latest commit from kirkstone fails 7 errors like:

FAIL: test_contains (bb.tests.codeparser.PythonReferenceTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/yoctouser/workdir/bitbake/lib/bb/tests/codeparser.py",
    line 268, in test_contains
    self.assertContains({'TESTVAR': {'one'}})
  File "/home/yoctouser/workdir/bitbake/lib/bb/tests/codeparser.py",
    line 40, in assertContains
    self.assertEqual(self.contains, contains)
AssertionError: {} != {'TESTVAR': {'one'}}
- {}
+ {'TESTVAR': {'one'}}

Reported-by: Eric Sun <eric.sun@meraki.net>
Signed-off-by: Adrian Freihofer <adrian.freihofer@siemens.com>
---
 lib/bb/codeparser.py | 112 +++++++++++++++++++++++++++++--------------
 1 file changed, 76 insertions(+), 36 deletions(-)
diff mbox series

Patch

diff --git a/lib/bb/codeparser.py b/lib/bb/codeparser.py
index 6ce0c5182..afde88f44 100644
--- a/lib/bb/codeparser.py
+++ b/lib/bb/codeparser.py
@@ -224,44 +224,84 @@  class PythonParser():
 
     def visit_Call(self, node):
         name = self.called_node_name(node.func)
-        if name and (name.endswith(self.getvars) or name.endswith(self.getvarflags) or name in self.containsfuncs or name in self.containsanyfuncs):
-            if isinstance(node.args[0], ast.Constant) and isinstance(node.args[0].value, str):
-                varname = node.args[0].value
-                if name in self.containsfuncs and isinstance(node.args[1], ast.Constant):
-                    if varname not in self.contains:
-                        self.contains[varname] = set()
-                    self.contains[varname].add(node.args[1].value)
-                elif name in self.containsanyfuncs and isinstance(node.args[1], ast.Constant):
-                    if varname not in self.contains:
-                        self.contains[varname] = set()
-                    self.contains[varname].update(node.args[1].value.split())
-                elif name.endswith(self.getvarflags):
-                    if isinstance(node.args[1], ast.Constant):
-                        self.references.add('%s[%s]' % (varname, node.args[1].value))
+        if sys.version_info[:3] < (3,8,0):
+            if name and (name.endswith(self.getvars) or name.endswith(self.getvarflags) or name in self.containsfuncs or name in self.containsanyfuncs):
+                if isinstance(node.args[0], ast.Str):
+                    varname = node.args[0].s
+                    if name in self.containsfuncs and isinstance(node.args[1], ast.Str):
+                        if varname not in self.contains:
+                            self.contains[varname] = set()
+                        self.contains[varname].add(node.args[1].s)
+                    elif name in self.containsanyfuncs and isinstance(node.args[1], ast.Str):
+                        if varname not in self.contains:
+                            self.contains[varname] = set()
+                        self.contains[varname].update(node.args[1].s.split())
+                    elif name.endswith(self.getvarflags):
+                        if isinstance(node.args[1], ast.Str):
+                            self.references.add('%s[%s]' % (varname, node.args[1].s))
+                        else:
+                            self.warn(node.func, node.args[1])
                     else:
-                        self.warn(node.func, node.args[1])
+                        self.references.add(varname)
                 else:
-                    self.references.add(varname)
-            else:
-                self.warn(node.func, node.args[0])
-        elif name and name.endswith(".expand"):
-            if isinstance(node.args[0], ast.Constant):
-                value = node.args[0].value
-                d = bb.data.init()
-                parser = d.expandWithRefs(value, self.name)
-                self.references |= parser.references
-                self.execs |= parser.execs
-                for varname in parser.contains:
-                    if varname not in self.contains:
-                        self.contains[varname] = set()
-                    self.contains[varname] |= parser.contains[varname]
-        elif name in self.execfuncs:
-            if isinstance(node.args[0], ast.Constant):
-                self.var_execs.add(node.args[0].value)
-            else:
-                self.warn(node.func, node.args[0])
-        elif name and isinstance(node.func, (ast.Name, ast.Attribute)):
-            self.execs.add(name)
+                    self.warn(node.func, node.args[0])
+            elif name and name.endswith(".expand"):
+                if isinstance(node.args[0], ast.Str):
+                    value = node.args[0].s
+                    d = bb.data.init()
+                    parser = d.expandWithRefs(value, self.name)
+                    self.references |= parser.references
+                    self.execs |= parser.execs
+                    for varname in parser.contains:
+                        if varname not in self.contains:
+                            self.contains[varname] = set()
+                        self.contains[varname] |= parser.contains[varname]
+            elif name in self.execfuncs:
+                if isinstance(node.args[0], ast.Str):
+                    self.var_execs.add(node.args[0].s)
+                else:
+                    self.warn(node.func, node.args[0])
+            elif name and isinstance(node.func, (ast.Name, ast.Attribute)):
+                self.execs.add(name)
+        else:
+            if name and (name.endswith(self.getvars) or name.endswith(self.getvarflags) or name in self.containsfuncs or name in self.containsanyfuncs):
+                if isinstance(node.args[0], ast.Constant) and isinstance(node.args[0].value, str):
+                    varname = node.args[0].value
+                    if name in self.containsfuncs and isinstance(node.args[1], ast.Constant):
+                        if varname not in self.contains:
+                            self.contains[varname] = set()
+                        self.contains[varname].add(node.args[1].value)
+                    elif name in self.containsanyfuncs and isinstance(node.args[1], ast.Constant):
+                        if varname not in self.contains:
+                            self.contains[varname] = set()
+                        self.contains[varname].update(node.args[1].value.split())
+                    elif name.endswith(self.getvarflags):
+                        if isinstance(node.args[1], ast.Constant):
+                            self.references.add('%s[%s]' % (varname, node.args[1].value))
+                        else:
+                            self.warn(node.func, node.args[1])
+                    else:
+                        self.references.add(varname)
+                else:
+                    self.warn(node.func, node.args[0])
+            elif name and name.endswith(".expand"):
+                if isinstance(node.args[0], ast.Constant):
+                    value = node.args[0].value
+                    d = bb.data.init()
+                    parser = d.expandWithRefs(value, self.name)
+                    self.references |= parser.references
+                    self.execs |= parser.execs
+                    for varname in parser.contains:
+                        if varname not in self.contains:
+                            self.contains[varname] = set()
+                        self.contains[varname] |= parser.contains[varname]
+            elif name in self.execfuncs:
+                if isinstance(node.args[0], ast.Constant):
+                    self.var_execs.add(node.args[0].value)
+                else:
+                    self.warn(node.func, node.args[0])
+            elif name and isinstance(node.func, (ast.Name, ast.Attribute)):
+                self.execs.add(name)
 
     def called_node_name(self, node):
         """Given a called node, return its original string form"""