1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 BitBake Smart Dictionary Implementation
6 Functions for interacting with the data structure used by the
9 Copyright (C) 2003, 2004 Chris Larson
10 Copyright (C) 2004, 2005 Seb Frankengul
11 Copyright (C) 2005, 2006 Holger Hans Peter Freyther
12 Copyright (C) 2005 Uli Luckas
13 Copyright (C) 2005 ROAD GmbH
15 This program is free software; you can redistribute it and/or modify it under
16 the terms of the GNU General Public License as published by the Free Software
17 Foundation; either version 2 of the License, or (at your option) any later
20 This program is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License along with
25 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
26 Place, Suite 330, Boston, MA 02111-1307 USA.
28 Based on functions from the base bb module, Copyright 2003 Holger Schurig
31 import copy, os, re, sys, time, types
32 from bb import note, debug, error, fatal, utils, methodpool
36 import cPickle as pickle
39 print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
41 __setvar_keyword__ = ["_append","_prepend"]
42 __setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
43 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
44 __expand_python_regexp__ = re.compile(r"\${@.+?}")
51 # cookie monster tribute
52 self._special_values = {}
53 self._seen_overrides = {}
55 def expand(self,s, varname):
57 key = match.group()[2:-1]
60 raise Exception("variable %s references itself!" % varname)
61 var = self.getVar(key, 1)
67 def python_sub(match):
69 code = match.group()[3:-1]
72 if type(s) == types.IntType: s = str(s)
75 if type(s) is not types.StringType: # sanity check
78 while s.find('$') != -1:
81 s = __expand_var_regexp__.sub(var_sub, s)
82 s = __expand_python_regexp__.sub(python_sub, s)
84 if type(s) is not types.StringType: # sanity check
85 error('expansion of %s returned non-string %s' % (olds, s))
86 except KeyboardInterrupt:
89 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
93 def initVar(self, var):
94 if not var in self.dict:
97 def _findVar(self,var):
100 while (_dest and var not in _dest):
101 if not "_data" in _dest:
104 _dest = _dest["_data"]
106 if _dest and var in _dest:
110 def _makeShadowCopy(self, var):
114 local_var = self._findVar(var)
117 self.dict[var] = copy.copy(local_var)
121 def setVar(self,var,value):
122 match = __setvar_regexp__.match(var)
123 if match and match.group("keyword") in __setvar_keyword__:
124 base = match.group('base')
125 keyword = match.group("keyword")
126 override = match.group('add')
127 l = self.getVarFlag(base, keyword) or []
128 l.append([value, override])
129 self.setVarFlag(base, keyword, l)
131 # pay the cookie monster
133 self._special_values[keyword].add( base )
135 self._special_values[keyword] = Set()
136 self._special_values[keyword].add( base )
138 # SRC_URI_append_simpad is both a flag and a override
139 #if not override in self._seen_overrides:
140 # self._seen_overrides[override] = Set()
141 #self._seen_overrides[override].add( base )
144 if not var in self.dict:
145 self._makeShadowCopy(var)
146 if self.getVarFlag(var, 'matchesenv'):
147 self.delVarFlag(var, 'matchesenv')
148 self.setVarFlag(var, 'export', 1)
150 # more cookies for the cookie monster
152 override = var[var.rfind('_')+1:]
153 if not override in self._seen_overrides:
154 self._seen_overrides[override] = Set()
155 self._seen_overrides[override].add( var )
158 self.dict[var]["content"] = value
160 def getVar(self,var,exp):
161 value = self.getVarFlag(var,"content")
164 return self.expand(value,var)
167 def delVar(self,var):
168 if not var in self.dict:
169 self._makeShadowCopy(var)
172 def setVarFlag(self,var,flag,flagvalue):
173 if not var in self.dict:
174 self._makeShadowCopy(var)
175 self.dict[var][flag] = flagvalue
177 def getVarFlag(self,var,flag):
178 local_var = self._findVar(var)
180 if flag in local_var:
181 return copy.copy(local_var[flag])
184 def delVarFlag(self,var,flag):
185 local_var = self._findVar(var)
188 if not var in self.dict:
189 self._makeShadowCopy(var)
191 if var in self.dict and flag in self.dict[var]:
192 del self.dict[var][flag]
194 def setVarFlags(self,var,flags):
195 if not var in self.dict:
196 self._makeShadowCopy(var)
198 for i in flags.keys():
201 self.dict[var][i] = flags[i]
203 def getVarFlags(self,var):
204 local_var = self._findVar(var)
208 for i in self.dict[var].keys():
211 flags[i] = self.dict[var][i]
218 def delVarFlags(self,var):
219 if not var in self.dict:
220 self._makeShadowCopy(var)
225 # try to save the content
226 if "content" in self.dict[var]:
227 content = self.dict[var]["content"]
229 self.dict[var]["content"] = content
234 def createCopy(self):
236 Create a copy of self by setting _data to self
238 # we really want this to be a DataSmart...
240 data.dict["_data"] = self.dict
248 _keys(d["_data"],mykey)
254 _keys(self.dict,keytab)
257 def __getitem__(self,item):
262 elif "_data" in start:
263 start = start["_data"]
268 def __setitem__(self,var,data):
269 self._makeShadowCopy(var)
270 self.dict[var] = data
273 class DataSmartPackage(DataSmart):
275 Persistent Data Storage
277 def sanitize_filename(bbfile):
278 return bbfile.replace( '/', '_' )
279 sanitize_filename = staticmethod(sanitize_filename)
283 Restore the dict from memory
285 cache_bbfile = self.sanitize_filename(self.bbfile)
286 p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
288 self._seen_overrides = p.load()
289 self._special_values = p.load()
292 # compile the functions into global scope
293 funcs = self.getVar('__functions__', 0) or {}
294 for key in funcs.keys():
295 methodpool.check_insert_method( key, funcs[key], self.bbfile )
296 methodpool.parsed_module( key )
298 # now add the handlers which were present
299 handlers = self.getVar('__all_handlers__', 0) or {}
301 for key in handlers.keys():
302 bb.event.register(key, handlers[key])
305 def linkDataSet(self):
306 if not self.parent == None:
307 # assume parent is a DataSmartInstance
308 self.dict["_data"] = self.parent.dict
311 def __init__(self,cache,name,clean,parent):
313 Construct a persistent data instance
315 #Initialize the dictionary
316 DataSmart.__init__(self)
319 self.bbfile = os.path.abspath( name )
322 # Either unpickle the data or do copy on write
328 def commit(self, mtime):
330 Save the package to a permanent storage
334 cache_bbfile = self.sanitize_filename(self.bbfile)
335 p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
337 p.dump( self._seen_overrides )
338 p.dump( self._special_values )
342 def mtime(cache,bbfile):
343 cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
345 return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
348 mtime = staticmethod(mtime)
350 def pickle_prep(self):
352 If self.dict contains a _data key and it is a configuration
353 we will remember we had a configuration instance attached
355 if "_data" in self.dict and self.dict["_data"] == self.parent:
356 dest["_data"] = "cfg"
358 def unpickle_prep(self):
360 If we had a configuration instance attached, we will reattach it
362 if "_data" in self.dict and self.dict["_data"] == "cfg":
363 self.dict["_data"] = self.parent