data_smart: Fix getVarFlags bug in data_smart
[bitbake.git] / 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 """
10
11 # Copyright (C) 2003, 2004  Chris Larson
12 # Copyright (C) 2004, 2005  Seb Frankengul
13 # Copyright (C) 2005, 2006  Holger Hans Peter Freyther
14 # Copyright (C) 2005        Uli Luckas
15 # Copyright (C) 2005        ROAD GmbH
16 #
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License version 2 as
19 # published by the Free Software Foundation.
20 #
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 # GNU General Public License for more details.
25 #
26 # You should have received a copy of the GNU General Public License along
27 # with this program; if not, write to the Free Software Foundation, Inc.,
28 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 # Based on functions from the base bb module, Copyright 2003 Holger Schurig
30
31 import copy, os, re, sys, time, types
32 import bb
33 from bb   import utils, methodpool
34 from COW  import COWDictBase
35 from sets import Set
36 from new  import classobj
37
38
39 __setvar_keyword__ = ["_append","_prepend"]
40 __setvar_regexp__ = re.compile('(?P<base>.*?)(?P<keyword>_append|_prepend)(_(?P<add>.*))?')
41 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
42 __expand_python_regexp__ = re.compile(r"\${@.+?}")
43
44
45 class DataSmart:
46     def __init__(self, special = COWDictBase.copy(), seen = COWDictBase.copy() ):
47         self.dict = {}
48
49         # cookie monster tribute
50         self._special_values = special
51         self._seen_overrides = seen
52
53         self.expand_cache = {}
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         if varname and varname in self.expand_cache:
79             return self.expand_cache[varname]
80
81         while s.find('${') != -1:
82             olds = s
83             try:
84                 s = __expand_var_regexp__.sub(var_sub, s)
85                 s = __expand_python_regexp__.sub(python_sub, s)
86                 if s == olds: break
87                 if type(s) is not types.StringType: # sanity check
88                     bb.msg.error(bb.msg.domain.Data, 'expansion of %s returned non-string %s' % (olds, s))
89             except KeyboardInterrupt:
90                 raise
91             except:
92                 bb.msg.note(1, bb.msg.domain.Data, "%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
93                 raise
94
95         if varname:
96             self.expand_cache[varname] = s
97
98         return s
99
100     def initVar(self, var):
101         self.expand_cache = {}
102         if not var in self.dict:
103             self.dict[var] = {}
104
105     def _findVar(self,var):
106         _dest = self.dict
107
108         while (_dest and var not in _dest):
109             if not "_data" in _dest:
110                 _dest = None
111                 break
112             _dest = _dest["_data"]
113
114         if _dest and var in _dest:
115             return _dest[var]
116         return None
117
118     def _makeShadowCopy(self, var):
119         if var in self.dict:
120             return
121
122         local_var = self._findVar(var)
123
124         if local_var:
125             self.dict[var] = copy.copy(local_var)
126         else:
127             self.initVar(var)
128
129     def setVar(self,var,value):
130         self.expand_cache = {}
131         match  = __setvar_regexp__.match(var)
132         if match and match.group("keyword") in __setvar_keyword__:
133             base = match.group('base')
134             keyword = match.group("keyword")
135             override = match.group('add')
136             l = self.getVarFlag(base, keyword) or []
137             l.append([value, override])
138             self.setVarFlag(base, keyword, l)
139
140             # todo make sure keyword is not __doc__ or __module__
141             # pay the cookie monster
142             try:
143                 self._special_values[keyword].add( base )
144             except:
145                 self._special_values[keyword] = Set()
146                 self._special_values[keyword].add( base )
147
148             return
149
150         if not var in self.dict:
151             self._makeShadowCopy(var)
152         if self.getVarFlag(var, 'matchesenv'):
153             self.delVarFlag(var, 'matchesenv')
154             self.setVarFlag(var, 'export', 1)
155
156         # more cookies for the cookie monster
157         if '_' in var:
158             override = var[var.rfind('_')+1:]
159             if not self._seen_overrides.has_key(override):
160                 self._seen_overrides[override] = Set()
161             self._seen_overrides[override].add( var )
162
163         # setting var
164         self.dict[var]["content"] = value
165
166     def getVar(self,var,exp):
167         value = self.getVarFlag(var,"content")
168
169         if exp and value:
170             return self.expand(value,var)
171         return value
172
173     def renameVar(self, key, newkey):
174         """
175         Rename the variable key to newkey 
176         """
177         val = self.getVar(key, 0)
178         if val is None:
179             return
180
181         self.setVar(newkey, val)
182
183         for i in ('_append', '_prepend'):
184             dest = self.getVarFlag(newkey, i) or []
185             src = self.getVarFlag(key, i) or []
186             dest.extend(src)
187             self.setVarFlag(newkey, i, dest)
188             
189             if self._special_values.has_key(i) and key in self._special_values[i]:
190                 self._special_values[i].remove(key)
191                 self._special_values[i].add(newkey)
192
193         self.delVar(key)
194
195     def delVar(self,var):
196         self.expand_cache = {}
197         self.dict[var] = {}
198
199     def setVarFlag(self,var,flag,flagvalue):
200         if not var in self.dict:
201             self._makeShadowCopy(var)
202         self.dict[var][flag] = flagvalue
203
204     def getVarFlag(self,var,flag):
205         local_var = self._findVar(var)
206         if local_var:
207             if flag in local_var:
208                 return copy.copy(local_var[flag])
209         return None
210
211     def delVarFlag(self,var,flag):
212         local_var = self._findVar(var)
213         if not local_var:
214             return
215         if not var in self.dict:
216             self._makeShadowCopy(var)
217
218         if var in self.dict and flag in self.dict[var]:
219             del self.dict[var][flag]
220
221     def setVarFlags(self,var,flags):
222         if not var in self.dict:
223             self._makeShadowCopy(var)
224
225         for i in flags.keys():
226             if i == "content":
227                 continue
228             self.dict[var][i] = flags[i]
229
230     def getVarFlags(self,var):
231         local_var = self._findVar(var)
232         flags = {}
233
234         if local_var:
235             for i in local_var.keys():
236                 if i == "content":
237                     continue
238                 flags[i] = local_var[i]
239
240         if len(flags) == 0:
241             return None
242         return flags
243
244
245     def delVarFlags(self,var):
246         if not var in self.dict:
247             self._makeShadowCopy(var)
248
249         if var in self.dict:
250             content = None
251
252             # try to save the content
253             if "content" in self.dict[var]:
254                 content  = self.dict[var]["content"]
255                 self.dict[var]            = {}
256                 self.dict[var]["content"] = content
257             else:
258                 del self.dict[var]
259
260
261     def createCopy(self):
262         """
263         Create a copy of self by setting _data to self
264         """
265         # we really want this to be a DataSmart...
266         data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy())
267         data.dict["_data"] = self.dict
268
269         return data
270
271     # Dictionary Methods
272     def keys(self):
273         def _keys(d, mykey):
274             if "_data" in d:
275                 _keys(d["_data"],mykey)
276
277             for key in d.keys():
278                 if key != "_data":
279                     mykey[key] = None
280         keytab = {}
281         _keys(self.dict,keytab)
282         return keytab.keys()
283
284     def __getitem__(self,item):
285         #print "Warning deprecated"
286         return self.getVar(item, False)
287
288     def __setitem__(self,var,data):
289         #print "Warning deprecated"
290         self.setVar(var,data)
291
292