diff options
Diffstat (limited to 'build/lib/bb/data.py')
-rw-r--r-- | build/lib/bb/data.py | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/build/lib/bb/data.py b/build/lib/bb/data.py new file mode 100644 index 000000000..5ec6d9561 --- /dev/null +++ b/build/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() |