data_smart.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. """
  2. BitBake Smart Dictionary Implementation
  3. Functions for interacting with the data structure used by the
  4. BitBake build tools.
  5. """
  6. # Copyright (C) 2003, 2004 Chris Larson
  7. # Copyright (C) 2004, 2005 Seb Frankengul
  8. # Copyright (C) 2005, 2006 Holger Hans Peter Freyther
  9. # Copyright (C) 2005 Uli Luckas
  10. # Copyright (C) 2005 ROAD GmbH
  11. #
  12. # SPDX-License-Identifier: GPL-2.0-only
  13. #
  14. # Based on functions from the base bb module, Copyright 2003 Holger Schurig
  15. import copy, re, sys, traceback
  16. from collections import MutableMapping
  17. import logging
  18. import hashlib
  19. import bb, bb.codeparser
  20. from bb import utils
  21. from bb.COW import COWDictBase
  22. logger = logging.getLogger("BitBake.Data")
  23. __setvar_keyword__ = ["_append", "_prepend", "_remove"]
  24. __setvar_regexp__ = re.compile(r'(?P<base>.*?)(?P<keyword>_append|_prepend|_remove)(_(?P<add>[^A-Z]*))?$')
  25. __expand_var_regexp__ = re.compile(r"\${[a-zA-Z0-9\-_+./~]+?}")
  26. __expand_python_regexp__ = re.compile(r"\${@.+?}")
  27. __whitespace_split__ = re.compile(r'(\s)')
  28. __override_regexp__ = re.compile(r'[a-z0-9]+')
  29. def infer_caller_details(loginfo, parent = False, varval = True):
  30. """Save the caller the trouble of specifying everything."""
  31. # Save effort.
  32. if 'ignore' in loginfo and loginfo['ignore']:
  33. return
  34. # If nothing was provided, mark this as possibly unneeded.
  35. if not loginfo:
  36. loginfo['ignore'] = True
  37. return
  38. # Infer caller's likely values for variable (var) and value (value),
  39. # to reduce clutter in the rest of the code.
  40. above = None
  41. def set_above():
  42. try:
  43. raise Exception
  44. except Exception:
  45. tb = sys.exc_info()[2]
  46. if parent:
  47. return tb.tb_frame.f_back.f_back.f_back
  48. else:
  49. return tb.tb_frame.f_back.f_back
  50. if varval and ('variable' not in loginfo or 'detail' not in loginfo):
  51. if not above:
  52. above = set_above()
  53. lcls = above.f_locals.items()
  54. for k, v in lcls:
  55. if k == 'value' and 'detail' not in loginfo:
  56. loginfo['detail'] = v
  57. if k == 'var' and 'variable' not in loginfo:
  58. loginfo['variable'] = v
  59. # Infer file/line/function from traceback
  60. # Don't use traceback.extract_stack() since it fills the line contents which
  61. # we don't need and that hits stat syscalls
  62. if 'file' not in loginfo:
  63. if not above:
  64. above = set_above()
  65. f = above.f_back
  66. line = f.f_lineno
  67. file = f.f_code.co_filename
  68. func = f.f_code.co_name
  69. loginfo['file'] = file
  70. loginfo['line'] = line
  71. if func not in loginfo:
  72. loginfo['func'] = func
  73. class VariableParse:
  74. def __init__(self, varname, d, val = None):
  75. self.varname = varname
  76. self.d = d
  77. self.value = val
  78. self.references = set()
  79. self.execs = set()
  80. self.contains = {}
  81. def var_sub(self, match):
  82. key = match.group()[2:-1]
  83. if self.varname and key:
  84. if self.varname == key:
  85. raise Exception("variable %s references itself!" % self.varname)
  86. var = self.d.getVarFlag(key, "_content")
  87. self.references.add(key)
  88. if var is not None:
  89. return var
  90. else:
  91. return match.group()
  92. def python_sub(self, match):
  93. if isinstance(match, str):
  94. code = match
  95. else:
  96. code = match.group()[3:-1]
  97. if self.varname:
  98. varname = 'Var <%s>' % self.varname
  99. else:
  100. varname = '<expansion>'
  101. codeobj = compile(code.strip(), varname, "eval")
  102. parser = bb.codeparser.PythonParser(self.varname, logger)
  103. parser.parse_python(code)
  104. if self.varname:
  105. vardeps = self.d.getVarFlag(self.varname, "vardeps")
  106. if vardeps is None:
  107. parser.log.flush()
  108. else:
  109. parser.log.flush()
  110. self.references |= parser.references
  111. self.execs |= parser.execs
  112. for k in parser.contains:
  113. if k not in self.contains:
  114. self.contains[k] = parser.contains[k].copy()
  115. else:
  116. self.contains[k].update(parser.contains[k])
  117. value = utils.better_eval(codeobj, DataContext(self.d), {'d' : self.d})
  118. return str(value)
  119. class DataContext(dict):
  120. def __init__(self, metadata, **kwargs):
  121. self.metadata = metadata
  122. dict.__init__(self, **kwargs)
  123. self['d'] = metadata
  124. def __missing__(self, key):
  125. value = self.metadata.getVar(key)
  126. if value is None or self.metadata.getVarFlag(key, 'func', False):
  127. raise KeyError(key)
  128. else:
  129. return value
  130. class ExpansionError(Exception):
  131. def __init__(self, varname, expression, exception):
  132. self.expression = expression
  133. self.variablename = varname
  134. self.exception = exception
  135. if varname:
  136. if expression:
  137. self.msg = "Failure expanding variable %s, expression was %s which triggered exception %s: %s" % (varname, expression, type(exception).__name__, exception)
  138. else:
  139. self.msg = "Failure expanding variable %s: %s: %s" % (varname, type(exception).__name__, exception)
  140. else:
  141. self.msg = "Failure expanding expression %s which triggered exception %s: %s" % (expression, type(exception).__name__, exception)
  142. Exception.__init__(self, self.msg)
  143. self.args = (varname, expression, exception)
  144. def __str__(self):
  145. return self.msg
  146. class IncludeHistory(object):
  147. def __init__(self, parent = None, filename = '[TOP LEVEL]'):
  148. self.parent = parent
  149. self.filename = filename
  150. self.children = []
  151. self.current = self
  152. def copy(self):
  153. new = IncludeHistory(self.parent, self.filename)
  154. for c in self.children:
  155. new.children.append(c)
  156. return new
  157. def include(self, filename):
  158. newfile = IncludeHistory(self.current, filename)
  159. self.current.children.append(newfile)
  160. self.current = newfile
  161. return self
  162. def __enter__(self):
  163. pass
  164. def __exit__(self, a, b, c):
  165. if self.current.parent:
  166. self.current = self.current.parent
  167. else:
  168. bb.warn("Include log: Tried to finish '%s' at top level." % filename)
  169. return False
  170. def emit(self, o, level = 0):
  171. """Emit an include history file, and its children."""
  172. if level:
  173. spaces = " " * (level - 1)
  174. o.write("# %s%s" % (spaces, self.filename))
  175. if len(self.children) > 0:
  176. o.write(" includes:")
  177. else:
  178. o.write("#\n# INCLUDE HISTORY:\n#")
  179. level = level + 1
  180. for child in self.children:
  181. o.write("\n")
  182. child.emit(o, level)
  183. class VariableHistory(object):
  184. def __init__(self, dataroot):
  185. self.dataroot = dataroot
  186. self.variables = COWDictBase.copy()
  187. def copy(self):
  188. new = VariableHistory(self.dataroot)
  189. new.variables = self.variables.copy()
  190. return new
  191. def __getstate__(self):
  192. vardict = {}
  193. for k, v in self.variables.iteritems():
  194. vardict[k] = v
  195. return {'dataroot': self.dataroot,
  196. 'variables': vardict}
  197. def __setstate__(self, state):
  198. self.dataroot = state['dataroot']
  199. self.variables = COWDictBase.copy()
  200. for k, v in state['variables'].items():
  201. self.variables[k] = v
  202. def record(self, *kwonly, **loginfo):
  203. if not self.dataroot._tracking:
  204. return
  205. if len(kwonly) > 0:
  206. raise TypeError
  207. infer_caller_details(loginfo, parent = True)
  208. if 'ignore' in loginfo and loginfo['ignore']:
  209. return
  210. if 'op' not in loginfo or not loginfo['op']:
  211. loginfo['op'] = 'set'
  212. if 'detail' in loginfo:
  213. loginfo['detail'] = str(loginfo['detail'])
  214. if 'variable' not in loginfo or 'file' not in loginfo:
  215. raise ValueError("record() missing variable or file.")
  216. var = loginfo['variable']
  217. if var not in self.variables:
  218. self.variables[var] = []
  219. if not isinstance(self.variables[var], list):
  220. return
  221. if 'nodups' in loginfo and loginfo in self.variables[var]:
  222. return
  223. self.variables[var].append(loginfo.copy())
  224. def rename_variable_hist(self, oldvar, newvar):
  225. if not self.dataroot._tracking:
  226. return
  227. if oldvar not in self.variables:
  228. return
  229. if newvar not in self.variables:
  230. self.variables[newvar] = []
  231. for i in self.variables[oldvar]:
  232. self.variables[newvar].append(i.copy())
  233. def variable(self, var):
  234. varhistory = []
  235. if var in self.variables:
  236. varhistory.extend(self.variables[var])
  237. return varhistory
  238. def emit(self, var, oval, val, o, d):
  239. history = self.variable(var)
  240. # Append override history
  241. if var in d.overridedata:
  242. for (r, override) in d.overridedata[var]:
  243. for event in self.variable(r):
  244. loginfo = event.copy()
  245. if 'flag' in loginfo and not loginfo['flag'].startswith("_"):
  246. continue
  247. loginfo['variable'] = var
  248. loginfo['op'] = 'override[%s]:%s' % (override, loginfo['op'])
  249. history.append(loginfo)
  250. commentVal = re.sub('\n', '\n#', str(oval))
  251. if history:
  252. if len(history) == 1:
  253. o.write("#\n# $%s\n" % var)
  254. else:
  255. o.write("#\n# $%s [%d operations]\n" % (var, len(history)))
  256. for event in history:
  257. # o.write("# %s\n" % str(event))
  258. if 'func' in event:
  259. # If we have a function listed, this is internal
  260. # code, not an operation in a config file, and the
  261. # full path is distracting.
  262. event['file'] = re.sub('.*/', '', event['file'])
  263. display_func = ' [%s]' % event['func']
  264. else:
  265. display_func = ''
  266. if 'flag' in event:
  267. flag = '[%s] ' % (event['flag'])
  268. else:
  269. flag = ''
  270. 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'])))
  271. if len(history) > 1:
  272. o.write("# pre-expansion value:\n")
  273. o.write('# "%s"\n' % (commentVal))
  274. else:
  275. o.write("#\n# $%s\n# [no history recorded]\n#\n" % var)
  276. o.write('# "%s"\n' % (commentVal))
  277. def get_variable_files(self, var):
  278. """Get the files where operations are made on a variable"""
  279. var_history = self.variable(var)
  280. files = []
  281. for event in var_history:
  282. files.append(event['file'])
  283. return files
  284. def get_variable_lines(self, var, f):
  285. """Get the line where a operation is made on a variable in file f"""
  286. var_history = self.variable(var)
  287. lines = []
  288. for event in var_history:
  289. if f== event['file']:
  290. line = event['line']
  291. lines.append(line)
  292. return lines
  293. def get_variable_items_files(self, var):
  294. """
  295. Use variable history to map items added to a list variable and
  296. the files in which they were added.
  297. """
  298. d = self.dataroot
  299. history = self.variable(var)
  300. finalitems = (d.getVar(var) or '').split()
  301. filemap = {}
  302. isset = False
  303. for event in history:
  304. if 'flag' in event:
  305. continue
  306. if event['op'] == '_remove':
  307. continue
  308. if isset and event['op'] == 'set?':
  309. continue
  310. isset = True
  311. items = d.expand(event['detail']).split()
  312. for item in items:
  313. # This is a little crude but is belt-and-braces to avoid us
  314. # having to handle every possible operation type specifically
  315. if item in finalitems and not item in filemap:
  316. filemap[item] = event['file']
  317. return filemap
  318. def del_var_history(self, var, f=None, line=None):
  319. """If file f and line are not given, the entire history of var is deleted"""
  320. if var in self.variables:
  321. if f and line:
  322. self.variables[var] = [ x for x in self.variables[var] if x['file']!=f and x['line']!=line]
  323. else:
  324. self.variables[var] = []
  325. class DataSmart(MutableMapping):
  326. def __init__(self):
  327. self.dict = {}
  328. self.inchistory = IncludeHistory()
  329. self.varhistory = VariableHistory(self)
  330. self._tracking = False
  331. self.expand_cache = {}
  332. # cookie monster tribute
  333. # Need to be careful about writes to overridedata as
  334. # its only a shallow copy, could influence other data store
  335. # copies!
  336. self.overridedata = {}
  337. self.overrides = None
  338. self.overridevars = set(["OVERRIDES", "FILE"])
  339. self.inoverride = False
  340. def enableTracking(self):
  341. self._tracking = True
  342. def disableTracking(self):
  343. self._tracking = False
  344. def expandWithRefs(self, s, varname):
  345. if not isinstance(s, str): # sanity check
  346. return VariableParse(varname, self, s)
  347. varparse = VariableParse(varname, self)
  348. while s.find('${') != -1:
  349. olds = s
  350. try:
  351. s = __expand_var_regexp__.sub(varparse.var_sub, s)
  352. try:
  353. s = __expand_python_regexp__.sub(varparse.python_sub, s)
  354. except SyntaxError as e:
  355. # Likely unmatched brackets, just don't expand the expression
  356. if e.msg != "EOL while scanning string literal":
  357. raise
  358. if s == olds:
  359. break
  360. except ExpansionError:
  361. raise
  362. except bb.parse.SkipRecipe:
  363. raise
  364. except Exception as exc:
  365. tb = sys.exc_info()[2]
  366. raise ExpansionError(varname, s, exc).with_traceback(tb) from exc
  367. varparse.value = s
  368. return varparse
  369. def expand(self, s, varname = None):
  370. return self.expandWithRefs(s, varname).value
  371. def finalize(self, parent = False):
  372. return
  373. def internal_finalize(self, parent = False):
  374. """Performs final steps upon the datastore, including application of overrides"""
  375. self.overrides = None
  376. def need_overrides(self):
  377. if self.overrides is not None:
  378. return
  379. if self.inoverride:
  380. return
  381. for count in range(5):
  382. self.inoverride = True
  383. # Can end up here recursively so setup dummy values
  384. self.overrides = []
  385. self.overridesset = set()
  386. self.overrides = (self.getVar("OVERRIDES") or "").split(":") or []
  387. self.overridesset = set(self.overrides)
  388. self.inoverride = False
  389. self.expand_cache = {}
  390. newoverrides = (self.getVar("OVERRIDES") or "").split(":") or []
  391. if newoverrides == self.overrides:
  392. break
  393. self.overrides = newoverrides
  394. self.overridesset = set(self.overrides)
  395. else:
  396. 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.")
  397. def initVar(self, var):
  398. self.expand_cache = {}
  399. if not var in self.dict:
  400. self.dict[var] = {}
  401. def _findVar(self, var):
  402. dest = self.dict
  403. while dest:
  404. if var in dest:
  405. return dest[var], self.overridedata.get(var, None)
  406. if "_data" not in dest:
  407. break
  408. dest = dest["_data"]
  409. return None, self.overridedata.get(var, None)
  410. def _makeShadowCopy(self, var):
  411. if var in self.dict:
  412. return
  413. local_var, _ = self._findVar(var)
  414. if local_var:
  415. self.dict[var] = copy.copy(local_var)
  416. else:
  417. self.initVar(var)
  418. def setVar(self, var, value, **loginfo):
  419. #print("var=" + str(var) + " val=" + str(value))
  420. self.expand_cache = {}
  421. parsing=False
  422. if 'parsing' in loginfo:
  423. parsing=True
  424. if 'op' not in loginfo:
  425. loginfo['op'] = "set"
  426. match = __setvar_regexp__.match(var)
  427. if match and match.group("keyword") in __setvar_keyword__:
  428. base = match.group('base')
  429. keyword = match.group("keyword")
  430. override = match.group('add')
  431. l = self.getVarFlag(base, keyword, False) or []
  432. l.append([value, override])
  433. self.setVarFlag(base, keyword, l, ignore=True)
  434. # And cause that to be recorded:
  435. loginfo['detail'] = value
  436. loginfo['variable'] = base
  437. if override:
  438. loginfo['op'] = '%s[%s]' % (keyword, override)
  439. else:
  440. loginfo['op'] = keyword
  441. self.varhistory.record(**loginfo)
  442. # todo make sure keyword is not __doc__ or __module__
  443. # pay the cookie monster
  444. # more cookies for the cookie monster
  445. if '_' in var:
  446. self._setvar_update_overrides(base, **loginfo)
  447. if base in self.overridevars:
  448. self._setvar_update_overridevars(var, value)
  449. return
  450. if not var in self.dict:
  451. self._makeShadowCopy(var)
  452. if not parsing:
  453. if "_append" in self.dict[var]:
  454. del self.dict[var]["_append"]
  455. if "_prepend" in self.dict[var]:
  456. del self.dict[var]["_prepend"]
  457. if "_remove" in self.dict[var]:
  458. del self.dict[var]["_remove"]
  459. if var in self.overridedata:
  460. active = []
  461. self.need_overrides()
  462. for (r, o) in self.overridedata[var]:
  463. if o in self.overridesset:
  464. active.append(r)
  465. elif "_" in o:
  466. if set(o.split("_")).issubset(self.overridesset):
  467. active.append(r)
  468. for a in active:
  469. self.delVar(a)
  470. del self.overridedata[var]
  471. # more cookies for the cookie monster
  472. if '_' in var:
  473. self._setvar_update_overrides(var, **loginfo)
  474. # setting var
  475. self.dict[var]["_content"] = value
  476. self.varhistory.record(**loginfo)
  477. if var in self.overridevars:
  478. self._setvar_update_overridevars(var, value)
  479. def _setvar_update_overridevars(self, var, value):
  480. vardata = self.expandWithRefs(value, var)
  481. new = vardata.references
  482. new.update(vardata.contains.keys())
  483. while not new.issubset(self.overridevars):
  484. nextnew = set()
  485. self.overridevars.update(new)
  486. for i in new:
  487. vardata = self.expandWithRefs(self.getVar(i), i)
  488. nextnew.update(vardata.references)
  489. nextnew.update(vardata.contains.keys())
  490. new = nextnew
  491. self.internal_finalize(True)
  492. def _setvar_update_overrides(self, var, **loginfo):
  493. # aka pay the cookie monster
  494. override = var[var.rfind('_')+1:]
  495. shortvar = var[:var.rfind('_')]
  496. while override and __override_regexp__.match(override):
  497. if shortvar not in self.overridedata:
  498. self.overridedata[shortvar] = []
  499. if [var, override] not in self.overridedata[shortvar]:
  500. # Force CoW by recreating the list first
  501. self.overridedata[shortvar] = list(self.overridedata[shortvar])
  502. self.overridedata[shortvar].append([var, override])
  503. override = None
  504. if "_" in shortvar:
  505. override = var[shortvar.rfind('_')+1:]
  506. shortvar = var[:shortvar.rfind('_')]
  507. if len(shortvar) == 0:
  508. override = None
  509. def getVar(self, var, expand=True, noweakdefault=False, parsing=False):
  510. return self.getVarFlag(var, "_content", expand, noweakdefault, parsing)
  511. def renameVar(self, key, newkey, **loginfo):
  512. """
  513. Rename the variable key to newkey
  514. """
  515. if key == newkey:
  516. bb.warn("Calling renameVar with equivalent keys (%s) is invalid" % key)
  517. return
  518. val = self.getVar(key, 0, parsing=True)
  519. if val is not None:
  520. self.varhistory.rename_variable_hist(key, newkey)
  521. loginfo['variable'] = newkey
  522. loginfo['op'] = 'rename from %s' % key
  523. loginfo['detail'] = val
  524. self.varhistory.record(**loginfo)
  525. self.setVar(newkey, val, ignore=True, parsing=True)
  526. for i in (__setvar_keyword__):
  527. src = self.getVarFlag(key, i, False)
  528. if src is None:
  529. continue
  530. dest = self.getVarFlag(newkey, i, False) or []
  531. dest.extend(src)
  532. self.setVarFlag(newkey, i, dest, ignore=True)
  533. if key in self.overridedata:
  534. self.overridedata[newkey] = []
  535. for (v, o) in self.overridedata[key]:
  536. self.overridedata[newkey].append([v.replace(key, newkey), o])
  537. self.renameVar(v, v.replace(key, newkey))
  538. if '_' in newkey and val is None:
  539. self._setvar_update_overrides(newkey, **loginfo)
  540. loginfo['variable'] = key
  541. loginfo['op'] = 'rename (to)'
  542. loginfo['detail'] = newkey
  543. self.varhistory.record(**loginfo)
  544. self.delVar(key, ignore=True)
  545. def appendVar(self, var, value, **loginfo):
  546. loginfo['op'] = 'append'
  547. self.varhistory.record(**loginfo)
  548. self.setVar(var + "_append", value, ignore=True, parsing=True)
  549. def prependVar(self, var, value, **loginfo):
  550. loginfo['op'] = 'prepend'
  551. self.varhistory.record(**loginfo)
  552. self.setVar(var + "_prepend", value, ignore=True, parsing=True)
  553. def delVar(self, var, **loginfo):
  554. self.expand_cache = {}
  555. loginfo['detail'] = ""
  556. loginfo['op'] = 'del'
  557. self.varhistory.record(**loginfo)
  558. self.dict[var] = {}
  559. if var in self.overridedata:
  560. del self.overridedata[var]
  561. if '_' in var:
  562. override = var[var.rfind('_')+1:]
  563. shortvar = var[:var.rfind('_')]
  564. while override and override.islower():
  565. try:
  566. if shortvar in self.overridedata:
  567. # Force CoW by recreating the list first
  568. self.overridedata[shortvar] = list(self.overridedata[shortvar])
  569. self.overridedata[shortvar].remove([var, override])
  570. except ValueError as e:
  571. pass
  572. override = None
  573. if "_" in shortvar:
  574. override = var[shortvar.rfind('_')+1:]
  575. shortvar = var[:shortvar.rfind('_')]
  576. if len(shortvar) == 0:
  577. override = None
  578. def setVarFlag(self, var, flag, value, **loginfo):
  579. self.expand_cache = {}
  580. if 'op' not in loginfo:
  581. loginfo['op'] = "set"
  582. loginfo['flag'] = flag
  583. self.varhistory.record(**loginfo)
  584. if not var in self.dict:
  585. self._makeShadowCopy(var)
  586. self.dict[var][flag] = value
  587. if flag == "_defaultval" and '_' in var:
  588. self._setvar_update_overrides(var, **loginfo)
  589. if flag == "_defaultval" and var in self.overridevars:
  590. self._setvar_update_overridevars(var, value)
  591. if flag == "unexport" or flag == "export":
  592. if not "__exportlist" in self.dict:
  593. self._makeShadowCopy("__exportlist")
  594. if not "_content" in self.dict["__exportlist"]:
  595. self.dict["__exportlist"]["_content"] = set()
  596. self.dict["__exportlist"]["_content"].add(var)
  597. def getVarFlag(self, var, flag, expand=True, noweakdefault=False, parsing=False, retparser=False):
  598. if flag == "_content":
  599. cachename = var
  600. else:
  601. if not flag:
  602. bb.warn("Calling getVarFlag with flag unset is invalid")
  603. return None
  604. cachename = var + "[" + flag + "]"
  605. if expand and cachename in self.expand_cache:
  606. return self.expand_cache[cachename].value
  607. local_var, overridedata = self._findVar(var)
  608. value = None
  609. removes = set()
  610. if flag == "_content" and overridedata is not None and not parsing:
  611. match = False
  612. active = {}
  613. self.need_overrides()
  614. for (r, o) in overridedata:
  615. # What about double overrides both with "_" in the name?
  616. if o in self.overridesset:
  617. active[o] = r
  618. elif "_" in o:
  619. if set(o.split("_")).issubset(self.overridesset):
  620. active[o] = r
  621. mod = True
  622. while mod:
  623. mod = False
  624. for o in self.overrides:
  625. for a in active.copy():
  626. if a.endswith("_" + o):
  627. t = active[a]
  628. del active[a]
  629. active[a.replace("_" + o, "")] = t
  630. mod = True
  631. elif a == o:
  632. match = active[a]
  633. del active[a]
  634. if match:
  635. value, subparser = self.getVarFlag(match, "_content", False, retparser=True)
  636. if hasattr(subparser, "removes"):
  637. # We have to carry the removes from the overridden variable to apply at the
  638. # end of processing
  639. removes = subparser.removes
  640. if local_var is not None and value is None:
  641. if flag in local_var:
  642. value = copy.copy(local_var[flag])
  643. elif flag == "_content" and "_defaultval" in local_var and not noweakdefault:
  644. value = copy.copy(local_var["_defaultval"])
  645. if flag == "_content" and local_var is not None and "_append" in local_var and not parsing:
  646. if not value:
  647. value = ""
  648. self.need_overrides()
  649. for (r, o) in local_var["_append"]:
  650. match = True
  651. if o:
  652. for o2 in o.split("_"):
  653. if not o2 in self.overrides:
  654. match = False
  655. if match:
  656. value = value + r
  657. if flag == "_content" and local_var is not None and "_prepend" in local_var and not parsing:
  658. if not value:
  659. value = ""
  660. self.need_overrides()
  661. for (r, o) in local_var["_prepend"]:
  662. match = True
  663. if o:
  664. for o2 in o.split("_"):
  665. if not o2 in self.overrides:
  666. match = False
  667. if match:
  668. value = r + value
  669. parser = None
  670. if expand or retparser:
  671. parser = self.expandWithRefs(value, cachename)
  672. if expand:
  673. value = parser.value
  674. if value and flag == "_content" and local_var is not None and "_remove" in local_var and not parsing:
  675. self.need_overrides()
  676. for (r, o) in local_var["_remove"]:
  677. match = True
  678. if o:
  679. for o2 in o.split("_"):
  680. if not o2 in self.overrides:
  681. match = False
  682. if match:
  683. removes.add(r)
  684. if value and flag == "_content" and not parsing:
  685. if removes and parser:
  686. expanded_removes = {}
  687. for r in removes:
  688. expanded_removes[r] = self.expand(r).split()
  689. parser.removes = set()
  690. val = ""
  691. for v in __whitespace_split__.split(parser.value):
  692. skip = False
  693. for r in removes:
  694. if v in expanded_removes[r]:
  695. parser.removes.add(r)
  696. skip = True
  697. if skip:
  698. continue
  699. val = val + v
  700. parser.value = val
  701. if expand:
  702. value = parser.value
  703. if parser:
  704. self.expand_cache[cachename] = parser
  705. if retparser:
  706. return value, parser
  707. return value
  708. def delVarFlag(self, var, flag, **loginfo):
  709. self.expand_cache = {}
  710. local_var, _ = self._findVar(var)
  711. if not local_var:
  712. return
  713. if not var in self.dict:
  714. self._makeShadowCopy(var)
  715. if var in self.dict and flag in self.dict[var]:
  716. loginfo['detail'] = ""
  717. loginfo['op'] = 'delFlag'
  718. loginfo['flag'] = flag
  719. self.varhistory.record(**loginfo)
  720. del self.dict[var][flag]
  721. def appendVarFlag(self, var, flag, value, **loginfo):
  722. loginfo['op'] = 'append'
  723. loginfo['flag'] = flag
  724. self.varhistory.record(**loginfo)
  725. newvalue = (self.getVarFlag(var, flag, False) or "") + value
  726. self.setVarFlag(var, flag, newvalue, ignore=True)
  727. def prependVarFlag(self, var, flag, value, **loginfo):
  728. loginfo['op'] = 'prepend'
  729. loginfo['flag'] = flag
  730. self.varhistory.record(**loginfo)
  731. newvalue = value + (self.getVarFlag(var, flag, False) or "")
  732. self.setVarFlag(var, flag, newvalue, ignore=True)
  733. def setVarFlags(self, var, flags, **loginfo):
  734. self.expand_cache = {}
  735. infer_caller_details(loginfo)
  736. if not var in self.dict:
  737. self._makeShadowCopy(var)
  738. for i in flags:
  739. if i == "_content":
  740. continue
  741. loginfo['flag'] = i
  742. loginfo['detail'] = flags[i]
  743. self.varhistory.record(**loginfo)
  744. self.dict[var][i] = flags[i]
  745. def getVarFlags(self, var, expand = False, internalflags=False):
  746. local_var, _ = self._findVar(var)
  747. flags = {}
  748. if local_var:
  749. for i in local_var:
  750. if i.startswith("_") and not internalflags:
  751. continue
  752. flags[i] = local_var[i]
  753. if expand and i in expand:
  754. flags[i] = self.expand(flags[i], var + "[" + i + "]")
  755. if len(flags) == 0:
  756. return None
  757. return flags
  758. def delVarFlags(self, var, **loginfo):
  759. self.expand_cache = {}
  760. if not var in self.dict:
  761. self._makeShadowCopy(var)
  762. if var in self.dict:
  763. content = None
  764. loginfo['op'] = 'delete flags'
  765. self.varhistory.record(**loginfo)
  766. # try to save the content
  767. if "_content" in self.dict[var]:
  768. content = self.dict[var]["_content"]
  769. self.dict[var] = {}
  770. self.dict[var]["_content"] = content
  771. else:
  772. del self.dict[var]
  773. def createCopy(self):
  774. """
  775. Create a copy of self by setting _data to self
  776. """
  777. # we really want this to be a DataSmart...
  778. data = DataSmart()
  779. data.dict["_data"] = self.dict
  780. data.varhistory = self.varhistory.copy()
  781. data.varhistory.dataroot = data
  782. data.inchistory = self.inchistory.copy()
  783. data._tracking = self._tracking
  784. data.overrides = None
  785. data.overridevars = copy.copy(self.overridevars)
  786. # Should really be a deepcopy but has heavy overhead.
  787. # Instead, we're careful with writes.
  788. data.overridedata = copy.copy(self.overridedata)
  789. return data
  790. def expandVarref(self, variable, parents=False):
  791. """Find all references to variable in the data and expand it
  792. in place, optionally descending to parent datastores."""
  793. if parents:
  794. keys = iter(self)
  795. else:
  796. keys = self.localkeys()
  797. ref = '${%s}' % variable
  798. value = self.getVar(variable, False)
  799. for key in keys:
  800. referrervalue = self.getVar(key, False)
  801. if referrervalue and ref in referrervalue:
  802. self.setVar(key, referrervalue.replace(ref, value))
  803. def localkeys(self):
  804. for key in self.dict:
  805. if key not in ['_data']:
  806. yield key
  807. def __iter__(self):
  808. deleted = set()
  809. overrides = set()
  810. def keylist(d):
  811. klist = set()
  812. for key in d:
  813. if key in ["_data"]:
  814. continue
  815. if key in deleted:
  816. continue
  817. if key in overrides:
  818. continue
  819. if not d[key]:
  820. deleted.add(key)
  821. continue
  822. klist.add(key)
  823. if "_data" in d:
  824. klist |= keylist(d["_data"])
  825. return klist
  826. self.need_overrides()
  827. for var in self.overridedata:
  828. for (r, o) in self.overridedata[var]:
  829. if o in self.overridesset:
  830. overrides.add(var)
  831. elif "_" in o:
  832. if set(o.split("_")).issubset(self.overridesset):
  833. overrides.add(var)
  834. for k in keylist(self.dict):
  835. yield k
  836. for k in overrides:
  837. yield k
  838. def __len__(self):
  839. return len(frozenset(iter(self)))
  840. def __getitem__(self, item):
  841. value = self.getVar(item, False)
  842. if value is None:
  843. raise KeyError(item)
  844. else:
  845. return value
  846. def __setitem__(self, var, value):
  847. self.setVar(var, value)
  848. def __delitem__(self, var):
  849. self.delVar(var)
  850. def get_hash(self):
  851. data = {}
  852. d = self.createCopy()
  853. bb.data.expandKeys(d)
  854. config_whitelist = set((d.getVar("BB_HASHCONFIG_WHITELIST") or "").split())
  855. keys = set(key for key in iter(d) if not key.startswith("__"))
  856. for key in keys:
  857. if key in config_whitelist:
  858. continue
  859. value = d.getVar(key, False) or ""
  860. if type(value) is type(self):
  861. data.update({key:value.get_hash()})
  862. else:
  863. data.update({key:value})
  864. varflags = d.getVarFlags(key, internalflags = True)
  865. if not varflags:
  866. continue
  867. for f in varflags:
  868. if f == "_content":
  869. continue
  870. data.update({'%s[%s]' % (key, f):varflags[f]})
  871. for key in ["__BBTASKS", "__BBANONFUNCS", "__BBHANDLERS"]:
  872. bb_list = d.getVar(key, False) or []
  873. data.update({key:str(bb_list)})
  874. if key == "__BBANONFUNCS":
  875. for i in bb_list:
  876. value = d.getVar(i, False) or ""
  877. data.update({i:value})
  878. data_str = str([(k, data[k]) for k in sorted(data.keys())])
  879. return hashlib.sha256(data_str.encode("utf-8")).hexdigest()