bitbake/lib/bb/data.py:
[vuplus_bitbake] / lib / bb / data_smart.py
1 # ex:ts=4:sw=4:sts=4:et
2 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 """
4 BitBake Smart Dictionary Implementation
5
6 Functions for interacting with the data structure used by the
7 BitBake build tools.
8
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
14
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
18 version.
19
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.
23
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. 
27
28 Based on functions from the base bb module, Copyright 2003 Holger Schurig
29 """
30
31 import copy, os, re, sys, time, types
32 from bb   import note, debug, error, fatal, utils, methodpool
33 from sets import Set
34
35 try:
36     import cPickle as pickle
37 except ImportError:
38     import pickle
39     print "NOTE: Importing cPickle failed. Falling back to a very slow implementation."
40
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"\${@.+?}")
45
46
47 class DataSmart:
48     def __init__(self):
49         self.dict = {}
50
51         # cookie monster tribute
52         self._special_values = {}
53         self._seen_overrides = {}
54
55     def expand(self,s, varname):
56         def var_sub(match):
57             key = match.group()[2:-1]
58             if varname and key:
59                 if varname == key:
60                     raise Exception("variable %s references itself!" % varname)
61             var = self.getVar(key, 1)
62             if var is not None:
63                 return var
64             else:
65                 return match.group()
66
67         def python_sub(match):
68             import bb
69             code = match.group()[3:-1]
70             locals()['d'] = self
71             s = eval(code)
72             if type(s) == types.IntType: s = str(s)
73             return s
74
75         if type(s) is not types.StringType: # sanity check
76             return s
77
78         while s.find('$') != -1:
79             olds = s
80             try:
81                 s = __expand_var_regexp__.sub(var_sub, s)
82                 s = __expand_python_regexp__.sub(python_sub, s)
83                 if s == olds: break
84                 if type(s) is not types.StringType: # sanity check
85                     error('expansion of %s returned non-string %s' % (olds, s))
86             except KeyboardInterrupt:
87                 raise
88             except:
89                 note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
90                 raise
91         return s
92
93     def initVar(self, var):
94         if not var in self.dict:
95             self.dict[var] = {}
96
97     def _findVar(self,var):
98         _dest = self.dict
99
100         while (_dest and var not in _dest):
101             if not "_data" in _dest:
102                 _dest = None
103                 break
104             _dest = _dest["_data"]
105
106         if _dest and var in _dest:
107             return _dest[var]
108         return None
109
110     def _makeShadowCopy(self, var):
111         if var in self.dict:
112             return
113
114         local_var = self._findVar(var)
115
116         if local_var:
117             self.dict[var] = copy.copy(local_var)
118         else:
119             self.initVar(var)
120
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)
130
131             # pay the cookie monster
132             try:
133                 self._special_values[keyword].add( base )
134             except:
135                 self._special_values[keyword] = Set()
136                 self._special_values[keyword].add( base )
137
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 )
142             return
143
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)
149
150         # more cookies for the cookie monster
151         if '_' in var:
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 )
156
157         # setting var
158         self.dict[var]["content"] = value
159
160     def getVar(self,var,exp):
161         value = self.getVarFlag(var,"content")
162
163         if exp and value:
164             return self.expand(value,var)
165         return value
166
167     def delVar(self,var):
168         if not var in self.dict:
169             self._makeShadowCopy(var)
170         self.dict[var] = {}
171
172     def setVarFlag(self,var,flag,flagvalue):
173         if not var in self.dict:
174             self._makeShadowCopy(var)
175         self.dict[var][flag] = flagvalue
176
177     def getVarFlag(self,var,flag):
178         local_var = self._findVar(var)
179         if local_var:
180             if flag in local_var:
181                 return copy.copy(local_var[flag])
182         return None
183
184     def delVarFlag(self,var,flag):
185         local_var = self._findVar(var)
186         if not local_var:
187             return
188         if not var in self.dict:
189             self._makeShadowCopy(var)
190
191         if var in self.dict and flag in self.dict[var]:
192             del self.dict[var][flag]
193
194     def setVarFlags(self,var,flags):
195         if not var in self.dict:
196             self._makeShadowCopy(var)
197
198         for i in flags.keys():
199             if i == "content":
200                 continue
201             self.dict[var][i] = flags[i]
202
203     def getVarFlags(self,var):
204         local_var = self._findVar(var)
205         flags = {}
206
207         if local_var:
208             for i in self.dict[var].keys():
209                 if i == "content":
210                     continue
211                 flags[i] = self.dict[var][i]
212
213         if len(flags) == 0:
214             return None
215         return flags
216
217
218     def delVarFlags(self,var):
219         if not var in self.dict:
220             self._makeShadowCopy(var)
221
222         if var in self.dict:
223             content = None
224
225             # try to save the content
226             if "content" in self.dict[var]:
227                 content  = self.dict[var]["content"]
228                 self.dict[var]            = {}
229                 self.dict[var]["content"] = content
230             else:
231                 del self.dict[var]
232
233
234     def createCopy(self):
235         """
236         Create a copy of self by setting _data to self
237         """
238         # we really want this to be a DataSmart...
239         data = DataSmart()
240         data.dict["_data"] = self.dict
241
242         return data
243
244     # Dictionary Methods
245     def keys(self):
246         def _keys(d, mykey):
247             if "_data" in d:
248                 _keys(d["_data"],mykey)
249
250             for key in d.keys():
251                 if key != "_data":
252                     mykey[key] = None
253         keytab = {}
254         _keys(self.dict,keytab)
255         return keytab.keys()
256
257     def __getitem__(self,item):
258         start = self.dict
259         while start:
260             if item in start:
261                 return start[item]
262             elif "_data" in start:
263                 start = start["_data"]
264             else:
265                 start = None
266         return None
267
268     def __setitem__(self,var,data):
269         self._makeShadowCopy(var)
270         self.dict[var] = data
271
272
273 class DataSmartPackage(DataSmart):
274     """
275     Persistent Data Storage
276     """
277     def sanitize_filename(bbfile):
278         return bbfile.replace( '/', '_' )
279     sanitize_filename = staticmethod(sanitize_filename)
280
281     def unpickle(self):
282         """
283         Restore the dict from memory
284         """
285         cache_bbfile = self.sanitize_filename(self.bbfile)
286         p = pickle.Unpickler( file("%s/%s"%(self.cache,cache_bbfile),"rb"))
287         self.dict = p.load()
288         self._seen_overrides = p.load()
289         self._special_values = p.load()
290         self.unpickle_prep()
291
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 )
297
298         # now add the handlers which were present
299         handlers = self.getVar('__all_handlers__', 0) or {}
300         import bb.event
301         for key in handlers.keys():
302             bb.event.register(key, handlers[key])
303
304
305     def linkDataSet(self):
306         if not self.parent == None:
307             # assume parent is a DataSmartInstance
308             self.dict["_data"] = self.parent.dict
309
310
311     def __init__(self,cache,name,clean,parent):
312         """
313         Construct a persistent data instance
314         """
315         #Initialize the dictionary
316         DataSmart.__init__(self)
317
318         self.cache  = cache
319         self.bbfile = os.path.abspath( name )
320         self.parent = parent
321
322         # Either unpickle the data or do copy on write
323         if clean:
324             self.linkDataSet()
325         else:
326             self.unpickle()
327
328     def commit(self, mtime):
329         """
330         Save the package to a permanent storage
331         """
332         self.pickle_prep()
333
334         cache_bbfile = self.sanitize_filename(self.bbfile)
335         p = pickle.Pickler(file("%s/%s" %(self.cache,cache_bbfile), "wb" ), -1 )
336         p.dump( self.dict )
337         p.dump( self._seen_overrides )
338         p.dump( self._special_values )
339
340         self.unpickle_prep()
341
342     def mtime(cache,bbfile):
343         cache_bbfile = DataSmartPackage.sanitize_filename(bbfile)
344         try:
345             return os.stat( "%s/%s" % (cache,cache_bbfile) )[8]
346         except OSError:
347             return 0
348     mtime = staticmethod(mtime)
349
350     def pickle_prep(self):
351         """
352         If self.dict contains a _data key and it is a configuration
353         we will remember we had a configuration instance attached
354         """
355         if "_data" in self.dict and  self.dict["_data"] == self.parent:
356             dest["_data"] = "cfg"
357
358     def unpickle_prep(self):
359         """
360         If we had a configuration instance attached, we will reattach it
361         """
362         if "_data" in self.dict and  self.dict["_data"] == "cfg":
363             self.dict["_data"] = self.parent