summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/data_smart.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/data_smart.py')
-rw-r--r--bitbake/lib/bb/data_smart.py351
1 files changed, 351 insertions, 0 deletions
diff --git a/bitbake/lib/bb/data_smart.py b/bitbake/lib/bb/data_smart.py
new file mode 100644
index 0000000000..741790502f
--- /dev/null
+++ b/bitbake/lib/bb/data_smart.py
@@ -0,0 +1,351 @@
1# ex:ts=4:sw=4:sts=4:et
2# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3"""
4BitBake Smart Dictionary Implementation
5
6Functions for interacting with the data structure used by the
7BitBake build tools.
8
9Copyright (C) 2003, 2004 Chris Larson
10Copyright (C) 2004, 2005 Seb Frankengul
11Copyright (C) 2005 Holger Hans Peter Freyther
12Copyright (C) 2005 Uli Luckas
13Copyright (C) 2005 ROAD GmbH
14
15This program is free software; you can redistribute it and/or modify it under
16the terms of the GNU General Public License as published by the Free Software
17Foundation; either version 2 of the License, or (at your option) any later
18version.
19
20This program is distributed in the hope that it will be useful, but WITHOUT
21ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
23
24You should have received a copy of the GNU General Public License along with
25this program; if not, write to the Free Software Foundation, Inc., 59 Temple
26Place, Suite 330, Boston, MA 02111-1307 USA.
27
28Based on functions from the base bb module, Copyright 2003 Holger Schurig
29"""
30
31import copy, os, re, sys, time, types
32from bb import note, debug, fatal
33
34try:
35 import cPickle as pickle
36except ImportError:
37 import pickle
38 print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
39
40
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"\${@.+?}")
45
46
47class DataSmart:
48 def __init__(self):
49 self.dict = {}
50
51 def expand(self,s, varname):
52 def var_sub(match):
53 key = match.group()[2:-1]
54 if varname and key:
55 if varname == key:
56 raise Exception("variable %s references itself!" % varname)
57 var = self.getVar(key, 1)
58 if var is not None:
59 return var
60 else:
61 return match.group()
62
63 def python_sub(match):
64 import bb
65 code = match.group()[3:-1]
66 locals()['d'] = self
67 s = eval(code)
68 if type(s) == types.IntType: s = str(s)
69 return s
70
71 if type(s) is not types.StringType: # sanity check
72 return s
73
74 while s.find('$') != -1:
75 olds = s
76 try:
77 s = __expand_var_regexp__.sub(var_sub, s)
78 s = __expand_python_regexp__.sub(python_sub, s)
79 if s == olds: break
80 if type(s) is not types.StringType: # sanity check
81 import bb
82 bb.error('expansion of %s returned non-string %s' % (olds, s))
83 except KeyboardInterrupt:
84 raise
85 except:
86 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
87 raise
88 return s
89
90 def initVar(self, var):
91 if not var in self.dict:
92 self.dict[var] = {}
93
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
99 pass
100
101 def unpickle_prep(self, cfg):
102 if "_data" in self.dict:
103 if self.dict["_data"] == "cfg":
104 self.dict["_data"] = cfg;
105
106 def _findVar(self,var):
107 _dest = self.dict
108
109 while (_dest and var not in _dest):
110 if not "_data" in _dest:
111 _dest = None
112 break
113 _dest = _dest["_data"]
114
115 if _dest and var in _dest:
116 return _dest[var]
117 return None
118
119 def _copyVar(self,var,name):
120 local_var = self._findVar(var)
121 if local_var:
122 self.dict[name] = copy.copy(local_var)
123 else:
124 debug(1,"Warning, _copyVar %s to %s, %s does not exists" % (var,name,var))
125
126
127 def _makeShadowCopy(self, var):
128 if var in self.dict:
129 return
130
131 local_var = self._findVar(var)
132
133 if local_var:
134 self.dict[var] = copy.copy(local_var)
135 else:
136 self.initVar(var)
137
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)
150 return
151
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)
157
158 # setting var
159 self.dict[var]["content"] = value
160
161 def getVar(self,var,exp):
162 value = self.getVarFlag(var,"content")
163
164 if exp and value:
165 return self.expand(value,var)
166 return value
167
168 def delVar(self,var):
169 self.dict[var] = {}
170
171 def setVarFlag(self,var,flag,flagvalue):
172 if not var in self.dict:
173 self._makeShadowCopy(var)
174 self.dict[var][flag] = flagvalue
175
176 def getVarFlag(self,var,flag):
177 local_var = self._findVar(var)
178 if local_var:
179 if flag in local_var:
180 return copy.copy(local_var[flag])
181 return None
182
183 def delVarFlag(self,var,flag):
184 local_var = self._findVar(var)
185 if not local_var:
186 return
187 if not var in self.dict:
188 self._makeShadowCopy(var)
189
190 if var in self.dict and flag in self.dict[var]:
191 del self.dict[var][flag]
192
193 def setVarFlags(self,var,flags):
194 if not var in self.dict:
195 self._makeShadowCopy(var)
196
197 for i in flags.keys():
198 if i == "content":
199 continue
200 self.dict[var][i] = flags[i]
201
202 def getVarFlags(self,var):
203 local_var = self._findVar(var)
204 flags = {}
205
206 if local_var:
207 for i in self.dict[var].keys():
208 if i == "content":
209 continue
210 flags[i] = self.dict[var][i]
211
212 if len(flags) == 0:
213 return None
214 return flags
215
216
217 def delVarFlags(self,var):
218 if not var in self.dict:
219 self._makeShadowCopy(var)
220
221 if var in self.dict:
222 content = None
223
224 # try to save the content
225 if "content" in self.dict[var]:
226 content = self.dict[var]["content"]
227 self.dict[var] = {}
228 self.dict[var]["content"] = content
229 else:
230 del self.dict[var]
231
232
233 def createCopy(self):
234 """
235 Create a copy of self by setting _data to self
236 """
237 # we really want this to be a DataSmart...
238 data = DataSmart()
239 data.dict["_data"] = self.dict
240
241 return data
242
243 # Dictionary Methods
244 def keys(self):
245 def _keys(d, mykey):
246 if "_data" in d:
247 _keys(d["_data"],mykey)
248
249 for key in d.keys():
250 if key != "_data":
251 mykey[key] = None
252 keytab = {}
253 _keys(self.dict,keytab)
254 return keytab.keys()
255
256 def __getitem__(self,item):
257 start = self.dict
258 while start:
259 if item in start:
260 return start[item]
261 elif "_data" in start:
262 start = start["_data"]
263 else:
264 start = None
265 return None
266
267 def __setitem__(self,var,data):
268 self._makeShadowCopy(var)
269 self.dict[var] = data
270
271
272class DataSmartPackage(DataSmart):
273 """
274 Persistent Data Storage
275 """
276 def sanitize_filename(bbfile):
277 return bbfile.replace( '/', '_' )
278 sanitize_filename = staticmethod(sanitize_filename)
279
280 def unpickle(self):
281 """
282 Restore the dict from memory
283 """
284 cache_bbfile = self.sanitize_filename(self.bbfile)
285 p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
286 self.dict = p.load()
287 self.unpickle_prep()
288 funcstr = self.getVar('__functions__', 0)
289 if funcstr:
290 comp = compile(funcstr, "<pickled>", "exec")
291 exec comp in __builtins__
292
293 def linkDataSet(self):
294 if not self.parent == None:
295 # assume parent is a DataSmartInstance
296 self.dict["_data"] = self.parent.dict
297
298
299 def __init__(self,cache,name,clean,parent):
300 """
301 Construct a persistent data instance
302 """
303 #Initialize the dictionary
304 DataSmart.__init__(self)
305
306 self.cache = cache
307 self.bbfile = os.path.abspath( name )
308 self.parent = parent
309
310 # Either unpickle the data or do copy on write
311 if clean:
312 self.linkDataSet()
313 else:
314 self.unpickle()
315
316 def commit(self, mtime):
317 """
318 Save the package to a permanent storage
319 """
320 self.pickle_prep()
321
322 cache_bbfile = self.sanitize_filename(self.bbfile)
323 p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
324 p.dump( self.dict )
325
326 self.unpickle_prep()
327
328 def mtime(cache,bbfile):
329 cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
330 try:
331 return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
332 except OSError:
333 return 0
334 mtime = staticmethod(mtime)
335
336 def pickle_prep(self):
337 """
338 If self.dict contains a _data key and it is a configuration
339 we will remember we had a configuration instance attached
340 """
341 if "_data" in self.dict:
342 if self.dict["_data"] == self.parent:
343 dest["_data"] = "cfg"
344
345 def unpickle_prep(self):
346 """
347 If we had a configuration instance attached, we will reattach it
348 """
349 if "_data" in self.dict:
350 if self.dict["_data"] == "cfg":
351 self.dict["_data"] = self.parent