2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
5 BitBake 'Data' implementations
7 Functions for interacting with the data structure used by the
10 The expandData and update_data are the most expensive
11 operations. At night the cookie monster came by and
12 suggested 'give me cookies on setting the variables and
13 things will work out'. Taking this suggestion into account
14 applying the skills from the not yet passed 'Entwurf und
15 Analyse von Algorithmen' lecture and the cookie
16 monster seems to be right. We will track setVar more carefully
17 to have faster update_data and expandKeys operations.
19 This is a treade-off between speed and memory again but
20 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 it under
26 the terms of the GNU General Public License as published by the Free Software
27 Foundation; either version 2 of the License, or (at your option) any later
30 This program is distributed in the hope that it will be useful, but WITHOUT
31 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
34 You should have received a copy of the GNU General Public License along with
35 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
36 Place, Suite 330, Boston, MA 02111-1307 USA.
38 Based on functions from the base bb module, Copyright 2003 Holger Schurig
41 import sys, os, re, time, types
42 if sys.argv[0][-5:] == "pydoc":
43 path = os.path.dirname(os.path.dirname(sys.argv[1]))
45 path = os.path.dirname(os.path.dirname(sys.argv[0]))
46 sys.path.insert(0,path)
48 from bb import note, debug, 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):
273 ekey = expand(key, readdata)
276 val = getVar(key, alterdata)
280 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
281 setVar(ekey, val, alterdata)
283 for i in ('_append', '_prepend'):
284 dest = getVarFlag(ekey, i, alterdata) or []
285 src = getVarFlag(key, i, readdata) or []
287 setVarFlag(ekey, i, dest, alterdata)
289 delVar(key, alterdata)
291 def expandData(alterdata, readdata = None):
292 """For each variable in alterdata, expand it, and update the var contents.
293 Replacements use data from readdata.
298 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
299 >>> setVar("DL_DIR", "/path/to/whatever", b)
301 >>> print getVar("dlmsg", a)
302 dl_dir is /path/to/whatever
307 for key in keys(alterdata):
308 val = getVar(key, alterdata)
309 if type(val) is not types.StringType:
311 expanded = expand(val, readdata)
312 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
314 setVar(key, expanded, alterdata)
318 def inheritFromOS(d):
319 """Inherit variables from the environment."""
320 # fakeroot needs to be able to set these
321 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
322 for s in os.environ.keys():
323 if not s in non_inherit_vars:
325 setVar(s, os.environ[s], d)
326 setVarFlag(s, 'matchesenv', '1', d)
332 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
333 """Emit a variable to be sourced by a shell."""
334 if getVarFlag(var, "python", d):
339 oval = getVar(var, d, 0)
340 val = getVar(var, d, 1)
341 except KeyboardInterrupt:
344 excname = str(sys.exc_info()[0])
345 if excname == "bb.build.FuncFailed":
347 o.write('# expansion of %s threw %s\n' % (var, excname))
351 o.write('# %s=%s\n' % (var, oval))
353 if type(val) is not types.StringType:
356 if getVarFlag(var, 'matchesenv', d):
359 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
366 if getVarFlag(var, "func", d):
367 # NOTE: should probably check for unbalanced {} within the var
368 o.write("%s() {\n%s\n}\n" % (var, val))
370 if getVarFlag(var, "export", d):
375 # if we're going to output this within doublequotes,
376 # to a shell, we need to escape the quotes in the var
377 alter = re.sub('"', '\\"', val.strip())
378 o.write('%s="%s"\n' % (var, alter))
382 def emit_env(o=sys.__stdout__, d = init(), all=False):
383 """Emits all items in the data store in a format such that it can be sourced by a shell."""
388 if getVarFlag(e, "func", d):
390 emit_var(e, o, d, all) and o.write('\n')
393 if not getVarFlag(e, "func", d):
395 emit_var(e, o, d) and o.write('\n')
398 """Modifies the environment vars according to local overrides and commands.
400 Appending to a variable:
402 >>> setVar('TEST', 'this is a', d)
403 >>> setVar('TEST_append', ' test', d)
404 >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
406 >>> print getVar('TEST', d)
407 this is a test of the emergency broadcast system.
409 Prepending to a variable:
410 >>> setVar('TEST', 'virtual/libc', d)
411 >>> setVar('TEST_prepend', 'virtual/tmake ', d)
412 >>> setVar('TEST_prepend', 'virtual/patcher ', d)
414 >>> print getVar('TEST', d)
415 virtual/patcher virtual/tmake virtual/libc
418 >>> setVar('TEST_arm', 'target', d)
419 >>> setVar('TEST_ramses', 'machine', d)
420 >>> setVar('TEST_local', 'local', d)
421 >>> setVar('OVERRIDES', 'arm', d)
423 >>> setVar('TEST', 'original', d)
425 >>> print getVar('TEST', d)
428 >>> setVar('OVERRIDES', 'arm:ramses:local', d)
429 >>> setVar('TEST', 'original', d)
431 >>> print getVar('TEST', d)
434 debug(2, "update_data()")
436 # now ask the cookie monster for help
437 #print "Cookie Monster"
438 #print "Append/Prepend %s" % d._special_values
439 #print "Overrides %s" % d._seen_overrides
441 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
444 # Well let us see what breaks here. We used to iterate
445 # over each variable and apply the override and then
446 # do the line expanding.
447 # If we have bad luck - which we will have - the keys
448 # where in some order that is so important for this
449 # method which we don't have anymore.
450 # Anyway we will fix that and write test cases this
454 # First we apply all overrides
455 # Then we will handle _append and _prepend
459 # calculate '_'+override
462 # see if one should even try
463 if not o in d._seen_overrides:
466 vars = d._seen_overrides[o]
472 note ("Untracked delVar")
474 # now on to the appends and prepends
475 if '_append' in d._special_values:
476 appends = d._special_values['_append'] or []
477 for append in appends:
478 for (a, o) in getVarFlag(append, '_append', d) or []:
479 # maybe the OVERRIDE was not yet added so keep the append
480 if (o and o in overrides) or not o:
481 delVarFlag(append, '_append', d)
482 if o and not o in overrides:
485 sval = getVar(append,d) or ""
487 setVar(append, sval, d)
490 if '_prepend' in d._special_values:
491 prepends = d._special_values['_prepend'] or []
493 for prepend in prepends:
494 for (a, o) in getVarFlag(prepend, '_prepend', d) or []:
495 # maybe the OVERRIDE was not yet added so keep the prepend
496 if (o and o in overrides) or not o:
497 delVarFlag(prepend, '_prepend', d)
498 if o and not o in overrides:
501 sval = a + (getVar(prepend,d) or "")
502 setVar(prepend, sval, d)
505 def inherits_class(klass, d):
506 val = getVar('__inherit_cache', d) or ""
507 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
512 """Start a doctest run on this module"""
515 doctest.testmod(data)
517 if __name__ == "__main__":