bitbake data module abstraction:
authorHolger Hans Peter Freyther <zecke@selfish.org>
Tue, 17 May 2005 18:04:46 +0000 (18:04 +0000)
committerHolger Hans Peter Freyther <zecke@selfish.org>
Tue, 17 May 2005 18:04:46 +0000 (18:04 +0000)
-bb.data is now a delegate to hookable Data implementation.
-bb.data.init() is the 'factory' method to create a instance
of a concrete implementation.
-Kill assumptions that bb.data.init() returns a {} (python dict)
-Add the old Dictionary Based Implementation as data_dict.py

classes/base.bbclass
lib/bb/data.py
lib/bb/data_dict.py [new file with mode: 0644]
lib/bb/parse/BBHandler.py
lib/bb/parse/ConfHandler.py

index f319676..1d75964 100644 (file)
@@ -54,7 +54,7 @@ python do_showdata() {
        # emit variables and shell functions
        bb.data.emit_env(sys.__stdout__, d, True)
        # emit the metadata which isnt valid shell
-       for e in d.keys():
+       for e in bb.data.keys(d):
                if bb.data.getVarFlag(e, 'python', d):
                        sys.__stdout__.write("\npython %s () {\n%s}\n" % (e, bb.data.getVar(e, d, 1)))
 }
@@ -63,7 +63,7 @@ addtask listtasks
 do_listtasks[nostamp] = "1"
 python do_listtasks() {
        import sys
-       for e in d.keys():
+       for e in bb.data.keys(d):
                if bb.data.getVarFlag(e, 'task', d):
                        sys.__stdout__.write("%s\n" % e)
 }
index 8f0f5dd..b7c28b2 100644 (file)
@@ -8,6 +8,7 @@ Functions for interacting with the data structure used by the
 BitBake build tools.
 
 Copyright (C) 2003, 2004  Chris Larson
+Copyright (C) 2005        Holger Hans Peter Freyther
 
 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
@@ -32,27 +33,22 @@ else:
     path = os.path.dirname(os.path.dirname(sys.argv[0]))
 sys.path.append(path)
 
-from bb import note, debug
+from bb import note, debug, data_dict
+
+_dict_type = data_dict.DataDict
+
 
 def init():
-    return {}
+    return _dict_type()
 
-_data = init()
+_data_dict = init()
 
-def initVar(var, d = _data):
+def initVar(var, d = _data_dict):
     """Non-destructive var init for data structure"""
-    if not var in d:
-        d[var] = {}
-
-    if not "flags" in d[var]:
-        d[var]["flags"] = {}
+    d.initVar(var)
 
-__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):
+def setVar(var, value, d = _data_dict):
     """Set a variable to a given value
 
     Example:
@@ -60,27 +56,10 @@ def setVar(var, value, d = _data):
         >>> 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
+    d.setVar(var,value)
 
-    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):
+def getVar(var, d = _data_dict, exp = 0):
     """Gets the value of a variable
 
     Example:
@@ -88,13 +67,9 @@ def getVar(var, d = _data, exp = 0):
         >>> 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"]
+    return d.getVar(var,exp)
 
-def delVar(var, d = _data):
+def delVar(var, d = _data_dict):
     """Removes a variable from the data set
 
     Example:
@@ -105,10 +80,9 @@ def delVar(var, d = _data):
         >>> print getVar('TEST')
         None
     """
-    if var in d:
-        del d[var]
+    d.delVar(var)
 
-def setVarFlag(var, flag, flagvalue, d = _data):
+def setVarFlag(var, flag, flagvalue, d = _data_dict):
     """Set a flag for a given variable to a given value
 
     Example:
@@ -116,12 +90,9 @@ def setVarFlag(var, flag, flagvalue, d = _data):
         >>> 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
+    d.setVarFlag(var,flag,flagvalue)
 
-def getVarFlag(var, flag, d = _data):
+def getVarFlag(var, flag, d = _data_dict):
     """Gets given flag from given var
 
     Example:
@@ -129,11 +100,9 @@ def getVarFlag(var, flag, d = _data):
         >>> 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
+    return d.getVarFlag(var,flag)
 
-def delVarFlag(var, flag, d = _data):
+def delVarFlag(var, flag, d = _data_dict):
     """Removes a given flag from the variable's flags
 
     Example:
@@ -145,10 +114,9 @@ def delVarFlag(var, flag, d = _data):
         None
 
     """
-    if var in d and "flags" in d[var] and flag in d[var]["flags"]:
-        del d[var]["flags"][flag]
+    d.delVarFlag(var,flag)
 
-def setVarFlags(var, flags, d = _data):
+def setVarFlags(var, flags, d = _data_dict):
     """Set the flags for a given variable
 
     Example:
@@ -158,11 +126,9 @@ def setVarFlags(var, flags, d = _data):
         >>> print getVarFlag('TEST', 'test')
         blah
     """
-    if not var in d:
-        initVar(var, d)
-    d[var]["flags"] = flags
+    d.setVarFlags(var,flags)
 
-def getVarFlags(var, d = _data):
+def getVarFlags(var, d = _data_dict):
     """Gets a variable's flags
 
     Example:
@@ -170,11 +136,9 @@ def getVarFlags(var, d = _data):
         >>> print getVarFlags('TEST')['test']
         blah
     """
-    if var in d and "flags" in d[var]:
-        return d[var]["flags"]
-    return None
+    return d.getVarFlags(var)
 
-def delVarFlags(var, d = _data):
+def delVarFlags(var, d = _data_dict):
     """Removes a variable's flags
 
     Example:
@@ -186,21 +150,33 @@ def delVarFlags(var, d = _data):
         None
 
     """
-    if var in d and "flags" in d[var]:
-        del d[var]["flags"]
+    d.delVarFlags(var)
+
+def keys(d = _data_dict):
+    """Return a list of keys in d
+
+    Example:
+        >>> d = init()
+        >>> setVar('TEST',  1, d)
+        >>> setVar('MOO' ,  2, d)
+        >>> setVarFlag('TEST', 'test', 1, d)
+        >>> keys(d)
+        ['TEST', 'MOO']
+    """
+    return d.keys()
 
-def getData(d = _data):
+def getData(d = _data_dict):
     """Returns the data object used"""
     return d
 
-def setData(newData, d = _data):
+def setData(newData, d = _data_dict):
     """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):
+def expand(s, d = _data_dict, varname = None):
     """Variable expansion using the data store.
 
     Example:
@@ -251,11 +227,11 @@ def expand(s, d = _data, varname = None):
             raise
     return s
 
-def expandKeys(alterdata = _data, readdata = None):
+def expandKeys(alterdata = _data_dict, readdata = None):
     if readdata == None:
         readdata = alterdata
 
-    for key in alterdata.keys():
+    for key in keys(alterdata):
         ekey = expand(key, readdata)
         if key == ekey:
             continue
@@ -274,7 +250,7 @@ def expandKeys(alterdata = _data, readdata = None):
 
         delVar(key, alterdata)
 
-def expandData(alterdata = _data, readdata = None):
+def expandData(alterdata = _data_dict, readdata = None):
     """For each variable in alterdata, expand it, and update the var contents.
        Replacements use data from readdata.
 
@@ -290,7 +266,7 @@ def expandData(alterdata = _data, readdata = None):
     if readdata == None:
         readdata = alterdata
 
-    for key in alterdata.keys():
+    for key in keys(alterdata):
         val = getVar(key, alterdata)
         if type(val) is not types.StringType:
             continue
@@ -301,7 +277,7 @@ def expandData(alterdata = _data, readdata = None):
 
 import os
 
-def inheritFromOS(d = _data):
+def inheritFromOS(d = _data_dict):
     """Inherit variables from the environment."""
 #   fakeroot needs to be able to set these
     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
@@ -315,7 +291,7 @@ def inheritFromOS(d = _data):
 
 import sys
 
-def emit_var(var, o=sys.__stdout__, d = _data, all=False):
+def emit_var(var, o=sys.__stdout__, d = _data_dict, all=False):
     """Emit a variable to be sourced by a shell."""
     if getVarFlag(var, "python", d):
         return 0
@@ -365,10 +341,10 @@ def emit_var(var, o=sys.__stdout__, d = _data, all=False):
     return 1
 
 
-def emit_env(o=sys.__stdout__, d = _data, all=False):
+def emit_env(o=sys.__stdout__, d = _data_dict, all=False):
     """Emits all items in the data store in a format such that it can be sourced by a shell."""
 
-    env = d.keys()
+    env = keys(d)
 
     for e in env:
         if getVarFlag(e, "func", d):
@@ -380,7 +356,7 @@ def emit_env(o=sys.__stdout__, d = _data, all=False):
             continue
         emit_var(e, o, d) and o.write('\n')
 
-def update_data(d = _data):
+def update_data(d = _data_dict):
     """Modifies the environment vars according to local overrides and commands.
     Examples:
         Appending to a variable:
@@ -423,7 +399,7 @@ def update_data(d = _data):
     dodel = []
     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
 
-    def applyOverrides(var, d = _data):
+    def applyOverrides(var, d = _data_dict):
         if not overrides:
             debug(1, "OVERRIDES not defined, nothing to do")
             return
@@ -434,7 +410,7 @@ def update_data(d = _data):
                 name = var[:-l]
                 d[name] = d[var]
 
-    for s in d.keys():
+    for s in keys(d):
         applyOverrides(s, d)
         sval = getVar(s, d) or ""
 
diff --git a/lib/bb/data_dict.py b/lib/bb/data_dict.py
new file mode 100644 (file)
index 0000000..8c6f3d8
--- /dev/null
@@ -0,0 +1,173 @@
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+"""
+BitBake 'Data-Dict' implementation
+
+Functions for interacting with the data structure used by the
+BitBake build tools.
+
+Copyright (C) 2003, 2004  Chris Larson
+Copyright (C) 2005        Holger Hans Peter Freyther
+
+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 os, re, sys, types
+from   bb import note, debug, fatal
+
+__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")
+
+__expand_var_regexp__ = re.compile(r"\${[^{}]+}")
+__expand_python_regexp__ = re.compile(r"\${@.+?}")
+
+
+class DataDict:
+    def __init__(self):
+        self.dict = {}
+
+    def expand(self,s, varname):
+        def var_sub(match):
+            key = match.group()[2:-1]
+            if varname and key:
+                if varname == key:
+                    raise Exception("variable %s references itself!" % varname)
+            var = self.getVar(key, 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'] = self
+            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 KeyboardInterrupt:
+                raise
+            except:
+                note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
+                raise
+        return s
+
+    def initVar(self, var):
+        if not var in self.dict:
+            self.dict[var] = {}
+
+        if not "flags" in self.dict[var]:
+            self.dict[var]["flags"] = {}
+
+    def setVar(self,var,value):
+        for v in ["_append", "_prepend", "_delete"]:
+            match = __setvar_regexp__[v].match(var)
+
+            if match:
+                base = match.group('base')
+                override = match.group('add')
+                l = self.getVarFlag(base, v) or []
+                if override == 'delete':
+                    if l.count([value, None]):
+                        del l[l.index([value, None])]
+                l.append([value, override])
+                self.setVarFlag(base, v, l)
+                return
+
+        self.initVar(var)
+        if self.getVarFlag(var, 'matchesenv'):
+            self.delVarFlag(var, 'matchesenv')
+            self.setVarFlag(var, 'export', 1)
+        self.dict[var]["content"] = value
+
+    def getVar(self,var,exp):
+        if not var in self.dict or not "content" in self.dict[var]:
+            return None
+
+        if exp:
+            return self.expand(self.dict[var]["content"], var)
+        return self.dict[var]["content"]
+
+    def delVar(self,var):
+        if var in self.dict:
+            del self.dict[var]
+
+    def setVarFlag(self,var,flag,flagvalue):
+        self.initVar(var)
+        self.dict[var]["flags"][flag] = flagvalue
+
+    def getVarFlag(self,var,flag):
+        if var in self.dict and "flags" in self.dict[var] and flag in self.dict[var]["flags"]:
+            di = self.dict[var]
+            di = di["flags"]
+            return di[flag]
+        return None
+
+    def delVarFlag(self,var,flag):
+        if var in self.dict and "flags" in self.dict[var] and flag in self.dict[var]["flags"]:
+            del self.dict[var]["flags"][flag]
+
+    def setVarFlags(self,var,flags):
+        self.initVar(var)
+        if flags == None:
+            debug("Setting Null Flag %s" % var)
+
+        self.dict[var]["flags"] = flags
+
+    def getVarFlags(self,var):
+        if var in self.dict and "flags" in self.dict[var]:
+            return self.dict[var]["flags"]
+
+        return None
+
+    def delVarFlags(self,var):
+        if var in self.dict and "flags" in self.dict[var]:
+            del self.dict[var]["flags"]
+
+    # Dictionary Methods
+    def keys(self):
+        return self.dict.keys()
+
+    def iterkeys(self):
+        return self.dict.iterkeys()
+
+    def iteritems(self):
+        return self.dict.iteritems()
+
+    def items(self):
+        return self.dict.items()
+
+    def __getitem__(self,y):
+        return self.dict.__getitem__(y)
+
+    def __setitem__(self,x,y):
+        self.dict.__setitem__(x,y)
+
index 70d84cb..7ff3909 100644 (file)
@@ -64,7 +64,7 @@ def inherit(files, d):
     data.setVar('__inherit_cache', __inherit_cache, d)
 
 
-def handle(fn, d = {}, include = 0):
+def handle(fn, d = data.init(), include = 0):
     global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
     __body__ = []
     __bbpath_found__ = 0
@@ -156,7 +156,7 @@ def handle(fn, d = {}, include = 0):
             set_additional_vars(fn, d, include)
             data.update_data(d)
 
-            for var in d.keys():
+            for var in data.keys(d):
                 if data.getVarFlag(var, 'handler', d):
                     bb.event.register(data.getVar(var, d))
                     continue
index 43cdec6..c001044 100644 (file)
@@ -51,7 +51,7 @@ def localpath(fn, d):
         localfn = fn
     return localfn
 
-def obtain(fn, data = {}):
+def obtain(fn, data = bb.data.init()):
     import sys, bb
     fn = bb.data.expand(fn, data)
     localfn = bb.data.expand(localpath(fn, data), data)
@@ -82,7 +82,7 @@ def obtain(fn, data = {}):
     return localfn
 
 
-def include(oldfn, fn, data = {}):
+def include(oldfn, fn, data = bb.data.init()):
     if oldfn == fn: # prevent infinate recursion
         return None
 
@@ -96,7 +96,7 @@ def include(oldfn, fn, data = {}):
     except IOError:
         debug(2, "CONF file '%s' not found" % fn)
 
-def handle(fn, data = {}, include = 0):
+def handle(fn, data = bb.data.init(), include = 0):
     if include:
         inc_string = "including"
     else:
@@ -153,7 +153,7 @@ def handle(fn, data = {}, include = 0):
         bb.data.setVar('FILE', oldfile, data)
     return data
 
-def feeder(lineno, s, fn, data = {}):
+def feeder(lineno, s, fn, data = bb.data.init()):
     m = __config_regexp__.match(s)
     if m:
         groupd = m.groupdict()