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]))
34 sys.path.insert(0,path)
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
215 setVarFlags will not clear previous
216 flags. Think of this method as
222 >>> myflags['test'] = 'blah'
223 >>> setVarFlags('TEST', myflags, d)
224 >>> print getVarFlag('TEST', 'test', d)
227 d.setVarFlags(var,flags)
229 def getVarFlags(var, d):
230 """Gets a variable's flags
234 >>> setVarFlag('TEST', 'test', 'blah', d)
235 >>> print getVarFlags('TEST', d)['test']
238 return d.getVarFlags(var)
240 def delVarFlags(var, d):
241 """Removes a variable's flags
245 >>> setVarFlag('TEST', 'testflag', 1, data)
246 >>> print getVarFlag('TEST', 'testflag', data)
248 >>> delVarFlags('TEST', data)
249 >>> print getVarFlags('TEST', data)
256 """Return a list of keys in d
260 >>> setVar('TEST', 1, d)
261 >>> setVar('MOO' , 2, d)
262 >>> setVarFlag('TEST', 'test', 1, d)
269 """Returns the data object used"""
272 def setData(newData, d):
273 """Sets the data object to the supplied value"""
276 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
277 __expand_python_regexp__ = re.compile(r"\${@.+?}")
279 def expand(s, d, varname = None):
280 """Variable expansion using the data store.
285 >>> setVar('A', 'sshd', d)
286 >>> print expand('/usr/bin/${A}', d)
291 >>> print expand('result: ${@37 * 72}', d)
296 >>> print expand('${TARGET_MOO}', d)
298 >>> setVar('TARGET_MOO', 'yupp', d)
299 >>> print expand('${TARGET_MOO}',d)
301 >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
302 >>> delVar('TARGET_MOO', d)
303 >>> print expand('${SRC_URI}', d)
304 http://somebug.${TARGET_MOO}
307 key = match.group()[2:-1]
310 raise Exception("variable %s references itself!" % varname)
311 var = getVar(key, d, 1)
317 def python_sub(match):
319 code = match.group()[3:-1]
322 if type(s) == types.IntType: s = str(s)
325 if type(s) is not types.StringType: # sanity check
328 while s.find('$') != -1:
331 s = __expand_var_regexp__.sub(var_sub, s)
332 s = __expand_python_regexp__.sub(python_sub, s)
334 if type(s) is not types.StringType: # sanity check
336 bb.error('expansion of %s returned non-string %s' % (olds, s))
337 except KeyboardInterrupt:
340 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
344 def expandKeys(alterdata, readdata = None):
348 for key in keys(alterdata):
349 ekey = expand(key, readdata)
352 val = getVar(key, alterdata)
356 # setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
357 setVar(ekey, val, alterdata)
359 for i in ('_append', '_prepend', '_delete'):
360 dest = getVarFlag(ekey, i, alterdata) or []
361 src = getVarFlag(key, i, readdata) or []
363 setVarFlag(ekey, i, dest, alterdata)
365 delVar(key, alterdata)
367 def expandData(alterdata, readdata = None):
368 """For each variable in alterdata, expand it, and update the var contents.
369 Replacements use data from readdata.
374 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
375 >>> setVar("DL_DIR", "/path/to/whatever", b)
377 >>> print getVar("dlmsg", a)
378 dl_dir is /path/to/whatever
383 for key in keys(alterdata):
384 val = getVar(key, alterdata)
385 if type(val) is not types.StringType:
387 expanded = expand(val, readdata)
388 # print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
390 setVar(key, expanded, alterdata)
394 def inheritFromOS(d):
395 """Inherit variables from the environment."""
396 # fakeroot needs to be able to set these
397 non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
398 for s in os.environ.keys():
399 if not s in non_inherit_vars:
401 setVar(s, os.environ[s], d)
402 setVarFlag(s, 'matchesenv', '1', d)
408 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
409 """Emit a variable to be sourced by a shell."""
410 if getVarFlag(var, "python", d):
415 oval = getVar(var, d, 0)
416 val = getVar(var, d, 1)
417 except KeyboardInterrupt:
420 excname = str(sys.exc_info()[0])
421 if excname == "bb.build.FuncFailed":
423 o.write('# expansion of %s threw %s\n' % (var, excname))
427 o.write('# %s=%s\n' % (var, oval))
429 if type(val) is not types.StringType:
432 if getVarFlag(var, 'matchesenv', d):
435 if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
442 if getVarFlag(var, "func", d):
443 # NOTE: should probably check for unbalanced {} within the var
444 o.write("%s() {\n%s\n}\n" % (var, val))
446 if getVarFlag(var, "export", d):
451 # if we're going to output this within doublequotes,
452 # to a shell, we need to escape the quotes in the var
453 alter = re.sub('"', '\\"', val.strip())
454 o.write('%s="%s"\n' % (var, alter))
458 def emit_env(o=sys.__stdout__, d = init(), all=False):
459 """Emits all items in the data store in a format such that it can be sourced by a shell."""
464 if getVarFlag(e, "func", d):
466 emit_var(e, o, d, all) and o.write('\n')
469 if not getVarFlag(e, "func", d):
471 emit_var(e, o, d) and o.write('\n')
474 """Modifies the environment vars according to local overrides and commands.
476 Appending to a variable:
478 >>> setVar('TEST', 'this is a', d)
479 >>> setVar('TEST_append', ' test', d)
480 >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
482 >>> print getVar('TEST', d)
483 this is a test of the emergency broadcast system.
485 Prepending to a variable:
486 >>> setVar('TEST', 'virtual/libc', d)
487 >>> setVar('TEST_prepend', 'virtual/tmake ', d)
488 >>> setVar('TEST_prepend', 'virtual/patcher ', d)
490 >>> print getVar('TEST', d)
491 virtual/patcher virtual/tmake virtual/libc
494 >>> setVar('TEST_arm', 'target', d)
495 >>> setVar('TEST_ramses', 'machine', d)
496 >>> setVar('TEST_local', 'local', d)
497 >>> setVar('OVERRIDES', 'arm', d)
499 >>> setVar('TEST', 'original', d)
501 >>> print getVar('TEST', d)
504 >>> setVar('OVERRIDES', 'arm:ramses:local', d)
505 >>> setVar('TEST', 'original', d)
507 >>> print getVar('TEST', d)
511 debug(2, "update_data()")
513 # can't do delete env[...] while iterating over the dictionary, so remember them
515 overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
517 def applyOverrides(var, d):
519 debug(1, "OVERRIDES not defined, nothing to do")
523 if var.endswith("_" + o):
530 sval = getVar(s, d) or ""
532 # Handle line appends:
533 for (a, o) in getVarFlag(s, '_append', d) or []:
534 # maybe the OVERRIDE was not yet added so keep the append
535 if (o and o in overrides) or not o:
536 delVarFlag(s, '_append', d)
538 if not o in overrides:
543 # Handle line prepends
544 for (a, o) in getVarFlag(s, '_prepend', d) or []:
545 # maybe the OVERRIDE was not yet added so keep the append
546 if (o and o in overrides) or not o:
547 delVarFlag(s, '_prepend', d)
549 if not o in overrides:
554 # Handle line deletions
556 nameval = getVar(name, d)
561 pattern = nameval.replace('\n','').strip()
562 for line in sval.split('\n'):
563 if line.find(pattern) == -1:
564 new = new + '\n' + line
568 # delete all environment vars no longer needed
572 def inherits_class(klass, d):
573 val = getVar('__inherit_cache', d) or ""
574 if os.path.join('classes', '%s.bbclass' % klass) in val.split():
579 """Start a doctest run on this module"""
582 doctest.testmod(data)
584 if __name__ == "__main__":