data_smart: Micro optimisation - search for "${" instead of "$"
[vuplus_bitbake] / lib / bb / data_smart.py
index e1ced4e..d63fdde 100644 (file)
@@ -8,7 +8,7 @@ BitBake build tools.
 
 Copyright (C) 2003, 2004  Chris Larson
 Copyright (C) 2004, 2005  Seb Frankengul
-Copyright (C) 2005        Holger Hans Peter Freyther
+Copyright (C) 2005, 2006  Holger Hans Peter Freyther
 Copyright (C) 2005        Uli Luckas
 Copyright (C) 2005        ROAD GmbH
 
@@ -29,25 +29,29 @@ Based on functions from the base bb module, Copyright 2003 Holger Schurig
 """
 
 import copy, os, re, sys, time, types
-from   bb import note, debug, fatal
+import bb
+from bb   import utils, methodpool
+from COW  import COWDictBase
+from sets import Set
+from new  import classobj
 
-try:
-    import cPickle as pickle
-except ImportError:
-    import pickle
-    print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
 
-
-__setvar_keyword__ = ["_append","_prepend","_delete"]
-__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend|_delete)(_(?P<add>.*))?')
+__setvar_keyword__ = ["_append","_prepend"]
+__setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
 __expand_python_regexp__ = re.compile(r"\${@.+?}")
 
 
 class DataSmart:
-    def __init__(self):
+    def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ):
         self.dict = {}
 
+        # cookie monster tribute
+        self._special_values = special
+        self._seen_overrides = seen
+
+        self.expand_cache = {}
+
     def expand(self,s, varname):
         def var_sub(match):
             key = match.group()[2:-1]
@@ -71,38 +75,33 @@ class DataSmart:
         if type(s) is not types.StringType: # sanity check
             return s
 
-        while s.find('$') != -1:
+        if varname and varname in self.expand_cache:
+            return self.expand_cache[varname]
+
+        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))
+                    bb.msg.error(bb.msg.domain.Data, '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))
+                bb.msg.note(1, bb.msg.domain.Data, "%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
                 raise
+
+        if varname:
+            self.expand_cache[varname] = s
+
         return s
 
     def initVar(self, var):
+        self.expand_cache = {}
         if not var in self.dict:
             self.dict[var] = {}
 
-    def pickle_prep(self, cfg):
-        if "_data" in self.dict:
-            if self.dict["_data"] == cfg:
-                self.dict["_data"] = "cfg";
-            else: # this is an unknown array for the moment
-                pass
-
-    def unpickle_prep(self, cfg):
-        if "_data" in self.dict:
-            if self.dict["_data"] == "cfg":
-                self.dict["_data"] = cfg;
-
     def _findVar(self,var):
         _dest = self.dict
 
@@ -116,14 +115,6 @@ class DataSmart:
             return _dest[var]
         return None
 
-    def _copyVar(self,var,name):
-        local_var = self._findVar(var)
-        if local_var:
-            self.dict[name] = copy.copy(local_var)
-        else:
-            debug(1,"Warning, _copyVar %s to %s, %s does not exists" % (var,name,var))
-
-
     def _makeShadowCopy(self, var):
         if var in self.dict:
             return
@@ -136,17 +127,24 @@ class DataSmart:
             self.initVar(var)
 
     def setVar(self,var,value):
+        self.expand_cache = {}
         match  = __setvar_regexp__.match(var)
         if match and match.group("keyword") in __setvar_keyword__:
             base = match.group('base')
             keyword = match.group("keyword")
             override = match.group('add')
             l = self.getVarFlag(base, keyword) or []
-            if override == 'delete':
-                if l.count([value, None]):
-                    del l[l.index([value, None])]
             l.append([value, override])
-            self.setVarFlag(base, match.group("keyword"), l)
+            self.setVarFlag(base, keyword, l)
+
+            # todo make sure keyword is not __doc__ or __module__
+            # pay the cookie monster
+            try:
+                self._special_values[keyword].add( base )
+            except:
+                self._special_values[keyword] = Set()
+                self._special_values[keyword].add( base )
+
             return
 
         if not var in self.dict:
@@ -155,6 +153,13 @@ class DataSmart:
             self.delVarFlag(var, 'matchesenv')
             self.setVarFlag(var, 'export', 1)
 
+        # more cookies for the cookie monster
+        if '_' in var:
+            override = var[var.rfind('_')+1:]
+            if not self._seen_overrides.has_key(override):
+                self._seen_overrides[override] = Set()
+            self._seen_overrides[override].add( var )
+
         # setting var
         self.dict[var]["content"] = value
 
@@ -166,6 +171,7 @@ class DataSmart:
         return value
 
     def delVar(self,var):
+        self.expand_cache = {}
         self.dict[var] = {}
 
     def setVarFlag(self,var,flag,flagvalue):
@@ -235,7 +241,7 @@ class DataSmart:
         Create a copy of self by setting _data to self
         """
         # we really want this to be a DataSmart...
-        data = DataSmart()
+        data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy())
         data.dict["_data"] = self.dict
 
         return data
@@ -254,75 +260,11 @@ class DataSmart:
         return keytab.keys()
 
     def __getitem__(self,item):
-        start = self.dict
-        while start:
-            if item in start:
-                return start[item]
-            elif "_data" in start:
-                start = start["_data"]
-            else:
-                start = None
-        return None
+        #print "Warning deprecated"
+        return self.getVar(item, False)
 
     def __setitem__(self,var,data):
-        self._makeShadowCopy(var)
-        self.dict[var] = data
-
-
-class DataSmartPackage(DataSmart):
-    """
-    Persistent Data Storage
-    """
-    def sanitize_filename(bbfile):
-        return bbfile.replace( '/', '_' )
-    sanitize_filename = staticmethod(sanitize_filename)
-
-    def unpickle(self):
-        """
-        Restore the dict from memory
-        """
-        cache_bbfile = self.sanitize_filename(self.bbfile)
-        p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
-        self.dict = p.load()
-        funcstr = self.getVar('__functions__', 0)
-        if funcstr:
-            comp = compile(funcstr, "<pickled>", "exec")
-            exec comp in  __builtins__
-
-    def linkDataSet(self,parent):
-        if not parent == None:
-            # assume parent is a DataSmartInstance
-            self.dict = copy.deepcopy(parent.dict)
+        #print "Warning deprecated"
+        self.setVar(var,data)
 
 
-    def __init__(self,cache,name,clean,parent):
-        """
-        Construct a persistent data instance
-        """
-        #Initialize the dictionary
-        DataSmart.__init__(self)
-
-        self.cache  = cache
-        self.bbfile = os.path.abspath( name )
-
-        # Either unpickle the data or do copy on write
-        if clean:
-            self.linkDataSet(parent)
-        else:
-            self.unpickle()
-
-    def commit(self, mtime):
-        """
-        Save the package to a permanent storage
-        """
-        cache_bbfile = self.sanitize_filename(self.bbfile)
-        p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
-        p.dump( self.dict )
-
-    def mtime(cache,bbfile):
-        cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
-        try:
-            return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
-        except OSError:
-            return 0
-    mtime = staticmethod(mtime)