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)
91 def createCopy(source):
92 """Link the source set to the destination
93 If one does not find the value in the destination set,
94 search will go on to the source set to get the value.
95 Value from source are copy-on-write. i.e. any try to
96 modify one of them will end up putting the modified value
97 in the destination set.
99 return source.createCopy()
102 """Non-destructive var init for data structure"""
106 def setVar(var, value, d):
107 """Set a variable to a given value
110 >>> setVar('TEST', 'testcontents')
111 >>> print getVar('TEST')
117 def getVar(var, d, exp = 0):
118 """Gets the value of a variable
121 >>> setVar('TEST', 'testcontents')
122 >>> print getVar('TEST')
125 return d.getVar(var,exp)
128 """Removes a variable from the data set
131 >>> setVar('TEST', 'testcontents')
132 >>> print getVar('TEST')
135 >>> print getVar('TEST')
140 def setVarFlag(var, flag, flagvalue, d):
141 """Set a flag for a given variable to a given value
144 >>> setVarFlag('TEST', 'python', 1)
145 >>> print getVarFlag('TEST', 'python')
148 d.setVarFlag(var,flag,flagvalue)
150 def getVarFlag(var, flag, d):
151 """Gets given flag from given var
154 >>> setVarFlag('TEST', 'python', 1)
155 >>> print getVarFlag('TEST', 'python')
158 return d.getVarFlag(var,flag)
160 def delVarFlag(var, flag, d):
161 """Removes a given flag from the variable's flags
164 >>> setVarFlag('TEST', 'testflag', 1)
165 >>> print getVarFlag('TEST', 'testflag')
167 >>> delVarFlag('TEST', 'testflag')
168 >>> print getVarFlag('TEST', 'testflag')
172 d.delVarFlag(var,flag)
174 def setVarFlags(var, flags, d):
175 """Set the flags for a given variable
179 >>> myflags['test'] = 'blah'
180 >>> setVarFlags('TEST', myflags)
181 >>> print getVarFlag('TEST', 'test')
184 d.setVarFlags(var,flags)
186 def getVarFlags(var, d):
187 """Gets a variable's flags
190 >>> setVarFlag('TEST', 'test', 'blah')
191 >>> print getVarFlags('TEST')['test']
194 return d.getVarFlags(var)
196 def delVarFlags(var, d):
197 """Removes a variable's flags
201 >>> setVarFlag('TEST', 'testflag', 1, data)
202 >>> print getVarFlag('TEST', 'testflag', data)
204 >>> delVarFlags('TEST', data)
205 >>> print getVarFlags('TEST', data)
212 """Return a list of keys in d
216 >>> setVar('TEST', 1, d)
217 >>> setVar('MOO' , 2, d)
218 >>> setVarFlag('TEST', 'test', 1, d)
225 """Returns the data object used"""
228 def setData(newData, d):
229 """Sets the data object to the supplied value"""
232 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
233 __expand_python_regexp__ = re.compile(r"\${@.+?}")
235 def expand(s, d, varname = None):
236 """Variable expansion using the data store.
240 >>> setVar('A', 'sshd')
241 >>> print expand('/usr/bin/${A}')
245 >>> print expand('result: ${@37 * 72}')
249 key = match.group()[2:-1]
252 raise Exception("variable %s references itself!" % varname)
253 var = getVar(key, d, 1)
259 def python_sub(match):
261 code = match.group()[3:-1]
264 if type(s) == types.IntType: s = str(s)
267 if type(s) is not types.StringType: # sanity check
270 while s.find('$') != -1:
273 s = __expand_var_regexp__.sub(var_sub, s)
274 s = __expand_python_regexp__.sub(python_sub, s)
276 if type(s) is not types.StringType: # sanity check
278 bb.error('expansion of %s returned non-string %s' % (olds, s))
279 except KeyboardInterrupt:
282 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
286 def expandKeys(alterdata, readdata = None):
290 for key in keys(alterdata):
291 ekey = expand(key, readdata)
294 val = getVar(key, alterdata)
298 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
299 setVar(ekey, val, alterdata)
301 for i in ('_append', '_prepend', '_delete'):
302 dest = getVarFlag(ekey, i, alterdata) or []
303 src = getVarFlag(key, i, readdata) or []
305 setVarFlag(ekey, i, dest, alterdata)
307 delVar(key, alterdata)
309 def expandData(alterdata, readdata = None):
310 """For each variable in alterdata, expand it, and update the var contents.
311 Replacements use data from readdata.
316 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
317 >>> setVar("DL_DIR", "/path/to/whatever", b)
319 >>> print getVar("dlmsg", a)
320 dl_dir is /path/to/whatever
325 for key in keys(alterdata):
326 val = getVar(key, alterdata)
327 if type(val) is not types.StringType:
329 expanded = expand(val, readdata)
330 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
332 setVar(key, expanded, alterdata)
336 def inheritFromOS(d):
337 """Inherit variables from the environment."""
338 # fakeroot needs to be able to set these
339 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
340 for s in os.environ.keys():
341 if not s in non_inherit_vars:
343 setVar(s, os.environ[s], d)
344 setVarFlag(s, 'matchesenv', '1', d)
350 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
351 """Emit a variable to be sourced by a shell."""
352 if getVarFlag(var, "python", d):
357 oval = getVar(var, d, 0)
358 val = getVar(var, d, 1)
359 except KeyboardInterrupt:
362 excname = str(sys.exc_info()[0])
363 if excname == "bb.build.FuncFailed":
365 o.write('# expansion of %s threw %s\n' % (var, excname))
369 o.write('# %s=%s\n' % (var, oval))
371 if type(val) is not types.StringType:
374 if getVarFlag(var, 'matchesenv', d):
377 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
384 if getVarFlag(var, "func", d):
385 # NOTE: should probably check for unbalanced {} within the var
386 o.write("%s() {\n%s\n}\n" % (var, val))
388 if getVarFlag(var, "export", d):
393 # if we're going to output this within doublequotes,
394 # to a shell, we need to escape the quotes in the var
395 alter = re.sub('"', '\\"', val.strip())
396 o.write('%s="%s"\n' % (var, alter))
400 def emit_env(o=sys.__stdout__, d = init(), all=False):
401 """Emits all items in the data store in a format such that it can be sourced by a shell."""
406 if getVarFlag(e, "func", d):
408 emit_var(e, o, d, all) and o.write('\n')
411 if not getVarFlag(e, "func", d):
413 emit_var(e, o, d) and o.write('\n')
416 """Modifies the environment vars according to local overrides and commands.
418 Appending to a variable:
419 >>> setVar('TEST', 'this is a')
420 >>> setVar('TEST_append', ' test')
421 >>> setVar('TEST_append', ' of the emergency broadcast system.')
423 >>> print getVar('TEST')
424 this is a test of the emergency broadcast system.
426 Prepending to a variable:
427 >>> setVar('TEST', 'virtual/libc')
428 >>> setVar('TEST_prepend', 'virtual/tmake ')
429 >>> setVar('TEST_prepend', 'virtual/patcher ')
431 >>> print getVar('TEST')
432 virtual/patcher virtual/tmake virtual/libc
435 >>> setVar('TEST_arm', 'target')
436 >>> setVar('TEST_ramses', 'machine')
437 >>> setVar('TEST_local', 'local')
438 >>> setVar('OVERRIDES', 'arm')
440 >>> setVar('TEST', 'original')
442 >>> print getVar('TEST')
445 >>> setVar('OVERRIDES', 'arm:ramses:local')
446 >>> setVar('TEST', 'original')
448 >>> print getVar('TEST')
452 debug(2, "update_data()")
454 # can't do delete env[...] while iterating over the dictionary, so remember them
456 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
458 def applyOverrides(var, d):
460 debug(1, "OVERRIDES not defined, nothing to do")
464 if var.endswith("_" + o):
471 sval = getVar(s, d) or ""
473 # Handle line appends:
474 for (a, o) in getVarFlag(s, '_append', d) or []:
475 # maybe the OVERRIDE was not yet added so keep the append
476 if (o and o in overrides) or not o:
477 delVarFlag(s, '_append', d)
479 if not o in overrides:
484 # Handle line prepends
485 for (a, o) in getVarFlag(s, '_prepend', d) or []:
486 # maybe the OVERRIDE was not yet added so keep the append
487 if (o and o in overrides) or not o:
488 delVarFlag(s, '_prepend', d)
490 if not o in overrides:
495 # Handle line deletions
497 nameval = getVar(name, d)
502 pattern = nameval.replace('\n','').strip()
503 for line in sval.split('\n'):
504 if line.find(pattern) == -1:
505 new = new + '\n' + line
509 # delete all environment vars no longer needed
513 def inherits_class(klass, d):
514 val = getVar('__inherit_cache', d) or ""
515 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
520 """Start a doctest run on this module"""
523 doctest.testmod(data)
525 if __name__ == "__main__":