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
39 _dict_p_type = data_dict.DataDictPackage
43 Databacked Dictionary implementation
45 def __init__(self, cache_dir):
46 self.cache_dir = cache_dir
49 def has_key(self,key):
50 return key in self.files
55 def __setitem__(self, key, data):
57 Add the key to the list of known files and
58 place the data in the cache?
63 self.files.append(key)
65 def __getitem__(self, key):
66 if not key in self.files:
70 return _dict_p_type(self.cache_dir, key,False,None)
77 def init_db(cache,name,clean,parent = None):
78 return _dict_p_type(cache,name,clean,parent)
80 def init_db_mtime(cache,cache_bbfile):
81 return _dict_p_type.mtime(cache,cache_bbfile)
83 def pkgdata(use_cache, cache):
85 Return some sort of dictionary to lookup parsed dictionaires
88 return DataDictCache(cache)
93 def createCopy(source):
94 """Link the source set to the destination
95 If one does not find the value in the destination set,
96 search will go on to the source set to get the value.
97 Value from source are copy-on-write. i.e. any try to
98 modify one of them will end up putting the modified value
99 in the destination set.
101 return source.createCopy()
103 def initVar(var, d = _data_dict):
104 """Non-destructive var init for data structure"""
108 def setVar(var, value, d = _data_dict):
109 """Set a variable to a given value
112 >>> setVar('TEST', 'testcontents')
113 >>> print getVar('TEST')
119 def getVar(var, d = _data_dict, exp = 0):
120 """Gets the value of a variable
123 >>> setVar('TEST', 'testcontents')
124 >>> print getVar('TEST')
127 return d.getVar(var,exp)
129 def delVar(var, d = _data_dict):
130 """Removes a variable from the data set
133 >>> setVar('TEST', 'testcontents')
134 >>> print getVar('TEST')
137 >>> print getVar('TEST')
142 def setVarFlag(var, flag, flagvalue, d = _data_dict):
143 """Set a flag for a given variable to a given value
146 >>> setVarFlag('TEST', 'python', 1)
147 >>> print getVarFlag('TEST', 'python')
150 d.setVarFlag(var,flag,flagvalue)
152 def getVarFlag(var, flag, d = _data_dict):
153 """Gets given flag from given var
156 >>> setVarFlag('TEST', 'python', 1)
157 >>> print getVarFlag('TEST', 'python')
160 return d.getVarFlag(var,flag)
162 def delVarFlag(var, flag, d = _data_dict):
163 """Removes a given flag from the variable's flags
166 >>> setVarFlag('TEST', 'testflag', 1)
167 >>> print getVarFlag('TEST', 'testflag')
169 >>> delVarFlag('TEST', 'testflag')
170 >>> print getVarFlag('TEST', 'testflag')
174 d.delVarFlag(var,flag)
176 def setVarFlags(var, flags, d = _data_dict):
177 """Set the flags for a given variable
181 >>> myflags['test'] = 'blah'
182 >>> setVarFlags('TEST', myflags)
183 >>> print getVarFlag('TEST', 'test')
186 d.setVarFlags(var,flags)
188 def getVarFlags(var, d = _data_dict):
189 """Gets a variable's flags
192 >>> setVarFlag('TEST', 'test', 'blah')
193 >>> print getVarFlags('TEST')['test']
196 return d.getVarFlags(var)
198 def delVarFlags(var, d = _data_dict):
199 """Removes a variable's flags
203 >>> setVarFlag('TEST', 'testflag', 1, data)
204 >>> print getVarFlag('TEST', 'testflag', data)
206 >>> delVarFlags('TEST', data)
207 >>> print getVarFlags('TEST', data)
213 def keys(d = _data_dict):
214 """Return a list of keys in d
218 >>> setVar('TEST', 1, d)
219 >>> setVar('MOO' , 2, d)
220 >>> setVarFlag('TEST', 'test', 1, d)
226 def getData(d = _data_dict):
227 """Returns the data object used"""
230 def setData(newData, d = _data_dict):
231 """Sets the data object to the supplied value"""
234 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
235 __expand_python_regexp__ = re.compile(r"\${@.+?}")
237 def expand(s, d = _data_dict, varname = None):
238 """Variable expansion using the data store.
242 >>> setVar('A', 'sshd')
243 >>> print expand('/usr/bin/${A}')
247 >>> print expand('result: ${@37 * 72}')
251 key = match.group()[2:-1]
254 raise Exception("variable %s references itself!" % varname)
255 var = getVar(key, d, 1)
261 def python_sub(match):
263 code = match.group()[3:-1]
266 if type(s) == types.IntType: s = str(s)
269 if type(s) is not types.StringType: # sanity check
272 while s.find('$') != -1:
275 s = __expand_var_regexp__.sub(var_sub, s)
276 s = __expand_python_regexp__.sub(python_sub, s)
278 if type(s) is not types.StringType: # sanity check
280 bb.error('expansion of %s returned non-string %s' % (olds, s))
281 except KeyboardInterrupt:
284 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
288 def expandKeys(alterdata = _data_dict, readdata = None):
292 for key in keys(alterdata):
293 ekey = expand(key, readdata)
296 val = getVar(key, alterdata)
300 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
301 setVar(ekey, val, alterdata)
303 for i in ('_append', '_prepend', '_delete'):
304 dest = getVarFlag(ekey, i, alterdata) or []
305 src = getVarFlag(key, i, readdata) or []
307 setVarFlag(ekey, i, dest, alterdata)
309 delVar(key, alterdata)
311 def expandData(alterdata = _data_dict, readdata = None):
312 """For each variable in alterdata, expand it, and update the var contents.
313 Replacements use data from readdata.
318 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
319 >>> setVar("DL_DIR", "/path/to/whatever", b)
321 >>> print getVar("dlmsg", a)
322 dl_dir is /path/to/whatever
327 for key in keys(alterdata):
328 val = getVar(key, alterdata)
329 if type(val) is not types.StringType:
331 expanded = expand(val, readdata)
332 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
334 setVar(key, expanded, alterdata)
338 def inheritFromOS(d = _data_dict):
339 """Inherit variables from the environment."""
340 # fakeroot needs to be able to set these
341 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
342 for s in os.environ.keys():
343 if not s in non_inherit_vars:
345 setVar(s, os.environ[s], d)
346 setVarFlag(s, 'matchesenv', '1', d)
352 def emit_var(var, o=sys.__stdout__, d = _data_dict, all=False):
353 """Emit a variable to be sourced by a shell."""
354 if getVarFlag(var, "python", d):
359 oval = getVar(var, d, 0)
360 val = getVar(var, d, 1)
361 except KeyboardInterrupt:
364 excname = str(sys.exc_info()[0])
365 if excname == "bb.build.FuncFailed":
367 o.write('# expansion of %s threw %s\n' % (var, excname))
371 o.write('# %s=%s\n' % (var, oval))
373 if type(val) is not types.StringType:
376 if getVarFlag(var, 'matchesenv', d):
379 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
386 if getVarFlag(var, "func", d):
387 # NOTE: should probably check for unbalanced {} within the var
388 o.write("%s() {\n%s\n}\n" % (var, val))
390 if getVarFlag(var, "export", d):
395 # if we're going to output this within doublequotes,
396 # to a shell, we need to escape the quotes in the var
397 alter = re.sub('"', '\\"', val.strip())
398 o.write('%s="%s"\n' % (var, alter))
402 def emit_env(o=sys.__stdout__, d = _data_dict, all=False):
403 """Emits all items in the data store in a format such that it can be sourced by a shell."""
408 if getVarFlag(e, "func", d):
410 emit_var(e, o, d, all) and o.write('\n')
413 if not getVarFlag(e, "func", d):
415 emit_var(e, o, d) and o.write('\n')
417 def update_data(d = _data_dict):
418 """Modifies the environment vars according to local overrides and commands.
420 Appending to a variable:
421 >>> setVar('TEST', 'this is a')
422 >>> setVar('TEST_append', ' test')
423 >>> setVar('TEST_append', ' of the emergency broadcast system.')
425 >>> print getVar('TEST')
426 this is a test of the emergency broadcast system.
428 Prepending to a variable:
429 >>> setVar('TEST', 'virtual/libc')
430 >>> setVar('TEST_prepend', 'virtual/tmake ')
431 >>> setVar('TEST_prepend', 'virtual/patcher ')
433 >>> print getVar('TEST')
434 virtual/patcher virtual/tmake virtual/libc
437 >>> setVar('TEST_arm', 'target')
438 >>> setVar('TEST_ramses', 'machine')
439 >>> setVar('TEST_local', 'local')
440 >>> setVar('OVERRIDES', 'arm')
442 >>> setVar('TEST', 'original')
444 >>> print getVar('TEST')
447 >>> setVar('OVERRIDES', 'arm:ramses:local')
448 >>> setVar('TEST', 'original')
450 >>> print getVar('TEST')
454 debug(2, "update_data()")
456 # can't do delete env[...] while iterating over the dictionary, so remember them
458 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
460 def applyOverrides(var, d = _data_dict):
462 debug(1, "OVERRIDES not defined, nothing to do")
466 if var.endswith("_" + o):
473 sval = getVar(s, d) or ""
475 # Handle line appends:
476 for (a, o) in getVarFlag(s, '_append', d) or []:
477 # maybe the OVERRIDE was not yet added so keep the append
478 if (o and o in overrides) or not o:
479 delVarFlag(s, '_append', d)
481 if not o in overrides:
486 # Handle line prepends
487 for (a, o) in getVarFlag(s, '_prepend', d) or []:
488 # maybe the OVERRIDE was not yet added so keep the append
489 if (o and o in overrides) or not o:
490 delVarFlag(s, '_prepend', d)
492 if not o in overrides:
497 # Handle line deletions
499 nameval = getVar(name, d)
504 pattern = nameval.replace('\n','').strip()
505 for line in sval.split('\n'):
506 if line.find(pattern) == -1:
507 new = new + '\n' + line
511 # delete all environment vars no longer needed
515 def inherits_class(klass, d):
516 val = getVar('__inherit_cache', d) or ""
517 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
522 """Start a doctest run on this module"""
525 doctest.testmod(data)
527 if __name__ == "__main__":