bin/bitbake: Add better environmental variable handling. By default it will now only...
[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
153         # more cookies for the cookie monster
154         if '_' in var:
155             override = var[var.rfind('_')+1:]
156             if not self._seen_overrides.has_key(override):
157                 self._seen_overrides[override] = Set()
158             self._seen_overrides[override].add( var )
159
160         # setting var
161         self.dict[var]["content"] = value
162
163     def getVar(self,var,exp):
164         value = self.getVarFlag(var,"content")
165
166         if exp and value:
167             return self.expand(value,var)
168         return value
169
170     def renameVar(self, key, newkey):
171         """
172         Rename the variable key to newkey 
173         """
174         val = self.getVar(key, 0)
175         if val is None:
176             return
177
178         self.setVar(newkey, val)
179
180         for i in ('_append', '_prepend'):
181             dest = self.getVarFlag(newkey, i) or []
182             src = self.getVarFlag(key, i) or []
183             dest.extend(src)
184             self.setVarFlag(newkey, i, dest)
185             
186             if self._special_values.has_key(i) and key in self._special_values[i]:
187                 self._special_values[i].remove(key)
188                 self._special_values[i].add(newkey)
189
190         self.delVar(key)
191
192     def delVar(self,var):
193         self.expand_cache = {}
194         self.dict[var] = {}
195
196     def setVarFlag(self,var,flag,flagvalue):
197         if not var in self.dict:
198             self._makeShadowCopy(var)
199         self.dict[var][flag] = flagvalue
200
201     def getVarFlag(self,var,flag):
202         local_var = self._findVar(var)
203         if local_var:
204             if flag in local_var:
205                 return copy.copy(local_var[flag])
206         return None
207
208     def delVarFlag(self,var,flag):
209         local_var = self._findVar(var)
210         if not local_var:
211             return
212         if not var in self.dict:
213             self._makeShadowCopy(var)
214
215         if var in self.dict and flag in self.dict[var]:
216             del self.dict[var][flag]
217
218     def setVarFlags(self,var,flags):
219         if not var in self.dict:
220             self._makeShadowCopy(var)
221
222         for i in flags.keys():
223             if i == "content":
224                 continue
225             self.dict[var][i] = flags[i]
226
227     def getVarFlags(self,var):
228         local_var = self._findVar(var)
229         flags = {}
230
231         if local_var:
232             for i in local_var.keys():
233                 if i == "content":
234                     continue
235                 flags[i] = local_var[i]
236
237         if len(flags) == 0:
238             return None
239         return flags
240
241
242     def delVarFlags(self,var):
243         if not var in self.dict:
244             self._makeShadowCopy(var)
245
246         if var in self.dict:
247             content = None
248
249             # try to save the content
250             if "content" in self.dict[var]:
251                 content  = self.dict[var]["content"]
252                 self.dict[var]            = {}
253                 self.dict[var]["content"] = content
254             else:
255                 del self.dict[var]
256
257
258     def createCopy(self):
259         """
260         Create a copy of self by setting _data to self
261         """
262         # we really want this to be a DataSmart...
263         data = DataSmart(seen=self._seen_overrides.copy(), special=self._special_values.copy())
264         data.dict["_data"] = self.dict
265
266         return data
267
268     # Dictionary Methods
269     def keys(self):
270         def _keys(d, mykey):
271             if "_data" in d:
272                 _keys(d["_data"],mykey)
273
274             for key in d.keys():
275                 if key != "_data":
276                     mykey[key] = None
277         keytab = {}
278         _keys(self.dict,keytab)
279         return keytab.keys()
280
281     def __getitem__(self,item):
282         #print "Warning deprecated"
283         return self.getVar(item, False)
284
285     def __setitem__(self,var,data):
286         #print "Warning deprecated"
287         self.setVar(var,data)
288
289