mirror of
https://git.yoctoproject.org/poky
synced 2026-02-05 16:28:43 +01:00
bitbake: codeparser: Fix handling of string AST nodes with older Python versions
Commits 4591011449212c8e494ea42348acb2d27a82a51b and
6c19b6cf105ac321ec89da1a876a317020c45ab7 unconditionally changed
codeparser to rely on CPython 3.8 semantics. However, kirkstone
continues to support CPython versions >= 3.6.0 and as such string AST
nodes were no longer correctly identified.
Fix this by continuing to use `ast.Str` for Python versions < 3.8.0 and
only using the new code path for more recent versions. Detecting which
version of the AST API to use seems to be non-trivial so the Python
feature version is used instead.
Instances of this issue can be identified when executing bitbake with
debug logging:
while parsing MACHINE_ARCH, in call of d.getVar, argument
''TUNE_PKGARCH'' is not a string literal
As a consequence of these parsing issues, bitbake may assume that task
inputs haven't changed and as such erroneously reuse sstate objects when
it shouldn't.
(Bitbake rev: fb73c495c45d1d4107cfd60b67a5b4f11a99647b)
Signed-off-by: Philip Lorenz <philip.lorenz@bmw.de>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
committed by
Steve Sakoman
parent
51bd4260cb
commit
3aaed26728
@@ -201,6 +201,22 @@ class DummyLogger():
|
||||
def flush(self):
|
||||
return
|
||||
|
||||
|
||||
# Starting with Python 3.8, the ast module exposes all string nodes as a
|
||||
# Constant. While earlier versions of the module also have the Constant type
|
||||
# those use the Str type to encapsulate strings.
|
||||
if sys.version_info < (3, 8):
|
||||
def node_str_value(node):
|
||||
if isinstance(node, ast.Str):
|
||||
return node.s
|
||||
return None
|
||||
else:
|
||||
def node_str_value(node):
|
||||
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
||||
return node.value
|
||||
return None
|
||||
|
||||
|
||||
class PythonParser():
|
||||
getvars = (".getVar", ".appendVar", ".prependVar", "oe.utils.conditional")
|
||||
getvarflags = (".getVarFlag", ".appendVarFlag", ".prependVarFlag")
|
||||
@@ -225,19 +241,22 @@ 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):
|
||||
varname = node_str_value(node.args[0])
|
||||
if varname is not None:
|
||||
arg_str_value = None
|
||||
if len(node.args) >= 2:
|
||||
arg_str_value = node_str_value(node.args[1])
|
||||
if name in self.containsfuncs and arg_str_value is not None:
|
||||
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):
|
||||
self.contains[varname].add(arg_str_value)
|
||||
elif name in self.containsanyfuncs and arg_str_value is not None:
|
||||
if varname not in self.contains:
|
||||
self.contains[varname] = set()
|
||||
self.contains[varname].update(node.args[1].value.split())
|
||||
self.contains[varname].update(arg_str_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 arg_str_value is not None:
|
||||
self.references.add('%s[%s]' % (varname, arg_str_value))
|
||||
else:
|
||||
self.warn(node.func, node.args[1])
|
||||
else:
|
||||
@@ -245,10 +264,10 @@ class PythonParser():
|
||||
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
|
||||
arg_str_value = node_str_value(node.args[0])
|
||||
if arg_str_value is not None:
|
||||
d = bb.data.init()
|
||||
parser = d.expandWithRefs(value, self.name)
|
||||
parser = d.expandWithRefs(arg_str_value, self.name)
|
||||
self.references |= parser.references
|
||||
self.execs |= parser.execs
|
||||
for varname in parser.contains:
|
||||
@@ -256,8 +275,9 @@ class PythonParser():
|
||||
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)
|
||||
arg_str_value = node_str_value(node.args[0])
|
||||
if arg_str_value is not None:
|
||||
self.var_execs.add(arg_str_value)
|
||||
else:
|
||||
self.warn(node.func, node.args[0])
|
||||
elif name and isinstance(node.func, (ast.Name, ast.Attribute)):
|
||||
|
||||
Reference in New Issue
Block a user