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_smart
38 _dict_type = data_smart.DataSmart
39 _dict_p_type = data_smart.DataSmartPackage
41 class DataDictFull(dict):
43 This implements our Package Data Storage Interface.
44 setDirty is a no op as all items are held in memory
46 def setDirty(self, bbfile, data):
48 No-Op we assume data was manipulated as some sort of
51 if not bbfile in self:
52 raise Exception("File %s was not in dictionary before" % bbfile)
58 Databacked Dictionary implementation
60 def __init__(self, cache_dir, config):
61 self.cache_dir = cache_dir
66 def has_key(self,key):
67 return key in self.files
72 def __setitem__(self, key, data):
74 Add the key to the list of known files and
75 place the data in the cache?
80 self.files.append(key)
82 def __getitem__(self, key):
83 if not key in self.files:
86 # if it was dirty we will
88 return self.dirty[key]
91 return _dict_p_type(self.cache_dir, key,False,self.config)
93 def setDirty(self, bbfile, data):
95 Only already added items can be declared dirty!!!
98 if not bbfile in self.files:
99 raise Exception("File %s was not in dictionary before" % bbfile)
101 self.dirty[bbfile] = data
108 def init_db(cache,name,clean,parent = None):
109 return _dict_p_type(cache,name,clean,parent)
111 def init_db_mtime(cache,cache_bbfile):
112 return _dict_p_type.mtime(cache,cache_bbfile)
114 def pkgdata(use_cache, cache, config = None):
116 Return some sort of dictionary to lookup parsed dictionaires
119 return DataDictCache(cache, config)
120 return DataDictFull()
122 def createCopy(source):
123 """Link the source set to the destination
124 If one does not find the value in the destination set,
125 search will go on to the source set to get the value.
126 Value from source are copy-on-write. i.e. any try to
127 modify one of them will end up putting the modified value
128 in the destination set.
130 return source.createCopy()
133 """Non-destructive var init for data structure"""
137 def setVar(var, value, d):
138 """Set a variable to a given value
142 >>> setVar('TEST', 'testcontents', d)
143 >>> print getVar('TEST', d)
149 def getVar(var, d, exp = 0):
150 """Gets the value of a variable
154 >>> setVar('TEST', 'testcontents', d)
155 >>> print getVar('TEST', d)
158 return d.getVar(var,exp)
161 """Removes a variable from the data set
165 >>> setVar('TEST', 'testcontents', d)
166 >>> print getVar('TEST', d)
168 >>> delVar('TEST', d)
169 >>> print getVar('TEST', d)
174 def setVarFlag(var, flag, flagvalue, d):
175 """Set a flag for a given variable to a given value
179 >>> setVarFlag('TEST', 'python', 1, d)
180 >>> print getVarFlag('TEST', 'python', d)
183 d.setVarFlag(var,flag,flagvalue)
185 def getVarFlag(var, flag, d):
186 """Gets given flag from given var
190 >>> setVarFlag('TEST', 'python', 1, d)
191 >>> print getVarFlag('TEST', 'python', d)
194 return d.getVarFlag(var,flag)
196 def delVarFlag(var, flag, d):
197 """Removes a given flag from the variable's flags
201 >>> setVarFlag('TEST', 'testflag', 1, d)
202 >>> print getVarFlag('TEST', 'testflag', d)
204 >>> delVarFlag('TEST', 'testflag', d)
205 >>> print getVarFlag('TEST', 'testflag', d)
209 d.delVarFlag(var,flag)
211 def setVarFlags(var, flags, d):
212 """Set the flags for a given variable
217 >>> myflags['test'] = 'blah'
218 >>> setVarFlags('TEST', myflags, d)
219 >>> print getVarFlag('TEST', 'test', d)
222 d.setVarFlags(var,flags)
224 def getVarFlags(var, d):
225 """Gets a variable's flags
229 >>> setVarFlag('TEST', 'test', 'blah', d)
230 >>> print getVarFlags('TEST', d)['test']
233 return d.getVarFlags(var)
235 def delVarFlags(var, d):
236 """Removes a variable's flags
240 >>> setVarFlag('TEST', 'testflag', 1, data)
241 >>> print getVarFlag('TEST', 'testflag', data)
243 >>> delVarFlags('TEST', data)
244 >>> print getVarFlags('TEST', data)
251 """Return a list of keys in d
255 >>> setVar('TEST', 1, d)
256 >>> setVar('MOO' , 2, d)
257 >>> setVarFlag('TEST', 'test', 1, d)
264 """Returns the data object used"""
267 def setData(newData, d):
268 """Sets the data object to the supplied value"""
271 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
272 __expand_python_regexp__ = re.compile(r"\${@.+?}")
274 def expand(s, d, varname = None):
275 """Variable expansion using the data store.
280 >>> setVar('A', 'sshd', d)
281 >>> print expand('/usr/bin/${A}', d)
286 >>> print expand('result: ${@37 * 72}', d)
291 >>> print expand('${TARGET_MOO}', d)
293 >>> setVar('TARGET_MOO', 'yupp', d)
294 >>> print expand('${TARGET_MOO}',d)
296 >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
297 >>> delVar('TARGET_MOO', d)
298 >>> print expand('${SRC_URI}', d)
299 http://somebug.${TARGET_MOO}
302 key = match.group()[2:-1]
305 raise Exception("variable %s references itself!" % varname)
306 var = getVar(key, d, 1)
312 def python_sub(match):
314 code = match.group()[3:-1]
317 if type(s) == types.IntType: s = str(s)
320 if type(s) is not types.StringType: # sanity check
323 while s.find('$') != -1:
326 s = __expand_var_regexp__.sub(var_sub, s)
327 s = __expand_python_regexp__.sub(python_sub, s)
329 if type(s) is not types.StringType: # sanity check
331 bb.error('expansion of %s returned non-string %s' % (olds, s))
332 except KeyboardInterrupt:
335 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
339 def expandKeys(alterdata, readdata = None):
343 for key in keys(alterdata):
344 ekey = expand(key, readdata)
347 val = getVar(key, alterdata)
351 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
352 setVar(ekey, val, alterdata)
354 for i in ('_append', '_prepend', '_delete'):
355 dest = getVarFlag(ekey, i, alterdata) or []
356 src = getVarFlag(key, i, readdata) or []
358 setVarFlag(ekey, i, dest, alterdata)
360 delVar(key, alterdata)
362 def expandData(alterdata, readdata = None):
363 """For each variable in alterdata, expand it, and update the var contents.
364 Replacements use data from readdata.
369 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
370 >>> setVar("DL_DIR", "/path/to/whatever", b)
372 >>> print getVar("dlmsg", a)
373 dl_dir is /path/to/whatever
378 for key in keys(alterdata):
379 val = getVar(key, alterdata)
380 if type(val) is not types.StringType:
382 expanded = expand(val, readdata)
383 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
385 setVar(key, expanded, alterdata)
389 def inheritFromOS(d):
390 """Inherit variables from the environment."""
391 # fakeroot needs to be able to set these
392 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
393 for s in os.environ.keys():
394 if not s in non_inherit_vars:
396 setVar(s, os.environ[s], d)
397 setVarFlag(s, 'matchesenv', '1', d)
403 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
404 """Emit a variable to be sourced by a shell."""
405 if getVarFlag(var, "python", d):
410 oval = getVar(var, d, 0)
411 val = getVar(var, d, 1)
412 except KeyboardInterrupt:
415 excname = str(sys.exc_info()[0])
416 if excname == "bb.build.FuncFailed":
418 o.write('# expansion of %s threw %s\n' % (var, excname))
422 o.write('# %s=%s\n' % (var, oval))
424 if type(val) is not types.StringType:
427 if getVarFlag(var, 'matchesenv', d):
430 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
437 if getVarFlag(var, "func", d):
438 # NOTE: should probably check for unbalanced {} within the var
439 o.write("%s() {\n%s\n}\n" % (var, val))
441 if getVarFlag(var, "export", d):
446 # if we're going to output this within doublequotes,
447 # to a shell, we need to escape the quotes in the var
448 alter = re.sub('"', '\\"', val.strip())
449 o.write('%s="%s"\n' % (var, alter))
453 def emit_env(o=sys.__stdout__, d = init(), all=False):
454 """Emits all items in the data store in a format such that it can be sourced by a shell."""
459 if getVarFlag(e, "func", d):
461 emit_var(e, o, d, all) and o.write('\n')
464 if not getVarFlag(e, "func", d):
466 emit_var(e, o, d) and o.write('\n')
469 """Modifies the environment vars according to local overrides and commands.
471 Appending to a variable:
473 >>> setVar('TEST', 'this is a', d)
474 >>> setVar('TEST_append', ' test', d)
475 >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
477 >>> print getVar('TEST', d)
478 this is a test of the emergency broadcast system.
480 Prepending to a variable:
481 >>> setVar('TEST', 'virtual/libc', d)
482 >>> setVar('TEST_prepend', 'virtual/tmake ', d)
483 >>> setVar('TEST_prepend', 'virtual/patcher ', d)
485 >>> print getVar('TEST', d)
486 virtual/patcher virtual/tmake virtual/libc
489 >>> setVar('TEST_arm', 'target', d)
490 >>> setVar('TEST_ramses', 'machine', d)
491 >>> setVar('TEST_local', 'local', d)
492 >>> setVar('OVERRIDES', 'arm', d)
494 >>> setVar('TEST', 'original', d)
496 >>> print getVar('TEST', d)
499 >>> setVar('OVERRIDES', 'arm:ramses:local', d)
500 >>> setVar('TEST', 'original', d)
502 >>> print getVar('TEST', d)
506 debug(2, "update_data()")
508 # can't do delete env[...] while iterating over the dictionary, so remember them
510 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
512 def applyOverrides(var, d):
514 debug(1, "OVERRIDES not defined, nothing to do")
518 if var.endswith("_" + o):
525 sval = getVar(s, d) or ""
527 # Handle line appends:
528 for (a, o) in getVarFlag(s, '_append', d) or []:
529 # maybe the OVERRIDE was not yet added so keep the append
530 if (o and o in overrides) or not o:
531 delVarFlag(s, '_append', d)
533 if not o in overrides:
538 # Handle line prepends
539 for (a, o) in getVarFlag(s, '_prepend', d) or []:
540 # maybe the OVERRIDE was not yet added so keep the append
541 if (o and o in overrides) or not o:
542 delVarFlag(s, '_prepend', d)
544 if not o in overrides:
549 # Handle line deletions
551 nameval = getVar(name, d)
556 pattern = nameval.replace('\n','').strip()
557 for line in sval.split('\n'):
558 if line.find(pattern) == -1:
559 new = new + '\n' + line
563 # delete all environment vars no longer needed
567 def inherits_class(klass, d):
568 val = getVar('__inherit_cache', d) or ""
569 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
574 """Start a doctest run on this module"""
577 doctest.testmod(data)
579 if __name__ == "__main__":