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 Copyright (C) 2003, 2004 Chris Larson
11 Copyright (C) 2005 Holger Hans Peter Freyther
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License as published by the Free Software
15 Foundation; either version 2 of the License, or (at your option) any later
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
24 Place, Suite 330, Boston, MA 02111-1307 USA.
26 Based on functions from the base bb module, Copyright 2003 Holger Schurig
29 import sys, os, re, time, types
30 if sys.argv[0][-5:] == "pydoc":
31 path = os.path.dirname(os.path.dirname(sys.argv[1]))
33 path = os.path.dirname(os.path.dirname(sys.argv[0]))
36 from bb import note, debug, data_dict
38 _dict_type = data_dict.DataDict
46 def createCopy(source):
47 """Link the source set to the destination
48 If one does not find the value in the destination set,
49 search will go on to the source set to get the value.
50 Value from source are copy-on-write. i.e. any try to
51 modify one of them will end up putting the modified value
52 in the destination set.
54 return source.createCopy()
56 def initVar(var, d = _data_dict):
57 """Non-destructive var init for data structure"""
61 def setVar(var, value, d = _data_dict):
62 """Set a variable to a given value
65 >>> setVar('TEST', 'testcontents')
66 >>> print getVar('TEST')
72 def getVar(var, d = _data_dict, exp = 0):
73 """Gets the value of a variable
76 >>> setVar('TEST', 'testcontents')
77 >>> print getVar('TEST')
80 return d.getVar(var,exp)
82 def delVar(var, d = _data_dict):
83 """Removes a variable from the data set
86 >>> setVar('TEST', 'testcontents')
87 >>> print getVar('TEST')
90 >>> print getVar('TEST')
95 def setVarFlag(var, flag, flagvalue, d = _data_dict):
96 """Set a flag for a given variable to a given value
99 >>> setVarFlag('TEST', 'python', 1)
100 >>> print getVarFlag('TEST', 'python')
103 d.setVarFlag(var,flag,flagvalue)
105 def getVarFlag(var, flag, d = _data_dict):
106 """Gets given flag from given var
109 >>> setVarFlag('TEST', 'python', 1)
110 >>> print getVarFlag('TEST', 'python')
113 return d.getVarFlag(var,flag)
115 def delVarFlag(var, flag, d = _data_dict):
116 """Removes a given flag from the variable's flags
119 >>> setVarFlag('TEST', 'testflag', 1)
120 >>> print getVarFlag('TEST', 'testflag')
122 >>> delVarFlag('TEST', 'testflag')
123 >>> print getVarFlag('TEST', 'testflag')
127 d.delVarFlag(var,flag)
129 def setVarFlags(var, flags, d = _data_dict):
130 """Set the flags for a given variable
134 >>> myflags['test'] = 'blah'
135 >>> setVarFlags('TEST', myflags)
136 >>> print getVarFlag('TEST', 'test')
139 d.setVarFlags(var,flags)
141 def getVarFlags(var, d = _data_dict):
142 """Gets a variable's flags
145 >>> setVarFlag('TEST', 'test', 'blah')
146 >>> print getVarFlags('TEST')['test']
149 return d.getVarFlags(var)
151 def delVarFlags(var, d = _data_dict):
152 """Removes a variable's flags
156 >>> setVarFlag('TEST', 'testflag', 1, data)
157 >>> print getVarFlag('TEST', 'testflag', data)
159 >>> delVarFlags('TEST', data)
160 >>> print getVarFlags('TEST', data)
166 def keys(d = _data_dict):
167 """Return a list of keys in d
171 >>> setVar('TEST', 1, d)
172 >>> setVar('MOO' , 2, d)
173 >>> setVarFlag('TEST', 'test', 1, d)
179 def getData(d = _data_dict):
180 """Returns the data object used"""
183 def setData(newData, d = _data_dict):
184 """Sets the data object to the supplied value"""
187 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
188 __expand_python_regexp__ = re.compile(r"\${@.+?}")
190 def expand(s, d = _data_dict, varname = None):
191 """Variable expansion using the data store.
195 >>> setVar('A', 'sshd')
196 >>> print expand('/usr/bin/${A}')
200 >>> print expand('result: ${@37 * 72}')
204 key = match.group()[2:-1]
207 raise Exception("variable %s references itself!" % varname)
208 var = getVar(key, d, 1)
214 def python_sub(match):
216 code = match.group()[3:-1]
219 if type(s) == types.IntType: s = str(s)
222 if type(s) is not types.StringType: # sanity check
225 while s.find('$') != -1:
228 s = __expand_var_regexp__.sub(var_sub, s)
229 s = __expand_python_regexp__.sub(python_sub, s)
231 if type(s) is not types.StringType: # sanity check
233 bb.error('expansion of %s returned non-string %s' % (olds, s))
234 except KeyboardInterrupt:
237 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
241 def expandKeys(alterdata = _data_dict, readdata = None):
245 for key in keys(alterdata):
246 ekey = expand(key, readdata)
249 val = getVar(key, alterdata)
253 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
254 setVar(ekey, val, alterdata)
256 for i in ('_append', '_prepend', '_delete'):
257 dest = getVarFlag(ekey, i, alterdata) or []
258 src = getVarFlag(key, i, readdata) or []
260 setVarFlag(ekey, i, dest, alterdata)
262 delVar(key, alterdata)
264 def expandData(alterdata = _data_dict, readdata = None):
265 """For each variable in alterdata, expand it, and update the var contents.
266 Replacements use data from readdata.
271 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
272 >>> setVar("DL_DIR", "/path/to/whatever", b)
274 >>> print getVar("dlmsg", a)
275 dl_dir is /path/to/whatever
280 for key in keys(alterdata):
281 val = getVar(key, alterdata)
282 if type(val) is not types.StringType:
284 expanded = expand(val, readdata)
285 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
287 setVar(key, expanded, alterdata)
291 def inheritFromOS(d = _data_dict):
292 """Inherit variables from the environment."""
293 # fakeroot needs to be able to set these
294 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
295 for s in os.environ.keys():
296 if not s in non_inherit_vars:
298 setVar(s, os.environ[s], d)
299 setVarFlag(s, 'matchesenv', '1', d)
305 def emit_var(var, o=sys.__stdout__, d = _data_dict, all=False):
306 """Emit a variable to be sourced by a shell."""
307 if getVarFlag(var, "python", d):
312 oval = getVar(var, d, 0)
313 val = getVar(var, d, 1)
314 except KeyboardInterrupt:
317 excname = str(sys.exc_info()[0])
318 if excname == "bb.build.FuncFailed":
320 o.write('# expansion of %s threw %s\n' % (var, excname))
324 o.write('# %s=%s\n' % (var, oval))
326 if type(val) is not types.StringType:
329 if getVarFlag(var, 'matchesenv', d):
332 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
339 if getVarFlag(var, "func", d):
340 # NOTE: should probably check for unbalanced {} within the var
341 o.write("%s() {\n%s\n}\n" % (var, val))
343 if getVarFlag(var, "export", d):
348 # if we're going to output this within doublequotes,
349 # to a shell, we need to escape the quotes in the var
350 alter = re.sub('"', '\\"', val.strip())
351 o.write('%s="%s"\n' % (var, alter))
355 def emit_env(o=sys.__stdout__, d = _data_dict, all=False):
356 """Emits all items in the data store in a format such that it can be sourced by a shell."""
361 if getVarFlag(e, "func", d):
363 emit_var(e, o, d, all) and o.write('\n')
366 if not getVarFlag(e, "func", d):
368 emit_var(e, o, d) and o.write('\n')
370 def update_data(d = _data_dict):
371 """Modifies the environment vars according to local overrides and commands.
373 Appending to a variable:
374 >>> setVar('TEST', 'this is a')
375 >>> setVar('TEST_append', ' test')
376 >>> setVar('TEST_append', ' of the emergency broadcast system.')
378 >>> print getVar('TEST')
379 this is a test of the emergency broadcast system.
381 Prepending to a variable:
382 >>> setVar('TEST', 'virtual/libc')
383 >>> setVar('TEST_prepend', 'virtual/tmake ')
384 >>> setVar('TEST_prepend', 'virtual/patcher ')
386 >>> print getVar('TEST')
387 virtual/patcher virtual/tmake virtual/libc
390 >>> setVar('TEST_arm', 'target')
391 >>> setVar('TEST_ramses', 'machine')
392 >>> setVar('TEST_local', 'local')
393 >>> setVar('OVERRIDES', 'arm')
395 >>> setVar('TEST', 'original')
397 >>> print getVar('TEST')
400 >>> setVar('OVERRIDES', 'arm:ramses:local')
401 >>> setVar('TEST', 'original')
403 >>> print getVar('TEST')
407 debug(2, "update_data()")
409 # can't do delete env[...] while iterating over the dictionary, so remember them
411 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
413 def applyOverrides(var, d = _data_dict):
415 debug(1, "OVERRIDES not defined, nothing to do")
419 if var.endswith("_" + o):
426 sval = getVar(s, d) or ""
428 # Handle line appends:
429 for (a, o) in getVarFlag(s, '_append', d) or []:
430 # maybe the OVERRIDE was not yet added so keep the append
431 if (o and o in overrides) or not o:
432 delVarFlag(s, '_append', d)
434 if not o in overrides:
439 # Handle line prepends
440 for (a, o) in getVarFlag(s, '_prepend', d) or []:
441 # maybe the OVERRIDE was not yet added so keep the append
442 if (o and o in overrides) or not o:
443 delVarFlag(s, '_prepend', d)
445 if not o in overrides:
450 # Handle line deletions
452 nameval = getVar(name, d)
457 pattern = nameval.replace('\n','').strip()
458 for line in sval.split('\n'):
459 if line.find(pattern) == -1:
460 new = new + '\n' + line
464 # delete all environment vars no longer needed
468 def inherits_class(klass, d):
469 val = getVar('__inherit_cache', d) or ""
470 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
475 """Start a doctest run on this module"""
478 doctest.testmod(data)
480 if __name__ == "__main__":