data_smart: Micro optimisation - search for "${" instead of "$"
[vuplus_bitbake] / lib / bb / data_smart.py
index a0258e5..d63fdde 100644 (file)
@@ -29,14 +29,12 @@ Based on functions from the base bb module, Copyright 2003 Holger Schurig
 """
 
 import copy, os, re, sys, time, types
-from bb   import note, debug, error, fatal, utils, methodpool
+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"]
 __setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
@@ -45,12 +43,14 @@ __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 = {}
-        self._seen_overrides = {}
+        self._special_values = special
+        self._seen_overrides = seen
+
+        self.expand_cache = {}
 
     def expand(self,s, varname):
         def var_sub(match):
@@ -75,22 +75,30 @@ 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
-                    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] = {}
 
@@ -119,6 +127,7 @@ 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')
@@ -128,6 +137,7 @@ class DataSmart:
             l.append([value, override])
             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 )
@@ -135,10 +145,6 @@ class DataSmart:
                 self._special_values[keyword] = Set()
                 self._special_values[keyword].add( base )
 
-            # SRC_URI_append_simpad is both a flag and a override
-            #if not override in self._seen_overrides:
-            #    self._seen_overrides[override] = Set()
-            #self._seen_overrides[override].add( base )
             return
 
         if not var in self.dict:
@@ -150,7 +156,7 @@ class DataSmart:
         # more cookies for the cookie monster
         if '_' in var:
             override = var[var.rfind('_')+1:]
-            if not override in self._seen_overrides:
+            if not self._seen_overrides.has_key(override):
                 self._seen_overrides[override] = Set()
             self._seen_overrides[override].add( var )
 
@@ -165,8 +171,7 @@ class DataSmart:
         return value
 
     def delVar(self,var):
-        if not var in self.dict:
-            self._makeShadowCopy(var)
+        self.expand_cache = {}
         self.dict[var] = {}
 
     def setVarFlag(self,var,flag,flagvalue):
@@ -236,10 +241,8 @@ 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
-        data._seen_overrides = copy.copy(self._seen_overrides)
-        data._special_values = copy.copy(self._special_values)
 
         return data
 
@@ -257,107 +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, self._seen_overrides, self._special_values) = p.load()
-        self.unpickle_prep()
-
-        # compile the functions into global scope
-        funcs = self.getVar('__functions__', 0) or {}
-        for key in funcs.keys():
-            methodpool.check_insert_method( key, funcs[key], self.bbfile )
-            methodpool.parsed_module( key )
-
-        # now add the handlers which were present
-        handlers = self.getVar('__all_handlers__', 0) or {}
-        import bb.event
-        for key in handlers.keys():
-            bb.event.register(key, handlers[key])
-
+        #print "Warning deprecated"
+        self.setVar(var,data)
 
-    def linkDataSet(self):
-        if not self.parent == None:
-            # assume parent is a DataSmartInstance
-            self.dict["_data"] = self.parent.dict
 
-
-    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 )
-        self.parent = parent
-
-        # Either unpickle the data or do copy on write
-        if clean:
-            self.linkDataSet()
-            self._seen_overrides = copy.copy(parent._seen_overrides)
-            self._special_values = copy.copy(parent._special_values)
-        else:
-            self.unpickle()
-
-    def commit(self, mtime):
-        """
-        Save the package to a permanent storage
-        """
-        self.pickle_prep()
-
-        cache_bbfile = self.sanitize_filename(self.bbfile)
-        p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
-        p.dump( (self.dict,self._seen_overrides,self._special_values) )
-
-        self.unpickle_prep()
-
-    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)
-
-    def pickle_prep(self):
-        """
-        If self.dict contains a _data key and it is a configuration
-        we will remember we had a configuration instance attached
-        """
-        if "_data" in self.dict and  self.dict["_data"] == self.parent:
-            dest["_data"] = "cfg"
-
-    def unpickle_prep(self):
-        """
-        If we had a configuration instance attached, we will reattach it
-        """
-        if "_data" in self.dict and  self.dict["_data"] == "cfg":
-            self.dict["_data"] = self.parent