1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 BitBake 'Data' implementations
6 Functions for interacting with the data structure used by the
9 The expandData and update_data are the most expensive
10 operations. At night the cookie monster came by and
11 suggested 'give me cookies on setting the variables and
12 things will work out'. Taking this suggestion into account
13 applying the skills from the not yet passed 'Entwurf und
14 Analyse von Algorithmen' lecture and the cookie
15 monster seems to be right. We will track setVar more carefully
16 to have faster update_data and expandKeys operations.
18 This is a treade-off between speed and memory again but
19 the speed is more critical here.
22 # Copyright (C) 2003, 2004 Chris Larson
23 # Copyright (C) 2005 Holger Hans Peter Freyther
25 # This program is free software; you can redistribute it and/or modify
26 # it under the terms of the GNU General Public License version 2 as
27 # published by the Free Software Foundation.
29 # This program is distributed in the hope that it will be useful,
30 # but WITHOUT ANY WARRANTY; without even the implied warranty of
31 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 # GNU General Public License for more details.
34 # You should have received a copy of the GNU General Public License along
35 # with this program; if not, write to the Free Software Foundation, Inc.,
36 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 #Based on functions from the base bb module, Copyright 2003 Holger Schurig
40 import sys, os, re, time, types
41 if sys.argv[0][-5:] == "pydoc":
42 path = os.path.dirname(os.path.dirname(sys.argv[1]))
44 path = os.path.dirname(os.path.dirname(sys.argv[0]))
45 sys.path.insert(0,path)
47 from bb import data_smart
50 _dict_type = data_smart.DataSmart
55 def init_db(parent = None):
57 return parent.createCopy()
61 def createCopy(source):
62 """Link the source set to the destination
63 If one does not find the value in the destination set,
64 search will go on to the source set to get the value.
65 Value from source are copy-on-write. i.e. any try to
66 modify one of them will end up putting the modified value
67 in the destination set.
69 return source.createCopy()
72 """Non-destructive var init for data structure"""
76 def setVar(var, value, d):
77 """Set a variable to a given value
81 >>> setVar('TEST', 'testcontents', d)
82 >>> print getVar('TEST', d)
88 def getVar(var, d, exp = 0):
89 """Gets the value of a variable
93 >>> setVar('TEST', 'testcontents', d)
94 >>> print getVar('TEST', d)
97 return d.getVar(var,exp)
100 """Removes a variable from the data set
104 >>> setVar('TEST', 'testcontents', d)
105 >>> print getVar('TEST', d)
107 >>> delVar('TEST', d)
108 >>> print getVar('TEST', d)
113 def setVarFlag(var, flag, flagvalue, d):
114 """Set a flag for a given variable to a given value
118 >>> setVarFlag('TEST', 'python', 1, d)
119 >>> print getVarFlag('TEST', 'python', d)
122 d.setVarFlag(var,flag,flagvalue)
124 def getVarFlag(var, flag, d):
125 """Gets given flag from given var
129 >>> setVarFlag('TEST', 'python', 1, d)
130 >>> print getVarFlag('TEST', 'python', d)
133 return d.getVarFlag(var,flag)
135 def delVarFlag(var, flag, d):
136 """Removes a given flag from the variable's flags
140 >>> setVarFlag('TEST', 'testflag', 1, d)
141 >>> print getVarFlag('TEST', 'testflag', d)
143 >>> delVarFlag('TEST', 'testflag', d)
144 >>> print getVarFlag('TEST', 'testflag', d)
148 d.delVarFlag(var,flag)
150 def setVarFlags(var, flags, d):
151 """Set the flags for a given variable
154 setVarFlags will not clear previous
155 flags. Think of this method as
161 >>> myflags['test'] = 'blah'
162 >>> setVarFlags('TEST', myflags, d)
163 >>> print getVarFlag('TEST', 'test', d)
166 d.setVarFlags(var,flags)
168 def getVarFlags(var, d):
169 """Gets a variable's flags
173 >>> setVarFlag('TEST', 'test', 'blah', d)
174 >>> print getVarFlags('TEST', d)['test']
177 return d.getVarFlags(var)
179 def delVarFlags(var, d):
180 """Removes a variable's flags
184 >>> setVarFlag('TEST', 'testflag', 1, data)
185 >>> print getVarFlag('TEST', 'testflag', data)
187 >>> delVarFlags('TEST', data)
188 >>> print getVarFlags('TEST', data)
195 """Return a list of keys in d
199 >>> setVar('TEST', 1, d)
200 >>> setVar('MOO' , 2, d)
201 >>> setVarFlag('TEST', 'test', 1, d)
208 """Returns the data object used"""
211 def setData(newData, d):
212 """Sets the data object to the supplied value"""
217 ## Cookie Monsters' query functions
219 def _get_override_vars(d, override):
223 Get the Names of Variables that have a specific
224 override. This function returns a iterable
229 def _get_var_flags_triple(d):
236 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
237 __expand_python_regexp__ = re.compile(r"\${@.+?}")
239 def expand(s, d, varname = None):
240 """Variable expansion using the data store.
245 >>> setVar('A', 'sshd', d)
246 >>> print expand('/usr/bin/${A}', d)
251 >>> print expand('result: ${@37 * 72}', d)
256 >>> print expand('${TARGET_MOO}', d)
258 >>> setVar('TARGET_MOO', 'yupp', d)
259 >>> print expand('${TARGET_MOO}',d)
261 >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
262 >>> delVar('TARGET_MOO', d)
263 >>> print expand('${SRC_URI}', d)
264 http://somebug.${TARGET_MOO}
266 return d.expand(s, varname)
268 def expandKeys(alterdata, readdata = None):
272 for key in keys(alterdata):
276 ekey = expand(key, readdata)
279 val = getVar(key, alterdata)
283 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
284 setVar(ekey, val, alterdata)
286 for i in ('_append', '_prepend'):
287 dest = getVarFlag(ekey, i, alterdata) or []
288 src = getVarFlag(key, i, readdata) or []
290 setVarFlag(ekey, i, dest, alterdata)
292 delVar(key, alterdata)
294 def expandData(alterdata, readdata = None):
295 """For each variable in alterdata, expand it, and update the var contents.
296 Replacements use data from readdata.
301 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
302 >>> setVar("DL_DIR", "/path/to/whatever", b)
304 >>> print getVar("dlmsg", a)
305 dl_dir is /path/to/whatever
310 for key in keys(alterdata):
311 val = getVar(key, alterdata)
312 if type(val) is not types.StringType:
314 expanded = expand(val, readdata)
315 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
317 setVar(key, expanded, alterdata)
321 def inheritFromOS(d):
322 """Inherit variables from the environment."""
323 # fakeroot needs to be able to set these
324 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
325 for s in os.environ.keys():
326 if not s in non_inherit_vars:
328 setVar(s, os.environ[s], d)
329 setVarFlag(s, 'matchesenv', '1', d)
335 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
336 """Emit a variable to be sourced by a shell."""
337 if getVarFlag(var, "python", d):
342 oval = getVar(var, d, 0)
343 val = getVar(var, d, 1)
344 except KeyboardInterrupt:
347 excname = str(sys.exc_info()[0])
348 if excname == "bb.build.FuncFailed":
350 o.write('# expansion of %s threw %s\n' % (var, excname))
354 o.write('# %s=%s\n' % (var, oval))
356 if type(val) is not types.StringType:
359 if getVarFlag(var, 'matchesenv', d):
362 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
369 varExpanded = expand(var, d)
371 if getVarFlag(var, "func", d):
372 # NOTE: should probably check for unbalanced {} within the var
373 o.write("%s() {\n%s\n}\n" % (varExpanded, val))
375 if getVarFlag(var, "unexport", d):
376 o.write('unset %s\n' % varExpanded)
378 if getVarFlag(var, "export", d):
383 # if we're going to output this within doublequotes,
384 # to a shell, we need to escape the quotes in the var
385 alter = re.sub('"', '\\"', val.strip())
386 o.write('%s="%s"\n' % (varExpanded, alter))
390 def emit_env(o=sys.__stdout__, d = init(), all=False):
391 """Emits all items in the data store in a format such that it can be sourced by a shell."""
396 if getVarFlag(e, "func", d):
398 emit_var(e, o, d, all) and o.write('\n')
401 if not getVarFlag(e, "func", d):
403 emit_var(e, o, d) and o.write('\n')
406 """Modifies the environment vars according to local overrides and commands.
408 Appending to a variable:
410 >>> setVar('TEST', 'this is a', d)
411 >>> setVar('TEST_append', ' test', d)
412 >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
414 >>> print getVar('TEST', d)
415 this is a test of the emergency broadcast system.
417 Prepending to a variable:
418 >>> setVar('TEST', 'virtual/libc', d)
419 >>> setVar('TEST_prepend', 'virtual/tmake ', d)
420 >>> setVar('TEST_prepend', 'virtual/patcher ', d)
422 >>> print getVar('TEST', d)
423 virtual/patcher virtual/tmake virtual/libc
426 >>> setVar('TEST_arm', 'target', d)
427 >>> setVar('TEST_ramses', 'machine', d)
428 >>> setVar('TEST_local', 'local', d)
429 >>> setVar('OVERRIDES', 'arm', d)
431 >>> setVar('TEST', 'original', d)
433 >>> print getVar('TEST', d)
436 >>> setVar('OVERRIDES', 'arm:ramses:local', d)
437 >>> setVar('TEST', 'original', d)
439 >>> print getVar('TEST', d)
443 >>> e = d.createCopy()
444 >>> setVar('TEST_foo', 'foo', e)
446 >>> print getVar('TEST', e)
449 >>> setVar('OVERRIDES', 'arm:ramses:local:foo', e)
451 >>> print getVar('TEST', e)
454 >>> f = d.createCopy()
455 >>> setVar('TEST_moo', 'something', f)
456 >>> setVar('OVERRIDES', 'moo:arm:ramses:local:foo', e)
458 >>> print getVar('TEST', e)
463 >>> setVar('SRC_URI', 'file://append.foo;patch=1 ', h)
464 >>> g = h.createCopy()
465 >>> setVar('SRC_URI_append_arm', 'file://other.foo;patch=1', g)
466 >>> setVar('OVERRIDES', 'arm:moo', g)
468 >>> print getVar('SRC_URI', g)
469 file://append.foo;patch=1 file://other.foo;patch=1
472 bb.msg.debug(2, bb.msg.domain.Data, "update_data()")
474 # now ask the cookie monster for help
475 #print "Cookie Monster"
476 #print "Append/Prepend %s" % d._special_values
477 #print "Overrides %s" % d._seen_overrides
479 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
482 # Well let us see what breaks here. We used to iterate
483 # over each variable and apply the override and then
484 # do the line expanding.
485 # If we have bad luck - which we will have - the keys
486 # where in some order that is so important for this
487 # method which we don't have anymore.
488 # Anyway we will fix that and write test cases this
492 # First we apply all overrides
493 # Then we will handle _append and _prepend
497 # calculate '_'+override
500 # see if one should even try
501 if not d._seen_overrides.has_key(o):
504 vars = d._seen_overrides[o]
510 bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar")
512 # now on to the appends and prepends
513 if d._special_values.has_key('_append'):
514 appends = d._special_values['_append'] or []
515 for append in appends:
516 for (a, o) in getVarFlag(append, '_append', d) or []:
517 # maybe the OVERRIDE was not yet added so keep the append
518 if (o and o in overrides) or not o:
519 delVarFlag(append, '_append', d)
520 if o and not o in overrides:
523 sval = getVar(append,d) or ""
525 setVar(append, sval, d)
528 if d._special_values.has_key('_prepend'):
529 prepends = d._special_values['_prepend'] or []
531 for prepend in prepends:
532 for (a, o) in getVarFlag(prepend, '_prepend', d) or []:
533 # maybe the OVERRIDE was not yet added so keep the prepend
534 if (o and o in overrides) or not o:
535 delVarFlag(prepend, '_prepend', d)
536 if o and not o in overrides:
539 sval = a + (getVar(prepend,d) or "")
540 setVar(prepend, sval, d)
543 def inherits_class(klass, d):
544 val = getVar('__inherit_cache', d) or []
545 if os.path.join('classes', '%s.bbclass' % klass) in val:
550 """Start a doctest run on this module"""
553 doctest.testmod(data)
555 if __name__ == "__main__":