summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/data_smart.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/data_smart.py')
-rw-r--r--bitbake/lib/bb/data_smart.py371
1 files changed, 237 insertions, 134 deletions
diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py
index 2328c334ac..8e7dd98384 100644
--- a/bitbake/lib/bb/data_smart.py
+++ b/bitbake/lib/bb/data_smart.py
@@ -16,8 +16,11 @@ BitBake build tools.
16# 16#
17# Based on functions from the base bb module, Copyright 2003 Holger Schurig 17# Based on functions from the base bb module, Copyright 2003 Holger Schurig
18 18
19import copy, re, sys, traceback 19import builtins
20from collections import MutableMapping 20import copy
21import re
22import sys
23from collections.abc import MutableMapping
21import logging 24import logging
22import hashlib 25import hashlib
23import bb, bb.codeparser 26import bb, bb.codeparser
@@ -26,13 +29,25 @@ from bb.COW import COWDictBase
26 29
27logger = logging.getLogger("BitBake.Data") 30logger = logging.getLogger("BitBake.Data")
28 31
29__setvar_keyword__ = ["_append", "_prepend", "_remove"] 32__setvar_keyword__ = [":append", ":prepend", ":remove"]
30__setvar_regexp__ = re.compile(r'(?P<base>.*?)(?P<keyword>_append|_prepend|_remove)(_(?P<add>[^A-Z]*))?$') 33__setvar_regexp__ = re.compile(r'(?P<base>.*?)(?P<keyword>:append|:prepend|:remove)(:(?P<add>[^A-Z]*))?$')
31__expand_var_regexp__ = re.compile(r"\${[a-zA-Z0-9\-_+./~]+?}") 34__expand_var_regexp__ = re.compile(r"\${[a-zA-Z0-9\-_+./~:]+}")
32__expand_python_regexp__ = re.compile(r"\${@.+?}") 35__expand_python_regexp__ = re.compile(r"\${@(?:{.*?}|.)+?}")
33__whitespace_split__ = re.compile(r'(\s)') 36__whitespace_split__ = re.compile(r'(\s)')
34__override_regexp__ = re.compile(r'[a-z0-9]+') 37__override_regexp__ = re.compile(r'[a-z0-9]+')
35 38
39bitbake_renamed_vars = {
40 "BB_ENV_WHITELIST": "BB_ENV_PASSTHROUGH",
41 "BB_ENV_EXTRAWHITE": "BB_ENV_PASSTHROUGH_ADDITIONS",
42 "BB_HASHBASE_WHITELIST": "BB_BASEHASH_IGNORE_VARS",
43 "BB_HASHCONFIG_WHITELIST": "BB_HASHCONFIG_IGNORE_VARS",
44 "BB_HASHTASK_WHITELIST": "BB_TASKHASH_IGNORE_TASKS",
45 "BB_SETSCENE_ENFORCE_WHITELIST": "BB_SETSCENE_ENFORCE_IGNORE_TASKS",
46 "MULTI_PROVIDER_WHITELIST": "BB_MULTI_PROVIDER_ALLOWED",
47 "BB_STAMP_WHITELIST": "is a deprecated variable and support has been removed",
48 "BB_STAMP_POLICY": "is a deprecated variable and support has been removed",
49}
50
36def infer_caller_details(loginfo, parent = False, varval = True): 51def infer_caller_details(loginfo, parent = False, varval = True):
37 """Save the caller the trouble of specifying everything.""" 52 """Save the caller the trouble of specifying everything."""
38 # Save effort. 53 # Save effort.
@@ -80,68 +95,79 @@ def infer_caller_details(loginfo, parent = False, varval = True):
80 loginfo['func'] = func 95 loginfo['func'] = func
81 96
82class VariableParse: 97class VariableParse:
83 def __init__(self, varname, d, val = None): 98 def __init__(self, varname, d, unexpanded_value = None, val = None):
84 self.varname = varname 99 self.varname = varname
85 self.d = d 100 self.d = d
86 self.value = val 101 self.value = val
102 self.unexpanded_value = unexpanded_value
87 103
88 self.references = set() 104 self.references = set()
89 self.execs = set() 105 self.execs = set()
90 self.contains = {} 106 self.contains = {}
91 107
92 def var_sub(self, match): 108 def var_sub(self, match):
93 key = match.group()[2:-1] 109 key = match.group()[2:-1]
94 if self.varname and key: 110 if self.varname and key:
95 if self.varname == key: 111 if self.varname == key:
96 raise Exception("variable %s references itself!" % self.varname) 112 raise Exception("variable %s references itself!" % self.varname)
97 var = self.d.getVarFlag(key, "_content") 113 var = self.d.getVarFlag(key, "_content")
98 self.references.add(key) 114 self.references.add(key)
99 if var is not None: 115 if var is not None:
100 return var 116 return var
101 else: 117 else:
102 return match.group() 118 return match.group()
103 119
104 def python_sub(self, match): 120 def python_sub(self, match):
105 if isinstance(match, str): 121 if isinstance(match, str):
106 code = match 122 code = match
107 else: 123 else:
108 code = match.group()[3:-1] 124 code = match.group()[3:-1]
109 125
110 if self.varname: 126 # Do not run code that contains one or more unexpanded variables
111 varname = 'Var <%s>' % self.varname 127 # instead return the code with the characters we removed put back
112 else: 128 if __expand_var_regexp__.findall(code):
113 varname = '<expansion>' 129 return "${@" + code + "}"
114 codeobj = compile(code.strip(), varname, "eval")
115
116 parser = bb.codeparser.PythonParser(self.varname, logger)
117 parser.parse_python(code)
118 if self.varname:
119 vardeps = self.d.getVarFlag(self.varname, "vardeps")
120 if vardeps is None:
121 parser.log.flush()
122 else:
123 parser.log.flush()
124 self.references |= parser.references
125 self.execs |= parser.execs
126 130
127 for k in parser.contains: 131 if self.varname:
128 if k not in self.contains: 132 varname = 'Var <%s>' % self.varname
129 self.contains[k] = parser.contains[k].copy() 133 else:
130 else: 134 varname = '<expansion>'
131 self.contains[k].update(parser.contains[k]) 135 codeobj = compile(code.strip(), varname, "eval")
132 value = utils.better_eval(codeobj, DataContext(self.d), {'d' : self.d}) 136
133 return str(value) 137 parser = bb.codeparser.PythonParser(self.varname, logger)
138 parser.parse_python(code)
139 if self.varname:
140 vardeps = self.d.getVarFlag(self.varname, "vardeps")
141 if vardeps is None:
142 parser.log.flush()
143 else:
144 parser.log.flush()
145 self.references |= parser.references
146 self.execs |= parser.execs
134 147
148 for k in parser.contains:
149 if k not in self.contains:
150 self.contains[k] = parser.contains[k].copy()
151 else:
152 self.contains[k].update(parser.contains[k])
153 value = utils.better_eval(codeobj, DataContext(self.d), {'d' : self.d})
154 return str(value)
135 155
136class DataContext(dict): 156class DataContext(dict):
157 excluded = set([i for i in dir(builtins) if not i.startswith('_')] + ['oe'])
158
137 def __init__(self, metadata, **kwargs): 159 def __init__(self, metadata, **kwargs):
138 self.metadata = metadata 160 self.metadata = metadata
139 dict.__init__(self, **kwargs) 161 dict.__init__(self, **kwargs)
140 self['d'] = metadata 162 self['d'] = metadata
163 self.context = set(bb.utils.get_context())
141 164
142 def __missing__(self, key): 165 def __missing__(self, key):
166 if key in self.excluded or key in self.context:
167 raise KeyError(key)
168
143 value = self.metadata.getVar(key) 169 value = self.metadata.getVar(key)
144 if value is None or self.metadata.getVarFlag(key, 'func', False): 170 if value is None:
145 raise KeyError(key) 171 raise KeyError(key)
146 else: 172 else:
147 return value 173 return value
@@ -151,6 +177,7 @@ class ExpansionError(Exception):
151 self.expression = expression 177 self.expression = expression
152 self.variablename = varname 178 self.variablename = varname
153 self.exception = exception 179 self.exception = exception
180 self.varlist = [varname or expression or ""]
154 if varname: 181 if varname:
155 if expression: 182 if expression:
156 self.msg = "Failure expanding variable %s, expression was %s which triggered exception %s: %s" % (varname, expression, type(exception).__name__, exception) 183 self.msg = "Failure expanding variable %s, expression was %s which triggered exception %s: %s" % (varname, expression, type(exception).__name__, exception)
@@ -160,8 +187,14 @@ class ExpansionError(Exception):
160 self.msg = "Failure expanding expression %s which triggered exception %s: %s" % (expression, type(exception).__name__, exception) 187 self.msg = "Failure expanding expression %s which triggered exception %s: %s" % (expression, type(exception).__name__, exception)
161 Exception.__init__(self, self.msg) 188 Exception.__init__(self, self.msg)
162 self.args = (varname, expression, exception) 189 self.args = (varname, expression, exception)
190
191 def addVar(self, varname):
192 if varname:
193 self.varlist.append(varname)
194
163 def __str__(self): 195 def __str__(self):
164 return self.msg 196 chain = "\nThe variable dependency chain for the failure is: " + " -> ".join(self.varlist)
197 return self.msg + chain
165 198
166class IncludeHistory(object): 199class IncludeHistory(object):
167 def __init__(self, parent = None, filename = '[TOP LEVEL]'): 200 def __init__(self, parent = None, filename = '[TOP LEVEL]'):
@@ -239,12 +272,9 @@ class VariableHistory(object):
239 return 272 return
240 if 'op' not in loginfo or not loginfo['op']: 273 if 'op' not in loginfo or not loginfo['op']:
241 loginfo['op'] = 'set' 274 loginfo['op'] = 'set'
242 if 'detail' in loginfo:
243 loginfo['detail'] = str(loginfo['detail'])
244 if 'variable' not in loginfo or 'file' not in loginfo: 275 if 'variable' not in loginfo or 'file' not in loginfo:
245 raise ValueError("record() missing variable or file.") 276 raise ValueError("record() missing variable or file.")
246 var = loginfo['variable'] 277 var = loginfo['variable']
247
248 if var not in self.variables: 278 if var not in self.variables:
249 self.variables[var] = [] 279 self.variables[var] = []
250 if not isinstance(self.variables[var], list): 280 if not isinstance(self.variables[var], list):
@@ -277,7 +307,7 @@ class VariableHistory(object):
277 for (r, override) in d.overridedata[var]: 307 for (r, override) in d.overridedata[var]:
278 for event in self.variable(r): 308 for event in self.variable(r):
279 loginfo = event.copy() 309 loginfo = event.copy()
280 if 'flag' in loginfo and not loginfo['flag'].startswith("_"): 310 if 'flag' in loginfo and not loginfo['flag'].startswith(("_", ":")):
281 continue 311 continue
282 loginfo['variable'] = var 312 loginfo['variable'] = var
283 loginfo['op'] = 'override[%s]:%s' % (override, loginfo['op']) 313 loginfo['op'] = 'override[%s]:%s' % (override, loginfo['op'])
@@ -303,7 +333,8 @@ class VariableHistory(object):
303 flag = '[%s] ' % (event['flag']) 333 flag = '[%s] ' % (event['flag'])
304 else: 334 else:
305 flag = '' 335 flag = ''
306 o.write("# %s %s:%s%s\n# %s\"%s\"\n" % (event['op'], event['file'], event['line'], display_func, flag, re.sub('\n', '\n# ', event['detail']))) 336 o.write("# %s %s:%s%s\n# %s\"%s\"\n" % \
337 (event['op'], event['file'], event['line'], display_func, flag, re.sub('\n', '\n# ', str(event['detail']))))
307 if len(history) > 1: 338 if len(history) > 1:
308 o.write("# pre-expansion value:\n") 339 o.write("# pre-expansion value:\n")
309 o.write('# "%s"\n' % (commentVal)) 340 o.write('# "%s"\n' % (commentVal))
@@ -329,6 +360,16 @@ class VariableHistory(object):
329 lines.append(line) 360 lines.append(line)
330 return lines 361 return lines
331 362
363 def get_variable_refs(self, var):
364 """Return a dict of file/line references"""
365 var_history = self.variable(var)
366 refs = {}
367 for event in var_history:
368 if event['file'] not in refs:
369 refs[event['file']] = []
370 refs[event['file']].append(event['line'])
371 return refs
372
332 def get_variable_items_files(self, var): 373 def get_variable_items_files(self, var):
333 """ 374 """
334 Use variable history to map items added to a list variable and 375 Use variable history to map items added to a list variable and
@@ -342,12 +383,12 @@ class VariableHistory(object):
342 for event in history: 383 for event in history:
343 if 'flag' in event: 384 if 'flag' in event:
344 continue 385 continue
345 if event['op'] == '_remove': 386 if event['op'] == ':remove':
346 continue 387 continue
347 if isset and event['op'] == 'set?': 388 if isset and event['op'] == 'set?':
348 continue 389 continue
349 isset = True 390 isset = True
350 items = d.expand(event['detail']).split() 391 items = d.expand(str(event['detail'])).split()
351 for item in items: 392 for item in items:
352 # This is a little crude but is belt-and-braces to avoid us 393 # This is a little crude but is belt-and-braces to avoid us
353 # having to handle every possible operation type specifically 394 # having to handle every possible operation type specifically
@@ -363,6 +404,23 @@ class VariableHistory(object):
363 else: 404 else:
364 self.variables[var] = [] 405 self.variables[var] = []
365 406
407def _print_rename_error(var, loginfo, renamedvars, fullvar=None):
408 info = ""
409 if "file" in loginfo:
410 info = " file: %s" % loginfo["file"]
411 if "line" in loginfo:
412 info += " line: %s" % loginfo["line"]
413 if fullvar and fullvar != var:
414 info += " referenced as: %s" % fullvar
415 if info:
416 info = " (%s)" % info.strip()
417 renameinfo = renamedvars[var]
418 if " " in renameinfo:
419 # A space signals a string to display instead of a rename
420 bb.erroronce('Variable %s %s%s' % (var, renameinfo, info))
421 else:
422 bb.erroronce('Variable %s has been renamed to %s%s' % (var, renameinfo, info))
423
366class DataSmart(MutableMapping): 424class DataSmart(MutableMapping):
367 def __init__(self): 425 def __init__(self):
368 self.dict = {} 426 self.dict = {}
@@ -370,6 +428,8 @@ class DataSmart(MutableMapping):
370 self.inchistory = IncludeHistory() 428 self.inchistory = IncludeHistory()
371 self.varhistory = VariableHistory(self) 429 self.varhistory = VariableHistory(self)
372 self._tracking = False 430 self._tracking = False
431 self._var_renames = {}
432 self._var_renames.update(bitbake_renamed_vars)
373 433
374 self.expand_cache = {} 434 self.expand_cache = {}
375 435
@@ -391,9 +451,9 @@ class DataSmart(MutableMapping):
391 def expandWithRefs(self, s, varname): 451 def expandWithRefs(self, s, varname):
392 452
393 if not isinstance(s, str): # sanity check 453 if not isinstance(s, str): # sanity check
394 return VariableParse(varname, self, s) 454 return VariableParse(varname, self, s, s)
395 455
396 varparse = VariableParse(varname, self) 456 varparse = VariableParse(varname, self, s)
397 457
398 while s.find('${') != -1: 458 while s.find('${') != -1:
399 olds = s 459 olds = s
@@ -403,14 +463,17 @@ class DataSmart(MutableMapping):
403 s = __expand_python_regexp__.sub(varparse.python_sub, s) 463 s = __expand_python_regexp__.sub(varparse.python_sub, s)
404 except SyntaxError as e: 464 except SyntaxError as e:
405 # Likely unmatched brackets, just don't expand the expression 465 # Likely unmatched brackets, just don't expand the expression
406 if e.msg != "EOL while scanning string literal": 466 if e.msg != "EOL while scanning string literal" and not e.msg.startswith("unterminated string literal"):
407 raise 467 raise
408 if s == olds: 468 if s == olds:
409 break 469 break
410 except ExpansionError: 470 except ExpansionError as e:
471 e.addVar(varname)
411 raise 472 raise
412 except bb.parse.SkipRecipe: 473 except bb.parse.SkipRecipe:
413 raise 474 raise
475 except bb.BBHandledException:
476 raise
414 except Exception as exc: 477 except Exception as exc:
415 tb = sys.exc_info()[2] 478 tb = sys.exc_info()[2]
416 raise ExpansionError(varname, s, exc).with_traceback(tb) from exc 479 raise ExpansionError(varname, s, exc).with_traceback(tb) from exc
@@ -422,24 +485,19 @@ class DataSmart(MutableMapping):
422 def expand(self, s, varname = None): 485 def expand(self, s, varname = None):
423 return self.expandWithRefs(s, varname).value 486 return self.expandWithRefs(s, varname).value
424 487
425 def finalize(self, parent = False):
426 return
427
428 def internal_finalize(self, parent = False):
429 """Performs final steps upon the datastore, including application of overrides"""
430 self.overrides = None
431
432 def need_overrides(self): 488 def need_overrides(self):
433 if self.overrides is not None: 489 if self.overrides is not None:
434 return 490 return
435 if self.inoverride: 491 if self.inoverride:
436 return 492 return
493 overrride_stack = []
437 for count in range(5): 494 for count in range(5):
438 self.inoverride = True 495 self.inoverride = True
439 # Can end up here recursively so setup dummy values 496 # Can end up here recursively so setup dummy values
440 self.overrides = [] 497 self.overrides = []
441 self.overridesset = set() 498 self.overridesset = set()
442 self.overrides = (self.getVar("OVERRIDES") or "").split(":") or [] 499 self.overrides = (self.getVar("OVERRIDES") or "").split(":") or []
500 overrride_stack.append(self.overrides)
443 self.overridesset = set(self.overrides) 501 self.overridesset = set(self.overrides)
444 self.inoverride = False 502 self.inoverride = False
445 self.expand_cache = {} 503 self.expand_cache = {}
@@ -449,7 +507,7 @@ class DataSmart(MutableMapping):
449 self.overrides = newoverrides 507 self.overrides = newoverrides
450 self.overridesset = set(self.overrides) 508 self.overridesset = set(self.overrides)
451 else: 509 else:
452 bb.fatal("Overrides could not be expanded into a stable state after 5 iterations, overrides must be being referenced by other overridden variables in some recursive fashion. Please provide your configuration to bitbake-devel so we can laugh, er, I mean try and understand how to make it work.") 510 bb.fatal("Overrides could not be expanded into a stable state after 5 iterations, overrides must be being referenced by other overridden variables in some recursive fashion. Please provide your configuration to bitbake-devel so we can laugh, er, I mean try and understand how to make it work. The list of failing override expansions: %s" % "\n".join(str(s) for s in overrride_stack))
453 511
454 def initVar(self, var): 512 def initVar(self, var):
455 self.expand_cache = {} 513 self.expand_cache = {}
@@ -460,27 +518,44 @@ class DataSmart(MutableMapping):
460 dest = self.dict 518 dest = self.dict
461 while dest: 519 while dest:
462 if var in dest: 520 if var in dest:
463 return dest[var], self.overridedata.get(var, None) 521 return dest[var]
464 522
465 if "_data" not in dest: 523 if "_data" not in dest:
466 break 524 break
467 dest = dest["_data"] 525 dest = dest["_data"]
468 return None, self.overridedata.get(var, None) 526 return None
469 527
470 def _makeShadowCopy(self, var): 528 def _makeShadowCopy(self, var):
471 if var in self.dict: 529 if var in self.dict:
472 return 530 return
473 531
474 local_var, _ = self._findVar(var) 532 local_var = self._findVar(var)
475 533
476 if local_var: 534 if local_var:
477 self.dict[var] = copy.copy(local_var) 535 self.dict[var] = copy.copy(local_var)
478 else: 536 else:
479 self.initVar(var) 537 self.initVar(var)
480 538
539 def hasOverrides(self, var):
540 return var in self.overridedata
481 541
482 def setVar(self, var, value, **loginfo): 542 def setVar(self, var, value, **loginfo):
483 #print("var=" + str(var) + " val=" + str(value)) 543 #print("var=" + str(var) + " val=" + str(value))
544
545 if not var.startswith("__anon_") and ("_append" in var or "_prepend" in var or "_remove" in var):
546 info = "%s" % var
547 if "file" in loginfo:
548 info += " file: %s" % loginfo["file"]
549 if "line" in loginfo:
550 info += " line: %s" % loginfo["line"]
551 bb.fatal("Variable %s contains an operation using the old override syntax. Please convert this layer/metadata before attempting to use with a newer bitbake." % info)
552
553 shortvar = var.split(":", 1)[0]
554 if shortvar in self._var_renames:
555 _print_rename_error(shortvar, loginfo, self._var_renames, fullvar=var)
556 # Mark that we have seen a renamed variable
557 self.setVar("_FAILPARSINGERRORHANDLED", True)
558
484 self.expand_cache = {} 559 self.expand_cache = {}
485 parsing=False 560 parsing=False
486 if 'parsing' in loginfo: 561 if 'parsing' in loginfo:
@@ -505,12 +580,10 @@ class DataSmart(MutableMapping):
505 else: 580 else:
506 loginfo['op'] = keyword 581 loginfo['op'] = keyword
507 self.varhistory.record(**loginfo) 582 self.varhistory.record(**loginfo)
508 # todo make sure keyword is not __doc__ or __module__
509 # pay the cookie monster 583 # pay the cookie monster
510 584
511 # more cookies for the cookie monster 585 # more cookies for the cookie monster
512 if '_' in var: 586 self._setvar_update_overrides(base, **loginfo)
513 self._setvar_update_overrides(base, **loginfo)
514 587
515 if base in self.overridevars: 588 if base in self.overridevars:
516 self._setvar_update_overridevars(var, value) 589 self._setvar_update_overridevars(var, value)
@@ -520,27 +593,27 @@ class DataSmart(MutableMapping):
520 self._makeShadowCopy(var) 593 self._makeShadowCopy(var)
521 594
522 if not parsing: 595 if not parsing:
523 if "_append" in self.dict[var]: 596 if ":append" in self.dict[var]:
524 del self.dict[var]["_append"] 597 del self.dict[var][":append"]
525 if "_prepend" in self.dict[var]: 598 if ":prepend" in self.dict[var]:
526 del self.dict[var]["_prepend"] 599 del self.dict[var][":prepend"]
527 if "_remove" in self.dict[var]: 600 if ":remove" in self.dict[var]:
528 del self.dict[var]["_remove"] 601 del self.dict[var][":remove"]
529 if var in self.overridedata: 602 if var in self.overridedata:
530 active = [] 603 active = []
531 self.need_overrides() 604 self.need_overrides()
532 for (r, o) in self.overridedata[var]: 605 for (r, o) in self.overridedata[var]:
533 if o in self.overridesset: 606 if o in self.overridesset:
534 active.append(r) 607 active.append(r)
535 elif "_" in o: 608 elif ":" in o:
536 if set(o.split("_")).issubset(self.overridesset): 609 if set(o.split(":")).issubset(self.overridesset):
537 active.append(r) 610 active.append(r)
538 for a in active: 611 for a in active:
539 self.delVar(a) 612 self.delVar(a)
540 del self.overridedata[var] 613 del self.overridedata[var]
541 614
542 # more cookies for the cookie monster 615 # more cookies for the cookie monster
543 if '_' in var: 616 if ':' in var:
544 self._setvar_update_overrides(var, **loginfo) 617 self._setvar_update_overrides(var, **loginfo)
545 618
546 # setting var 619 # setting var
@@ -562,12 +635,13 @@ class DataSmart(MutableMapping):
562 nextnew.update(vardata.references) 635 nextnew.update(vardata.references)
563 nextnew.update(vardata.contains.keys()) 636 nextnew.update(vardata.contains.keys())
564 new = nextnew 637 new = nextnew
565 self.internal_finalize(True) 638 self.overrides = None
639 self.expand_cache = {}
566 640
567 def _setvar_update_overrides(self, var, **loginfo): 641 def _setvar_update_overrides(self, var, **loginfo):
568 # aka pay the cookie monster 642 # aka pay the cookie monster
569 override = var[var.rfind('_')+1:] 643 override = var[var.rfind(':')+1:]
570 shortvar = var[:var.rfind('_')] 644 shortvar = var[:var.rfind(':')]
571 while override and __override_regexp__.match(override): 645 while override and __override_regexp__.match(override):
572 if shortvar not in self.overridedata: 646 if shortvar not in self.overridedata:
573 self.overridedata[shortvar] = [] 647 self.overridedata[shortvar] = []
@@ -576,9 +650,9 @@ class DataSmart(MutableMapping):
576 self.overridedata[shortvar] = list(self.overridedata[shortvar]) 650 self.overridedata[shortvar] = list(self.overridedata[shortvar])
577 self.overridedata[shortvar].append([var, override]) 651 self.overridedata[shortvar].append([var, override])
578 override = None 652 override = None
579 if "_" in shortvar: 653 if ":" in shortvar:
580 override = var[shortvar.rfind('_')+1:] 654 override = var[shortvar.rfind(':')+1:]
581 shortvar = var[:shortvar.rfind('_')] 655 shortvar = var[:shortvar.rfind(':')]
582 if len(shortvar) == 0: 656 if len(shortvar) == 0:
583 override = None 657 override = None
584 658
@@ -602,10 +676,11 @@ class DataSmart(MutableMapping):
602 self.varhistory.record(**loginfo) 676 self.varhistory.record(**loginfo)
603 self.setVar(newkey, val, ignore=True, parsing=True) 677 self.setVar(newkey, val, ignore=True, parsing=True)
604 678
605 for i in (__setvar_keyword__): 679 srcflags = self.getVarFlags(key, False, True) or {}
606 src = self.getVarFlag(key, i, False) 680 for i in srcflags:
607 if src is None: 681 if i not in (__setvar_keyword__):
608 continue 682 continue
683 src = srcflags[i]
609 684
610 dest = self.getVarFlag(newkey, i, False) or [] 685 dest = self.getVarFlag(newkey, i, False) or []
611 dest.extend(src) 686 dest.extend(src)
@@ -617,7 +692,7 @@ class DataSmart(MutableMapping):
617 self.overridedata[newkey].append([v.replace(key, newkey), o]) 692 self.overridedata[newkey].append([v.replace(key, newkey), o])
618 self.renameVar(v, v.replace(key, newkey)) 693 self.renameVar(v, v.replace(key, newkey))
619 694
620 if '_' in newkey and val is None: 695 if ':' in newkey and val is None:
621 self._setvar_update_overrides(newkey, **loginfo) 696 self._setvar_update_overrides(newkey, **loginfo)
622 697
623 loginfo['variable'] = key 698 loginfo['variable'] = key
@@ -629,12 +704,12 @@ class DataSmart(MutableMapping):
629 def appendVar(self, var, value, **loginfo): 704 def appendVar(self, var, value, **loginfo):
630 loginfo['op'] = 'append' 705 loginfo['op'] = 'append'
631 self.varhistory.record(**loginfo) 706 self.varhistory.record(**loginfo)
632 self.setVar(var + "_append", value, ignore=True, parsing=True) 707 self.setVar(var + ":append", value, ignore=True, parsing=True)
633 708
634 def prependVar(self, var, value, **loginfo): 709 def prependVar(self, var, value, **loginfo):
635 loginfo['op'] = 'prepend' 710 loginfo['op'] = 'prepend'
636 self.varhistory.record(**loginfo) 711 self.varhistory.record(**loginfo)
637 self.setVar(var + "_prepend", value, ignore=True, parsing=True) 712 self.setVar(var + ":prepend", value, ignore=True, parsing=True)
638 713
639 def delVar(self, var, **loginfo): 714 def delVar(self, var, **loginfo):
640 self.expand_cache = {} 715 self.expand_cache = {}
@@ -645,10 +720,10 @@ class DataSmart(MutableMapping):
645 self.dict[var] = {} 720 self.dict[var] = {}
646 if var in self.overridedata: 721 if var in self.overridedata:
647 del self.overridedata[var] 722 del self.overridedata[var]
648 if '_' in var: 723 if ':' in var:
649 override = var[var.rfind('_')+1:] 724 override = var[var.rfind(':')+1:]
650 shortvar = var[:var.rfind('_')] 725 shortvar = var[:var.rfind(':')]
651 while override and override.islower(): 726 while override and __override_regexp__.match(override):
652 try: 727 try:
653 if shortvar in self.overridedata: 728 if shortvar in self.overridedata:
654 # Force CoW by recreating the list first 729 # Force CoW by recreating the list first
@@ -657,15 +732,23 @@ class DataSmart(MutableMapping):
657 except ValueError as e: 732 except ValueError as e:
658 pass 733 pass
659 override = None 734 override = None
660 if "_" in shortvar: 735 if ":" in shortvar:
661 override = var[shortvar.rfind('_')+1:] 736 override = var[shortvar.rfind(':')+1:]
662 shortvar = var[:shortvar.rfind('_')] 737 shortvar = var[:shortvar.rfind(':')]
663 if len(shortvar) == 0: 738 if len(shortvar) == 0:
664 override = None 739 override = None
665 740
666 def setVarFlag(self, var, flag, value, **loginfo): 741 def setVarFlag(self, var, flag, value, **loginfo):
667 self.expand_cache = {} 742 self.expand_cache = {}
668 743
744 if var == "BB_RENAMED_VARIABLES":
745 self._var_renames[flag] = value
746
747 if var in self._var_renames:
748 _print_rename_error(var, loginfo, self._var_renames)
749 # Mark that we have seen a renamed variable
750 self.setVar("_FAILPARSINGERRORHANDLED", True)
751
669 if 'op' not in loginfo: 752 if 'op' not in loginfo:
670 loginfo['op'] = "set" 753 loginfo['op'] = "set"
671 loginfo['flag'] = flag 754 loginfo['flag'] = flag
@@ -674,7 +757,7 @@ class DataSmart(MutableMapping):
674 self._makeShadowCopy(var) 757 self._makeShadowCopy(var)
675 self.dict[var][flag] = value 758 self.dict[var][flag] = value
676 759
677 if flag == "_defaultval" and '_' in var: 760 if flag == "_defaultval" and ':' in var:
678 self._setvar_update_overrides(var, **loginfo) 761 self._setvar_update_overrides(var, **loginfo)
679 if flag == "_defaultval" and var in self.overridevars: 762 if flag == "_defaultval" and var in self.overridevars:
680 self._setvar_update_overridevars(var, value) 763 self._setvar_update_overridevars(var, value)
@@ -695,22 +778,27 @@ class DataSmart(MutableMapping):
695 return None 778 return None
696 cachename = var + "[" + flag + "]" 779 cachename = var + "[" + flag + "]"
697 780
781 if not expand and retparser and cachename in self.expand_cache:
782 return self.expand_cache[cachename].unexpanded_value, self.expand_cache[cachename]
783
698 if expand and cachename in self.expand_cache: 784 if expand and cachename in self.expand_cache:
699 return self.expand_cache[cachename].value 785 return self.expand_cache[cachename].value
700 786
701 local_var, overridedata = self._findVar(var) 787 local_var = self._findVar(var)
702 value = None 788 value = None
703 removes = set() 789 removes = set()
704 if flag == "_content" and overridedata is not None and not parsing: 790 if flag == "_content" and not parsing:
791 overridedata = self.overridedata.get(var, None)
792 if flag == "_content" and not parsing and overridedata is not None:
705 match = False 793 match = False
706 active = {} 794 active = {}
707 self.need_overrides() 795 self.need_overrides()
708 for (r, o) in overridedata: 796 for (r, o) in overridedata:
709 # What about double overrides both with "_" in the name? 797 # FIXME What about double overrides both with "_" in the name?
710 if o in self.overridesset: 798 if o in self.overridesset:
711 active[o] = r 799 active[o] = r
712 elif "_" in o: 800 elif ":" in o:
713 if set(o.split("_")).issubset(self.overridesset): 801 if set(o.split(":")).issubset(self.overridesset):
714 active[o] = r 802 active[o] = r
715 803
716 mod = True 804 mod = True
@@ -718,10 +806,10 @@ class DataSmart(MutableMapping):
718 mod = False 806 mod = False
719 for o in self.overrides: 807 for o in self.overrides:
720 for a in active.copy(): 808 for a in active.copy():
721 if a.endswith("_" + o): 809 if a.endswith(":" + o):
722 t = active[a] 810 t = active[a]
723 del active[a] 811 del active[a]
724 active[a.replace("_" + o, "")] = t 812 active[a.replace(":" + o, "")] = t
725 mod = True 813 mod = True
726 elif a == o: 814 elif a == o:
727 match = active[a] 815 match = active[a]
@@ -738,33 +826,35 @@ class DataSmart(MutableMapping):
738 value = copy.copy(local_var[flag]) 826 value = copy.copy(local_var[flag])
739 elif flag == "_content" and "_defaultval" in local_var and not noweakdefault: 827 elif flag == "_content" and "_defaultval" in local_var and not noweakdefault:
740 value = copy.copy(local_var["_defaultval"]) 828 value = copy.copy(local_var["_defaultval"])
829 elif "_defaultval_flag_"+flag in local_var and not noweakdefault:
830 value = copy.copy(local_var["_defaultval_flag_"+flag])
741 831
742 832
743 if flag == "_content" and local_var is not None and "_append" in local_var and not parsing: 833 if flag == "_content" and local_var is not None and ":append" in local_var and not parsing:
744 if not value:
745 value = ""
746 self.need_overrides() 834 self.need_overrides()
747 for (r, o) in local_var["_append"]: 835 for (r, o) in local_var[":append"]:
748 match = True 836 match = True
749 if o: 837 if o:
750 for o2 in o.split("_"): 838 for o2 in o.split(":"):
751 if not o2 in self.overrides: 839 if not o2 in self.overrides:
752 match = False 840 match = False
753 if match: 841 if match:
842 if value is None:
843 value = ""
754 value = value + r 844 value = value + r
755 845
756 if flag == "_content" and local_var is not None and "_prepend" in local_var and not parsing: 846 if flag == "_content" and local_var is not None and ":prepend" in local_var and not parsing:
757 if not value:
758 value = ""
759 self.need_overrides() 847 self.need_overrides()
760 for (r, o) in local_var["_prepend"]: 848 for (r, o) in local_var[":prepend"]:
761 849
762 match = True 850 match = True
763 if o: 851 if o:
764 for o2 in o.split("_"): 852 for o2 in o.split(":"):
765 if not o2 in self.overrides: 853 if not o2 in self.overrides:
766 match = False 854 match = False
767 if match: 855 if match:
856 if value is None:
857 value = ""
768 value = r + value 858 value = r + value
769 859
770 parser = None 860 parser = None
@@ -773,12 +863,12 @@ class DataSmart(MutableMapping):
773 if expand: 863 if expand:
774 value = parser.value 864 value = parser.value
775 865
776 if value and flag == "_content" and local_var is not None and "_remove" in local_var and not parsing: 866 if value and flag == "_content" and local_var is not None and ":remove" in local_var and not parsing:
777 self.need_overrides() 867 self.need_overrides()
778 for (r, o) in local_var["_remove"]: 868 for (r, o) in local_var[":remove"]:
779 match = True 869 match = True
780 if o: 870 if o:
781 for o2 in o.split("_"): 871 for o2 in o.split(":"):
782 if not o2 in self.overrides: 872 if not o2 in self.overrides:
783 match = False 873 match = False
784 if match: 874 if match:
@@ -791,7 +881,7 @@ class DataSmart(MutableMapping):
791 expanded_removes[r] = self.expand(r).split() 881 expanded_removes[r] = self.expand(r).split()
792 882
793 parser.removes = set() 883 parser.removes = set()
794 val = "" 884 val = []
795 for v in __whitespace_split__.split(parser.value): 885 for v in __whitespace_split__.split(parser.value):
796 skip = False 886 skip = False
797 for r in removes: 887 for r in removes:
@@ -800,8 +890,8 @@ class DataSmart(MutableMapping):
800 skip = True 890 skip = True
801 if skip: 891 if skip:
802 continue 892 continue
803 val = val + v 893 val.append(v)
804 parser.value = val 894 parser.value = "".join(val)
805 if expand: 895 if expand:
806 value = parser.value 896 value = parser.value
807 897
@@ -816,7 +906,7 @@ class DataSmart(MutableMapping):
816 def delVarFlag(self, var, flag, **loginfo): 906 def delVarFlag(self, var, flag, **loginfo):
817 self.expand_cache = {} 907 self.expand_cache = {}
818 908
819 local_var, _ = self._findVar(var) 909 local_var = self._findVar(var)
820 if not local_var: 910 if not local_var:
821 return 911 return
822 if not var in self.dict: 912 if not var in self.dict:
@@ -829,6 +919,8 @@ class DataSmart(MutableMapping):
829 self.varhistory.record(**loginfo) 919 self.varhistory.record(**loginfo)
830 920
831 del self.dict[var][flag] 921 del self.dict[var][flag]
922 if ("_defaultval_flag_" + flag) in self.dict[var]:
923 del self.dict[var]["_defaultval_flag_" + flag]
832 924
833 def appendVarFlag(self, var, flag, value, **loginfo): 925 def appendVarFlag(self, var, flag, value, **loginfo):
834 loginfo['op'] = 'append' 926 loginfo['op'] = 'append'
@@ -859,21 +951,26 @@ class DataSmart(MutableMapping):
859 self.dict[var][i] = flags[i] 951 self.dict[var][i] = flags[i]
860 952
861 def getVarFlags(self, var, expand = False, internalflags=False): 953 def getVarFlags(self, var, expand = False, internalflags=False):
862 local_var, _ = self._findVar(var) 954 local_var = self._findVar(var)
863 flags = {} 955 flags = {}
864 956
865 if local_var: 957 if local_var:
866 for i in local_var: 958 for i, val in local_var.items():
867 if i.startswith("_") and not internalflags: 959 if i.startswith("_defaultval_flag_") and not internalflags:
960 i = i[len("_defaultval_flag_"):]
961 if i not in local_var:
962 flags[i] = val
963 elif i.startswith(("_", ":")) and not internalflags:
868 continue 964 continue
869 flags[i] = local_var[i] 965 else:
966 flags[i] = val
967
870 if expand and i in expand: 968 if expand and i in expand:
871 flags[i] = self.expand(flags[i], var + "[" + i + "]") 969 flags[i] = self.expand(flags[i], var + "[" + i + "]")
872 if len(flags) == 0: 970 if len(flags) == 0:
873 return None 971 return None
874 return flags 972 return flags
875 973
876
877 def delVarFlags(self, var, **loginfo): 974 def delVarFlags(self, var, **loginfo):
878 self.expand_cache = {} 975 self.expand_cache = {}
879 if not var in self.dict: 976 if not var in self.dict:
@@ -905,6 +1002,7 @@ class DataSmart(MutableMapping):
905 data.inchistory = self.inchistory.copy() 1002 data.inchistory = self.inchistory.copy()
906 1003
907 data._tracking = self._tracking 1004 data._tracking = self._tracking
1005 data._var_renames = self._var_renames
908 1006
909 data.overrides = None 1007 data.overrides = None
910 data.overridevars = copy.copy(self.overridevars) 1008 data.overridevars = copy.copy(self.overridevars)
@@ -927,7 +1025,7 @@ class DataSmart(MutableMapping):
927 value = self.getVar(variable, False) 1025 value = self.getVar(variable, False)
928 for key in keys: 1026 for key in keys:
929 referrervalue = self.getVar(key, False) 1027 referrervalue = self.getVar(key, False)
930 if referrervalue and ref in referrervalue: 1028 if referrervalue and isinstance(referrervalue, str) and ref in referrervalue:
931 self.setVar(key, referrervalue.replace(ref, value)) 1029 self.setVar(key, referrervalue.replace(ref, value))
932 1030
933 def localkeys(self): 1031 def localkeys(self):
@@ -962,8 +1060,8 @@ class DataSmart(MutableMapping):
962 for (r, o) in self.overridedata[var]: 1060 for (r, o) in self.overridedata[var]:
963 if o in self.overridesset: 1061 if o in self.overridesset:
964 overrides.add(var) 1062 overrides.add(var)
965 elif "_" in o: 1063 elif ":" in o:
966 if set(o.split("_")).issubset(self.overridesset): 1064 if set(o.split(":")).issubset(self.overridesset):
967 overrides.add(var) 1065 overrides.add(var)
968 1066
969 for k in keylist(self.dict): 1067 for k in keylist(self.dict):
@@ -993,10 +1091,10 @@ class DataSmart(MutableMapping):
993 d = self.createCopy() 1091 d = self.createCopy()
994 bb.data.expandKeys(d) 1092 bb.data.expandKeys(d)
995 1093
996 config_whitelist = set((d.getVar("BB_HASHCONFIG_WHITELIST") or "").split()) 1094 config_ignore_vars = set((d.getVar("BB_HASHCONFIG_IGNORE_VARS") or "").split())
997 keys = set(key for key in iter(d) if not key.startswith("__")) 1095 keys = set(key for key in iter(d) if not key.startswith("__"))
998 for key in keys: 1096 for key in keys:
999 if key in config_whitelist: 1097 if key in config_ignore_vars:
1000 continue 1098 continue
1001 1099
1002 value = d.getVar(key, False) or "" 1100 value = d.getVar(key, False) or ""
@@ -1022,5 +1120,10 @@ class DataSmart(MutableMapping):
1022 value = d.getVar(i, False) or "" 1120 value = d.getVar(i, False) or ""
1023 data.update({i:value}) 1121 data.update({i:value})
1024 1122
1123 moddeps = bb.codeparser.modulecode_deps
1124 for dep in sorted(moddeps):
1125 # Ignore visitor code, sort sets
1126 data.update({'moddep[%s]' % dep : [sorted(moddeps[dep][0]), sorted(moddeps[dep][1]), sorted(moddeps[dep][2]), sorted(moddeps[dep][3]), moddeps[dep][4]]})
1127
1025 data_str = str([(k, data[k]) for k in sorted(data.keys())]) 1128 data_str = str([(k, data[k]) for k in sorted(data.keys())])
1026 return hashlib.sha256(data_str.encode("utf-8")).hexdigest() 1129 return hashlib.sha256(data_str.encode("utf-8")).hexdigest()