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 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, fatal
35 import cPickle as pickle
38 print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
41 __setvar_keyword__ = ["_append","_prepend","_delete"]
42 __setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend|_delete)(_(?P<add>.*))?')
43 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
44 __expand_python_regexp__ = re.compile(r"\${@.+?}")
51 def expand(self,s, varname):
53 key = match.group()[2:-1]
56 raise Exception("variable %s references itself!" % varname)
57 var = self.getVar(key, 1)
63 def python_sub(match):
65 code = match.group()[3:-1]
68 if type(s) == types.IntType: s = str(s)
71 if type(s) is not types.StringType: # sanity check
74 while s.find('$') != -1:
77 s = __expand_var_regexp__.sub(var_sub, s)
78 s = __expand_python_regexp__.sub(python_sub, s)
80 if type(s) is not types.StringType: # sanity check
82 bb.error('expansion of %s returned non-string %s' % (olds, s))
83 except KeyboardInterrupt:
86 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
90 def initVar(self, var):
91 if not var in self.dict:
94 def pickle_prep(self, cfg):
95 if "_data" in self.dict:
96 if self.dict["_data"] == cfg:
97 self.dict["_data"] = "cfg";
98 else: # this is an unknown array for the moment
101 def unpickle_prep(self, cfg):
102 if "_data" in self.dict:
103 if self.dict["_data"] == "cfg":
104 self.dict["_data"] = cfg;
106 def _findVar(self,var):
109 while (_dest and var not in _dest):
110 if not "_data" in _dest:
113 _dest = _dest["_data"]
115 if _dest and var in _dest:
119 def _copyVar(self,var,name):
120 local_var = self._findVar(var)
122 self.dict[name] = copy.copy(local_var)
124 debug(1,"Warning, _copyVar %s to %s, %s does not exists" % (var,name,var))
127 def _makeShadowCopy(self, var):
131 local_var = self._findVar(var)
134 self.dict[var] = copy.copy(local_var)
138 def setVar(self,var,value):
139 match = __setvar_regexp__.match(var)
140 if match and match.group("keyword") in __setvar_keyword__:
141 base = match.group('base')
142 keyword = match.group("keyword")
143 override = match.group('add')
144 l = self.getVarFlag(base, keyword) or []
145 if override == 'delete':
146 if l.count([value, None]):
147 del l[l.index([value, None])]
148 l.append([value, override])
149 self.setVarFlag(base, match.group("keyword"), l)
152 if not var in self.dict:
153 self._makeShadowCopy(var)
154 if self.getVarFlag(var, 'matchesenv'):
155 self.delVarFlag(var, 'matchesenv')
156 self.setVarFlag(var, 'export', 1)
159 self.dict[var]["content"] = value
161 def getVar(self,var,exp):
162 value = self.getVarFlag(var,"content")
165 return self.expand(value,var)
168 def delVar(self,var):
171 def setVarFlag(self,var,flag,flagvalue):
172 if not var in self.dict:
173 self._makeShadowCopy(var)
174 self.dict[var][flag] = flagvalue
176 def getVarFlag(self,var,flag):
177 local_var = self._findVar(var)
179 if flag in local_var:
180 return copy.copy(local_var[flag])
183 def delVarFlag(self,var,flag):
184 local_var = self._findVar(var)
187 if not var in self.dict:
188 self._makeShadowCopy(var)
190 if var in self.dict and flag in self.dict[var]:
191 del self.dict[var][flag]
193 def setVarFlags(self,var,flags):
194 if not var in self.dict:
195 self._makeShadowCopy(var)
197 for i in flags.keys():
200 self.dict[var][i] = flags[i]
202 def getVarFlags(self,var):
203 local_var = self._findVar(var)
207 for i in self.dict[var].keys():
210 flags[i] = self.dict[var][i]
217 def delVarFlags(self,var):
218 if not var in self.dict:
219 self._makeShadowCopy(var)
224 # try to save the content
225 if "content" in self.dict[var]:
226 content = self.dict[var]["content"]
228 self.dict[var]["content"] = content
233 def createCopy(self):
235 Create a copy of self by setting _data to self
237 # we really want this to be a DataSmart...
239 data.dict["_data"] = self.dict
247 _keys(d["_data"],mykey)
253 _keys(self.dict,keytab)
256 def __getitem__(self,item):
261 elif "_data" in start:
262 start = start["_data"]
267 def __setitem__(self,var,data):
268 self._makeShadowCopy(var)
269 self.dict[var] = data
272 class DataSmartPackage(DataSmart):
274 Persistent Data Storage
276 def sanitize_filename(bbfile):
277 return bbfile.replace( '/', '_' )
278 sanitize_filename = staticmethod(sanitize_filename)
282 Restore the dict from memory
284 cache_bbfile = self.sanitize_filename(self.bbfile)
285 p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
288 funcstr = self.getVar('__functions__', 0)
290 comp = compile(funcstr, "<pickled>", "exec")
291 exec comp in __builtins__
293 def linkDataSet(self):
294 if not self.parent == None:
295 # assume parent is a DataSmartInstance
296 self.dict["_data"] = self.parent.dict
299 def __init__(self,cache,name,clean,parent):
301 Construct a persistent data instance
303 #Initialize the dictionary
304 DataSmart.__init__(self)
307 self.bbfile = os.path.abspath( name )
310 # Either unpickle the data or do copy on write
316 def commit(self, mtime):
318 Save the package to a permanent storage
322 cache_bbfile = self.sanitize_filename(self.bbfile)
323 p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
328 def mtime(cache,bbfile):
329 cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
331 return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
334 mtime = staticmethod(mtime)
336 def pickle_prep(self):
338 If self.dict contains a _data key and it is a configuration
339 we will remember we had a configuration instance attached
341 if "_data" in self.dict:
342 if self.dict["_data"] == self.parent:
343 dest["_data"] = "cfg"
345 def unpickle_prep(self):
347 If we had a configuration instance attached, we will reattach it
349 if "_data" in self.dict:
350 if self.dict["_data"] == "cfg":
351 self.dict["_data"] = self.parent