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
12 This program is free software; you can redistribute it and/or modify it under
13 the terms of the GNU General Public License as published by the Free Software
14 Foundation; either version 2 of the License, or (at your option) any later
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23 Place, Suite 330, Boston, MA 02111-1307 USA.
25 Based on functions from the base bb module, Copyright 2003 Holger Schurig
28 import sys, os, re, time, types
29 if sys.argv[0][-5:] == "pydoc":
30 path = os.path.dirname(os.path.dirname(sys.argv[1]))
32 path = os.path.dirname(os.path.dirname(sys.argv[0]))
35 from bb import note, debug
42 def initVar(var, d = _data):
43 """Non-destructive var init for data structure"""
47 if not "flags" in d[var]:
50 __setvar_regexp__ = {}
51 __setvar_regexp__["_append"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_append")
52 __setvar_regexp__["_prepend"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_prepend")
53 __setvar_regexp__["_delete"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_delete")
55 def setVar(var, value, d = _data):
56 """Set a variable to a given value
59 >>> setVar('TEST', 'testcontents')
60 >>> print getVar('TEST')
63 for v in ["_append", "_prepend", "_delete"]:
64 match = __setvar_regexp__[v].match(var)
66 base = match.group('base')
67 override = match.group('add')
68 l = getVarFlag(base, v, d) or []
69 if override == 'delete':
70 if l.count([value, None]):
71 del l[l.index([value, None])]
72 l.append([value, override])
73 setVarFlag(base, v, l, d)
78 if getVarFlag(var, 'matchesenv', d):
79 delVarFlag(var, 'matchesenv', d)
80 setVarFlag(var, 'export', 1, d)
81 d[var]["content"] = value
83 def getVar(var, d = _data, exp = 0):
84 """Gets the value of a variable
87 >>> setVar('TEST', 'testcontents')
88 >>> print getVar('TEST')
91 if not var in d or not "content" in d[var]:
94 return expand(d[var]["content"], d, var)
95 return d[var]["content"]
97 def delVar(var, d = _data):
98 """Removes a variable from the data set
101 >>> setVar('TEST', 'testcontents')
102 >>> print getVar('TEST')
105 >>> print getVar('TEST')
111 def setVarFlag(var, flag, flagvalue, d = _data):
112 """Set a flag for a given variable to a given value
115 >>> setVarFlag('TEST', 'python', 1)
116 >>> print getVarFlag('TEST', 'python')
119 # print "d[%s][\"flags\"][%s] = %s" % (var, flag, flagvalue)
122 d[var]["flags"][flag] = flagvalue
124 def getVarFlag(var, flag, d = _data):
125 """Gets given flag from given var
128 >>> setVarFlag('TEST', 'python', 1)
129 >>> print getVarFlag('TEST', 'python')
132 if var in d and "flags" in d[var] and flag in d[var]["flags"]:
133 return d[var]["flags"][flag]
136 def delVarFlag(var, flag, d = _data):
137 """Removes a given flag from the variable's flags
140 >>> setVarFlag('TEST', 'testflag', 1)
141 >>> print getVarFlag('TEST', 'testflag')
143 >>> delVarFlag('TEST', 'testflag')
144 >>> print getVarFlag('TEST', 'testflag')
148 if var in d and "flags" in d[var] and flag in d[var]["flags"]:
149 del d[var]["flags"][flag]
151 def setVarFlags(var, flags, d = _data):
152 """Set the flags for a given variable
156 >>> myflags['test'] = 'blah'
157 >>> setVarFlags('TEST', myflags)
158 >>> print getVarFlag('TEST', 'test')
163 d[var]["flags"] = flags
165 def getVarFlags(var, d = _data):
166 """Gets a variable's flags
169 >>> setVarFlag('TEST', 'test', 'blah')
170 >>> print getVarFlags('TEST')['test']
173 if var in d and "flags" in d[var]:
174 return d[var]["flags"]
177 def delVarFlags(var, d = _data):
178 """Removes a variable's flags
181 >>> setVarFlag('TEST', 'testflag', 1)
182 >>> print getVarFlag('TEST', 'testflag')
184 >>> delVarFlags('TEST')
185 >>> print getVarFlags('TEST')
189 if var in d and "flags" in d[var]:
192 def getData(d = _data):
193 """Returns the data object used"""
196 def setData(newData, d = _data):
197 """Sets the data object to the supplied value"""
200 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
201 __expand_python_regexp__ = re.compile(r"\${@.+?}")
203 def expand(s, d = _data, varname = None):
204 """Variable expansion using the data store.
208 >>> setVar('A', 'sshd')
209 >>> print expand('/usr/bin/${A}')
213 >>> print expand('result: ${@37 * 72}')
217 key = match.group()[2:-1]
220 raise Exception("variable %s references itself!" % varname)
221 var = getVar(key, d, 1)
227 def python_sub(match):
229 code = match.group()[3:-1]
232 if type(s) == types.IntType: s = str(s)
235 if type(s) is not types.StringType: # sanity check
238 while s.find('$') != -1:
241 s = __expand_var_regexp__.sub(var_sub, s)
242 s = __expand_python_regexp__.sub(python_sub, s)
244 if type(s) is not types.StringType: # sanity check
246 bb.error('expansion of %s returned non-string %s' % (olds, s))
249 bb.note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
253 def expandKeys(alterdata = _data, readdata = None):
257 for key in alterdata.keys():
258 ekey = expand(key, readdata)
261 val = getVar(key, alterdata)
265 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
266 setVar(ekey, val, alterdata)
268 for i in ('_append', '_prepend', '_delete'):
269 dest = getVarFlag(ekey, i, alterdata) or []
270 src = getVarFlag(key, i, readdata) or []
272 setVarFlag(ekey, i, dest, alterdata)
274 delVar(key, alterdata)
276 def expandData(alterdata = _data, readdata = None):
277 """For each variable in alterdata, expand it, and update the var contents.
278 Replacements use data from readdata.
283 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
284 >>> setVar("DL_DIR", "/path/to/whatever", b)
286 >>> print getVar("dlmsg", a)
287 dl_dir is /path/to/whatever
292 for key in alterdata.keys():
293 val = getVar(key, alterdata)
294 if type(val) is not types.StringType:
296 expanded = expand(val, readdata)
297 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
299 setVar(key, expanded, alterdata)
303 def inheritFromOS(d = _data):
304 """Inherit variables from the environment."""
305 # fakeroot needs to be able to set these
306 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
307 for s in os.environ.keys():
308 if not s in non_inherit_vars:
310 setVar(s, os.environ[s], d)
311 setVarFlag(s, 'matchesenv', '1', d)
317 def emit_var(var, o=sys.__stdout__, d = _data, all=False):
318 """Emit a variable to be sourced by a shell."""
319 if getVarFlag(var, "python", d):
324 oval = getVar(var, d, 0)
325 val = getVar(var, d, 1)
326 except KeyboardInterrupt:
329 o.write('# expansion of %s threw %s\n' % (var, sys.exc_info()[0]))
333 o.write('# %s=%s\n' % (var, oval))
335 if type(val) is not types.StringType:
338 if getVarFlag(var, 'matchesenv', d):
341 if var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1:
348 if getVarFlag(var, "func", d):
349 # NOTE: should probably check for unbalanced {} within the var
350 o.write("%s() {\n%s\n}\n" % (var, val))
352 if getVarFlag(var, "export", d):
357 # if we're going to output this within doublequotes,
358 # to a shell, we need to escape the quotes in the var
359 alter = re.sub('"', '\\"', val.strip())
360 o.write('%s="%s"\n' % (var, alter))
364 def emit_env(o=sys.__stdout__, d = _data, all=False):
365 """Emits all items in the data store in a format such that it can be sourced by a shell."""
370 if getVarFlag(e, "func", d):
372 emit_var(e, o, d, all) and o.write('\n')
375 if not getVarFlag(e, "func", d):
377 emit_var(e, o, d) and o.write('\n')
379 def update_data(d = _data):
380 """Modifies the environment vars according to local overrides and commands.
382 Appending to a variable:
383 >>> setVar('TEST', 'this is a')
384 >>> setVar('TEST_append', ' test')
385 >>> setVar('TEST_append', ' of the emergency broadcast system.')
387 >>> print getVar('TEST')
388 this is a test of the emergency broadcast system.
390 Prepending to a variable:
391 >>> setVar('TEST', 'virtual/libc')
392 >>> setVar('TEST_prepend', 'virtual/tmake ')
393 >>> setVar('TEST_prepend', 'virtual/patcher ')
395 >>> print getVar('TEST')
396 virtual/patcher virtual/tmake virtual/libc
399 >>> setVar('TEST_arm', 'target')
400 >>> setVar('TEST_ramses', 'machine')
401 >>> setVar('TEST_local', 'local')
402 >>> setVar('OVERRIDES', 'arm')
404 >>> setVar('TEST', 'original')
406 >>> print getVar('TEST')
409 >>> setVar('OVERRIDES', 'arm:ramses:local')
410 >>> setVar('TEST', 'original')
412 >>> print getVar('TEST')
416 debug(2, "update_data()")
418 # can't do delete env[...] while iterating over the dictionary, so remember them
420 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
422 def applyOverrides(var, d = _data):
424 debug(1, "OVERRIDES not defined, nothing to do")
428 if var.endswith("_" + o):
435 sval = getVar(s, d) or ""
437 # Handle line appends:
438 for (a, o) in getVarFlag(s, '_append', d) or []:
439 # maybe the OVERRIDE was not yet added so keep the append
440 if (o and o in overrides) or not o:
441 delVarFlag(s, '_append', d)
443 if not o in overrides:
448 # Handle line prepends
449 for (a, o) in getVarFlag(s, '_prepend', d) or []:
450 # maybe the OVERRIDE was not yet added so keep the append
451 if (o and o in overrides) or not o:
452 delVarFlag(s, '_prepend', d)
454 if not o in overrides:
459 # Handle line deletions
461 nameval = getVar(name, d)
466 pattern = nameval.replace('\n','').strip()
467 for line in sval.split('\n'):
468 if line.find(pattern) == -1:
469 new = new + '\n' + line
473 # delete all environment vars no longer needed
477 def inherits_class(klass, d):
478 val = getVar('__inherit_cache', d) or ""
479 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
484 """Start a doctest run on this module"""
487 doctest.testmod(data)
489 if __name__ == "__main__":