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
241 data._seen_overrides = copy.copy(self._seen_overrides)
242 data._special_values = copy.copy(self._special_values)
250 _keys(d["_data"],mykey)
256 _keys(self.dict,keytab)
259 def __getitem__(self,item):
264 elif "_data" in start:
265 start = start["_data"]
270 def __setitem__(self,var,data):
271 self._makeShadowCopy(var)
272 self.dict[var] = data
275 class DataSmartPackage(DataSmart):
277 Persistent Data Storage
279 def sanitize_filename(bbfile):
280 return bbfile.replace( '/', '_' )
281 sanitize_filename = staticmethod(sanitize_filename)
285 Restore the dict from memory
287 cache_bbfile = self.sanitize_filename(self.bbfile)
288 p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
290 self._seen_overrides = p.load()
291 self._special_values = p.load()
294 # compile the functions into global scope
295 funcs = self.getVar('__functions__', 0) or {}
296 for key in funcs.keys():
297 methodpool.check_insert_method( key, funcs[key], self.bbfile )
298 methodpool.parsed_module( key )
300 # now add the handlers which were present
301 handlers = self.getVar('__all_handlers__', 0) or {}
303 for key in handlers.keys():
304 bb.event.register(key, handlers[key])
307 def linkDataSet(self):
308 if not self.parent == None:
309 # assume parent is a DataSmartInstance
310 self.dict["_data"] = self.parent.dict
313 def __init__(self,cache,name,clean,parent):
315 Construct a persistent data instance
317 #Initialize the dictionary
318 DataSmart.__init__(self)
321 self.bbfile = os.path.abspath( name )
324 # Either unpickle the data or do copy on write
327 self._seen_overrides = copy.copy(parent._seen_overrides)
328 self._special_values = copy.copy(parent._special_values)
332 def commit(self, mtime):
334 Save the package to a permanent storage
338 cache_bbfile = self.sanitize_filename(self.bbfile)
339 p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
341 p.dump( self._seen_overrides )
342 p.dump( self._special_values )
346 def mtime(cache,bbfile):
347 cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
349 return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
352 mtime = staticmethod(mtime)
354 def pickle_prep(self):
356 If self.dict contains a _data key and it is a configuration
357 we will remember we had a configuration instance attached
359 if "_data" in self.dict and self.dict["_data"] == self.parent:
360 dest["_data"] = "cfg"
362 def unpickle_prep(self):
364 If we had a configuration instance attached, we will reattach it
366 if "_data" in self.dict and self.dict["_data"] == "cfg":
367 self.dict["_data"] = self.parent