summaryrefslogtreecommitdiffstats
path: root/lib/bb/data.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bb/data.py')
-rw-r--r--lib/bb/data.py490
1 files changed, 490 insertions, 0 deletions
diff --git a/lib/bb/data.py b/lib/bb/data.py
new file mode 100644
index 000000000..5ec6d9561
--- /dev/null
+++ b/lib/bb/data.py
@@ -0,0 +1,490 @@
+#!/usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake 'Data' implementations
+
+Functions for interacting with the data structure used by the
+BitBake build tools.
+
+Copyright (C) 2003, 2004 Chris Larson
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA.
+
+Based on functions from the base bb module, Copyright 2003 Holger Schurig
+"""
+
+import sys, os, re, time, types
+if sys.argv[0][-5:] == "pydoc":
+ path = os.path.dirname(os.path.dirname(sys.argv[1]))
+else:
+ path = os.path.dirname(os.path.dirname(sys.argv[0]))
+sys.path.append(path)
+
+from bb import note, debug
+
+def init():
+ return {}
+
+_data = init()
+
+def initVar(var, d = _data):
+ """Non-destructive var init for data structure"""
+ if not var in d:
+ d[var] = {}
+
+ if not "flags" in d[var]:
+ d[var]["flags"] = {}
+
+__setvar_regexp__ = {}
+__setvar_regexp__["_append"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_append")
+__setvar_regexp__["_prepend"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_prepend")
+__setvar_regexp__["_delete"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_delete")
+
+def setVar(var, value, d = _data):
+ """Set a variable to a given value
+
+ Example:
+ >>> setVar('TEST', 'testcontents')
+ >>> print getVar('TEST')
+ testcontents
+ """
+ for v in ["_append", "_prepend", "_delete"]:
+ match = __setvar_regexp__[v].match(var)
+ if match:
+ base = match.group('base')
+ override = match.group('add')
+ l = getVarFlag(base, v, d) or []
+ if override == 'delete':
+ if l.count([value, None]):
+ del l[l.index([value, None])]
+ l.append([value, override])
+ setVarFlag(base, v, l, d)
+ return
+
+ if not var in d:
+ initVar(var, d)
+ if getVarFlag(var, 'matchesenv', d):
+ delVarFlag(var, 'matchesenv', d)
+ setVarFlag(var, 'export', 1, d)
+ d[var]["content"] = value
+
+def getVar(var, d = _data, exp = 0):
+ """Gets the value of a variable
+
+ Example:
+ >>> setVar('TEST', 'testcontents')
+ >>> print getVar('TEST')
+ testcontents
+ """
+ if not var in d or not "content" in d[var]:
+ return None
+ if exp:
+ return expand(d[var]["content"], d, var)
+ return d[var]["content"]
+
+def delVar(var, d = _data):
+ """Removes a variable from the data set
+
+ Example:
+ >>> setVar('TEST', 'testcontents')
+ >>> print getVar('TEST')
+ testcontents
+ >>> delVar('TEST')
+ >>> print getVar('TEST')
+ None
+ """
+ if var in d:
+ del d[var]
+
+def setVarFlag(var, flag, flagvalue, d = _data):
+ """Set a flag for a given variable to a given value
+
+ Example:
+ >>> setVarFlag('TEST', 'python', 1)
+ >>> print getVarFlag('TEST', 'python')
+ 1
+ """
+# print "d[%s][\"flags\"][%s] = %s" % (var, flag, flagvalue)
+ if not var in d:
+ initVar(var, d)
+ d[var]["flags"][flag] = flagvalue
+
+def getVarFlag(var, flag, d = _data):
+ """Gets given flag from given var
+
+ Example:
+ >>> setVarFlag('TEST', 'python', 1)
+ >>> print getVarFlag('TEST', 'python')
+ 1
+ """
+ if var in d and "flags" in d[var] and flag in d[var]["flags"]:
+ return d[var]["flags"][flag]
+ return None
+
+def delVarFlag(var, flag, d = _data):
+ """Removes a given flag from the variable's flags
+
+ Example:
+ >>> setVarFlag('TEST', 'testflag', 1)
+ >>> print getVarFlag('TEST', 'testflag')
+ 1
+ >>> delVarFlag('TEST', 'testflag')
+ >>> print getVarFlag('TEST', 'testflag')
+ None
+
+ """
+ if var in d and "flags" in d[var] and flag in d[var]["flags"]:
+ del d[var]["flags"][flag]
+
+def setVarFlags(var, flags, d = _data):
+ """Set the flags for a given variable
+
+ Example:
+ >>> myflags = {}
+ >>> myflags['test'] = 'blah'
+ >>> setVarFlags('TEST', myflags)
+ >>> print getVarFlag('TEST', 'test')
+ blah
+ """
+ if not var in d:
+ initVar(var, d)
+ d[var]["flags"] = flags
+
+def getVarFlags(var, d = _data):
+ """Gets a variable's flags
+
+ Example:
+ >>> setVarFlag('TEST', 'test', 'blah')
+ >>> print getVarFlags('TEST')['test']
+ blah
+ """
+ if var in d and "flags" in d[var]:
+ return d[var]["flags"]
+ return None
+
+def delVarFlags(var, d = _data):
+ """Removes a variable's flags
+
+ Example:
+ >>> setVarFlag('TEST', 'testflag', 1)
+ >>> print getVarFlag('TEST', 'testflag')
+ 1
+ >>> delVarFlags('TEST')
+ >>> print getVarFlags('TEST')
+ None
+
+ """
+ if var in d and "flags" in d[var]:
+ del d[var]["flags"]
+
+def getData(d = _data):
+ """Returns the data object used"""
+ return d
+
+def setData(newData, d = _data):
+ """Sets the data object to the supplied value"""
+ d = newData
+
+__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
+__expand_python_regexp__ = re.compile(r"\${@.+?}")
+
+def expand(s, d = _data, varname = None):
+ """Variable expansion using the data store.
+
+ Example:
+ Standard expansion:
+ >>> setVar('A', 'sshd')
+ >>> print expand('/usr/bin/${A}')
+ /usr/bin/sshd
+
+ Python expansion:
+ >>> print expand('result: ${@37 * 72}')
+ result: 2664
+ """
+ def var_sub(match):
+ key = match.group()[2:-1]
+ if varname and key:
+ if varname == key:
+ raise Exception("variable %s references itself!" % varname)
+ var = getVar(key, d, 1)
+ if var is not None:
+ return var
+ else:
+ return match.group()
+
+ def python_sub(match):
+ import bb
+ code = match.group()[3:-1]
+ locals()['d'] = d
+ s = eval(code)
+ if type(s) == types.IntType: s = str(s)
+ return s
+
+ if type(s) is not types.StringType: # sanity check
+ return s
+
+ while s.find('$') != -1:
+ olds = s
+ try:
+ s = __expand_var_regexp__.sub(var_sub, s)
+ s = __expand_python_regexp__.sub(python_sub, s)
+ if s == olds: break
+ if type(s) is not types.StringType: # sanity check
+ import bb
+ bb.error('expansion of %s returned non-string %s' % (olds, s))
+ except:
+ import bb
+ bb.note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
+ raise
+ return s
+
+def expandKeys(alterdata = _data, readdata = None):
+ if readdata == None:
+ readdata = alterdata
+
+ for key in alterdata.keys():
+ ekey = expand(key, readdata)
+ if key == ekey:
+ continue
+ val = getVar(key, alterdata)
+ if val is None:
+ continue
+# import copy
+# setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
+ setVar(ekey, val, alterdata)
+
+ for i in ('_append', '_prepend', '_delete'):
+ dest = getVarFlag(ekey, i, alterdata) or []
+ src = getVarFlag(key, i, readdata) or []
+ dest.extend(src)
+ setVarFlag(ekey, i, dest, alterdata)
+
+ delVar(key, alterdata)
+
+def expandData(alterdata = _data, readdata = None):
+ """For each variable in alterdata, expand it, and update the var contents.
+ Replacements use data from readdata.
+
+ Example:
+ >>> a=init()
+ >>> b=init()
+ >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
+ >>> setVar("DL_DIR", "/path/to/whatever", b)
+ >>> expandData(a, b)
+ >>> print getVar("dlmsg", a)
+ dl_dir is /path/to/whatever
+ """
+ if readdata == None:
+ readdata = alterdata
+
+ for key in alterdata.keys():
+ val = getVar(key, alterdata)
+ if type(val) is not types.StringType:
+ continue
+ expanded = expand(val, readdata)
+# print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
+ if val != expanded:
+ setVar(key, expanded, alterdata)
+
+import os
+
+def inheritFromOS(d = _data):
+ """Inherit variables from the environment."""
+# fakeroot needs to be able to set these
+ non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
+ for s in os.environ.keys():
+ if not s in non_inherit_vars:
+ try:
+ setVar(s, os.environ[s], d)
+ setVarFlag(s, 'matchesenv', '1', d)
+ except TypeError:
+ pass
+
+import sys
+
+def emit_var(var, o=sys.__stdout__, d = _data, all=False):
+ """Emit a variable to be sourced by a shell."""
+ if getVarFlag(var, "python", d):
+ return 0
+
+ try:
+ if all:
+ oval = getVar(var, d, 0)
+ val = getVar(var, d, 1)
+ except KeyboardInterrupt:
+ raise
+ except:
+ o.write('# expansion of %s threw %s\n' % (var, sys.exc_info()[0]))
+ return 0
+
+ if all:
+ o.write('# %s=%s\n' % (var, oval))
+
+ if type(val) is not types.StringType:
+ return 0
+
+ if getVarFlag(var, 'matchesenv', d):
+ return 0
+
+ if var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1:
+ return 0
+
+ val.rstrip()
+ if not val:
+ return 0
+
+ if getVarFlag(var, "func", d):
+# NOTE: should probably check for unbalanced {} within the var
+ o.write("%s() {\n%s\n}\n" % (var, val))
+ else:
+ if getVarFlag(var, "export", d):
+ o.write('export ')
+ else:
+ if not all:
+ return 0
+# if we're going to output this within doublequotes,
+# to a shell, we need to escape the quotes in the var
+ alter = re.sub('"', '\\"', val.strip())
+ o.write('%s="%s"\n' % (var, alter))
+ return 1
+
+
+def emit_env(o=sys.__stdout__, d = _data, all=False):
+ """Emits all items in the data store in a format such that it can be sourced by a shell."""
+
+ env = d.keys()
+
+ for e in env:
+ if getVarFlag(e, "func", d):
+ continue
+ emit_var(e, o, d, all) and o.write('\n')
+
+ for e in env:
+ if not getVarFlag(e, "func", d):
+ continue
+ emit_var(e, o, d) and o.write('\n')
+
+def update_data(d = _data):
+ """Modifies the environment vars according to local overrides and commands.
+ Examples:
+ Appending to a variable:
+ >>> setVar('TEST', 'this is a')
+ >>> setVar('TEST_append', ' test')
+ >>> setVar('TEST_append', ' of the emergency broadcast system.')
+ >>> update_data()
+ >>> print getVar('TEST')
+ this is a test of the emergency broadcast system.
+
+ Prepending to a variable:
+ >>> setVar('TEST', 'virtual/libc')
+ >>> setVar('TEST_prepend', 'virtual/tmake ')
+ >>> setVar('TEST_prepend', 'virtual/patcher ')
+ >>> update_data()
+ >>> print getVar('TEST')
+ virtual/patcher virtual/tmake virtual/libc
+
+ Overrides:
+ >>> setVar('TEST_arm', 'target')
+ >>> setVar('TEST_ramses', 'machine')
+ >>> setVar('TEST_local', 'local')
+ >>> setVar('OVERRIDES', 'arm')
+
+ >>> setVar('TEST', 'original')
+ >>> update_data()
+ >>> print getVar('TEST')
+ target
+
+ >>> setVar('OVERRIDES', 'arm:ramses:local')
+ >>> setVar('TEST', 'original')
+ >>> update_data()
+ >>> print getVar('TEST')
+ local
+ """
+
+ debug(2, "update_data()")
+
+# can't do delete env[...] while iterating over the dictionary, so remember them
+ dodel = []
+ overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
+
+ def applyOverrides(var, d = _data):
+ if not overrides:
+ debug(1, "OVERRIDES not defined, nothing to do")
+ return
+ val = getVar(var, d)
+ for o in overrides:
+ if var.endswith("_" + o):
+ l = len(o)+1
+ name = var[:-l]
+ d[name] = d[var]
+
+ for s in d.keys():
+ applyOverrides(s, d)
+ sval = getVar(s, d) or ""
+
+# Handle line appends:
+ for (a, o) in getVarFlag(s, '_append', d) or []:
+ # maybe the OVERRIDE was not yet added so keep the append
+ if (o and o in overrides) or not o:
+ delVarFlag(s, '_append', d)
+ if o:
+ if not o in overrides:
+ continue
+ sval+=a
+ setVar(s, sval, d)
+
+# Handle line prepends
+ for (a, o) in getVarFlag(s, '_prepend', d) or []:
+ # maybe the OVERRIDE was not yet added so keep the append
+ if (o and o in overrides) or not o:
+ delVarFlag(s, '_prepend', d)
+ if o:
+ if not o in overrides:
+ continue
+ sval=a+sval
+ setVar(s, sval, d)
+
+# Handle line deletions
+ name = s + "_delete"
+ nameval = getVar(name, d)
+ if nameval:
+ sval = getVar(s, d)
+ if sval:
+ new = ''
+ pattern = nameval.replace('\n','').strip()
+ for line in sval.split('\n'):
+ if line.find(pattern) == -1:
+ new = new + '\n' + line
+ setVar(s, new, d)
+ dodel.append(name)
+
+# delete all environment vars no longer needed
+ for s in dodel:
+ delVar(s, d)
+
+def inherits_class(klass, d):
+ val = getVar('__inherit_cache', d) or ""
+ if os.path.join('classes', '%s.bbclass' % klass) in val.split():
+ return True
+ return False
+
+def _test():
+ """Start a doctest run on this module"""
+ import doctest
+ from bb import data
+ doctest.testmod(data)
+
+if __name__ == "__main__":
+ _test()