0aeda8de08939f3a93aa8b4853e3d6b86f5181cd
[vuplus_bitbake] / lib / bb / data.py
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 """
5 BitBake 'Data' implementations
6
7 Functions for interacting with the data structure used by the
8 BitBake build tools.
9
10 Copyright (C) 2003, 2004  Chris Larson
11 Copyright (C) 2005        Holger Hans Peter Freyther
12
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License as published by the Free Software
15 Foundation; either version 2 of the License, or (at your option) any later
16 version.
17
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
24 Place, Suite 330, Boston, MA 02111-1307 USA. 
25
26 Based on functions from the base bb module, Copyright 2003 Holger Schurig
27 """
28
29 import sys, os, re, time, types
30 if sys.argv[0][-5:] == "pydoc":
31     path = os.path.dirname(os.path.dirname(sys.argv[1]))
32 else:
33     path = os.path.dirname(os.path.dirname(sys.argv[0]))
34 sys.path.append(path)
35
36 from bb import note, debug, data_dict
37
38 _dict_type = data_dict.DataDict
39 _dict_p_type = data_dict.DataDictPackage
40
41
42 def init():
43     return _dict_type()
44
45 def init_db(cache,name,clean,parent = None):
46     return _dict_p_type(cache,name,clean,parent)
47
48 def init_db_mtime(cache,cache_bbfile):
49     return _dict_p_type.mtime(cache,cache_bbfile)
50
51 _data_dict = init()
52
53 def createCopy(source):
54      """Link the source set to the destination
55      If one does not find the value in the destination set,
56      search will go on to the source set to get the value.
57      Value from source are copy-on-write. i.e. any try to
58      modify one of them will end up putting the modified value
59      in the destination set.
60      """
61      return source.createCopy()
62
63 def initVar(var, d = _data_dict):
64     """Non-destructive var init for data structure"""
65     d.initVar(var)
66
67
68 def setVar(var, value, d = _data_dict):
69     """Set a variable to a given value
70
71     Example:
72         >>> setVar('TEST', 'testcontents')
73         >>> print getVar('TEST')
74         testcontents
75     """
76     d.setVar(var,value)
77
78
79 def getVar(var, d = _data_dict, exp = 0):
80     """Gets the value of a variable
81
82     Example:
83         >>> setVar('TEST', 'testcontents')
84         >>> print getVar('TEST')
85         testcontents
86     """
87     return d.getVar(var,exp)
88
89 def delVar(var, d = _data_dict):
90     """Removes a variable from the data set
91
92     Example:
93         >>> setVar('TEST', 'testcontents')
94         >>> print getVar('TEST')
95         testcontents
96         >>> delVar('TEST')
97         >>> print getVar('TEST')
98         None
99     """
100     d.delVar(var)
101
102 def setVarFlag(var, flag, flagvalue, d = _data_dict):
103     """Set a flag for a given variable to a given value
104
105     Example:
106         >>> setVarFlag('TEST', 'python', 1)
107         >>> print getVarFlag('TEST', 'python')
108         1
109     """
110     d.setVarFlag(var,flag,flagvalue)
111
112 def getVarFlag(var, flag, d = _data_dict):
113     """Gets given flag from given var
114
115     Example:
116         >>> setVarFlag('TEST', 'python', 1)
117         >>> print getVarFlag('TEST', 'python')
118         1
119     """
120     return d.getVarFlag(var,flag)
121
122 def delVarFlag(var, flag, d = _data_dict):
123     """Removes a given flag from the variable's flags
124
125     Example:
126         >>> setVarFlag('TEST', 'testflag', 1)
127         >>> print getVarFlag('TEST', 'testflag')
128         1
129         >>> delVarFlag('TEST', 'testflag')
130         >>> print getVarFlag('TEST', 'testflag')
131         None
132
133     """
134     d.delVarFlag(var,flag)
135
136 def setVarFlags(var, flags, d = _data_dict):
137     """Set the flags for a given variable
138
139     Example:
140         >>> myflags = {}
141         >>> myflags['test'] = 'blah'
142         >>> setVarFlags('TEST', myflags)
143         >>> print getVarFlag('TEST', 'test')
144         blah
145     """
146     d.setVarFlags(var,flags)
147
148 def getVarFlags(var, d = _data_dict):
149     """Gets a variable's flags
150
151     Example:
152         >>> setVarFlag('TEST', 'test', 'blah')
153         >>> print getVarFlags('TEST')['test']
154         blah
155     """
156     return d.getVarFlags(var)
157
158 def delVarFlags(var, d = _data_dict):
159     """Removes a variable's flags
160
161     Example:
162         >>> data = init()
163         >>> setVarFlag('TEST', 'testflag', 1, data)
164         >>> print getVarFlag('TEST', 'testflag', data)
165         1
166         >>> delVarFlags('TEST', data)
167         >>> print getVarFlags('TEST', data)
168         None
169
170     """
171     d.delVarFlags(var)
172
173 def keys(d = _data_dict):
174     """Return a list of keys in d
175
176     Example:
177         >>> d = init()
178         >>> setVar('TEST',  1, d)
179         >>> setVar('MOO' ,  2, d)
180         >>> setVarFlag('TEST', 'test', 1, d)
181         >>> keys(d)
182         ['TEST', 'MOO']
183     """
184     return d.keys()
185
186 def getData(d = _data_dict):
187     """Returns the data object used"""
188     return d
189
190 def setData(newData, d = _data_dict):
191     """Sets the data object to the supplied value"""
192     d = newData
193
194 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
195 __expand_python_regexp__ = re.compile(r"\${@.+?}")
196
197 def expand(s, d = _data_dict, varname = None):
198     """Variable expansion using the data store.
199
200     Example:
201         Standard expansion:
202         >>> setVar('A', 'sshd')
203         >>> print expand('/usr/bin/${A}')
204         /usr/bin/sshd
205
206         Python expansion:
207         >>> print expand('result: ${@37 * 72}')
208         result: 2664
209     """
210     def var_sub(match):
211         key = match.group()[2:-1]
212         if varname and key:
213             if varname == key:
214                 raise Exception("variable %s references itself!" % varname)
215         var = getVar(key, d, 1)
216         if var is not None:
217             return var
218         else:
219             return match.group()
220
221     def python_sub(match):
222         import bb
223         code = match.group()[3:-1]
224         locals()['d'] = d
225         s = eval(code)
226         if type(s) == types.IntType: s = str(s)
227         return s
228
229     if type(s) is not types.StringType: # sanity check
230         return s
231
232     while s.find('$') != -1:
233         olds = s
234         try:
235             s = __expand_var_regexp__.sub(var_sub, s)
236             s = __expand_python_regexp__.sub(python_sub, s)
237             if s == olds: break
238             if type(s) is not types.StringType: # sanity check
239                 import bb
240                 bb.error('expansion of %s returned non-string %s' % (olds, s))
241         except KeyboardInterrupt:
242             raise
243         except:
244             note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
245             raise
246     return s
247
248 def expandKeys(alterdata = _data_dict, readdata = None):
249     if readdata == None:
250         readdata = alterdata
251
252     for key in keys(alterdata):
253         ekey = expand(key, readdata)
254         if key == ekey:
255             continue
256         val = getVar(key, alterdata)
257         if val is None:
258             continue
259 #        import copy
260 #        setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
261         setVar(ekey, val, alterdata)
262
263         for i in ('_append', '_prepend', '_delete'):
264             dest = getVarFlag(ekey, i, alterdata) or []
265             src = getVarFlag(key, i, readdata) or []
266             dest.extend(src)
267             setVarFlag(ekey, i, dest, alterdata)
268
269         delVar(key, alterdata)
270
271 def expandData(alterdata = _data_dict, readdata = None):
272     """For each variable in alterdata, expand it, and update the var contents.
273        Replacements use data from readdata.
274
275     Example:
276         >>> a=init()
277         >>> b=init()
278         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
279         >>> setVar("DL_DIR", "/path/to/whatever", b)
280         >>> expandData(a, b)
281         >>> print getVar("dlmsg", a)
282         dl_dir is /path/to/whatever
283        """
284     if readdata == None:
285         readdata = alterdata
286
287     for key in keys(alterdata):
288         val = getVar(key, alterdata)
289         if type(val) is not types.StringType:
290             continue
291         expanded = expand(val, readdata)
292 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
293         if val != expanded:
294             setVar(key, expanded, alterdata)
295
296 import os
297
298 def inheritFromOS(d = _data_dict):
299     """Inherit variables from the environment."""
300 #   fakeroot needs to be able to set these
301     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
302     for s in os.environ.keys():
303         if not s in non_inherit_vars:
304             try:
305                 setVar(s, os.environ[s], d)
306                 setVarFlag(s, 'matchesenv', '1', d)
307             except TypeError:
308                 pass
309
310 import sys
311
312 def emit_var(var, o=sys.__stdout__, d = _data_dict, all=False):
313     """Emit a variable to be sourced by a shell."""
314     if getVarFlag(var, "python", d):
315         return 0
316
317     try:
318         if all:
319             oval = getVar(var, d, 0)
320         val = getVar(var, d, 1)
321     except KeyboardInterrupt:
322         raise
323     except:
324         excname = str(sys.exc_info()[0])
325         if excname == "bb.build.FuncFailed":
326             raise
327         o.write('# expansion of %s threw %s\n' % (var, excname))
328         return 0
329
330     if all:
331         o.write('# %s=%s\n' % (var, oval))
332
333     if type(val) is not types.StringType:
334         return 0
335
336     if getVarFlag(var, 'matchesenv', d):
337         return 0
338
339     if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
340         return 0
341
342     val.rstrip()
343     if not val:
344         return 0
345
346     if getVarFlag(var, "func", d):
347 #       NOTE: should probably check for unbalanced {} within the var
348         o.write("%s() {\n%s\n}\n" % (var, val))
349     else:
350         if getVarFlag(var, "export", d):
351             o.write('export ')
352         else:
353             if not all:
354                 return 0
355 #       if we're going to output this within doublequotes,
356 #       to a shell, we need to escape the quotes in the var
357         alter = re.sub('"', '\\"', val.strip())
358         o.write('%s="%s"\n' % (var, alter))
359     return 1
360
361
362 def emit_env(o=sys.__stdout__, d = _data_dict, all=False):
363     """Emits all items in the data store in a format such that it can be sourced by a shell."""
364
365     env = keys(d)
366
367     for e in env:
368         if getVarFlag(e, "func", d):
369             continue
370         emit_var(e, o, d, all) and o.write('\n')
371
372     for e in env:
373         if not getVarFlag(e, "func", d):
374             continue
375         emit_var(e, o, d) and o.write('\n')
376
377 def update_data(d = _data_dict):
378     """Modifies the environment vars according to local overrides and commands.
379     Examples:
380         Appending to a variable:
381         >>> setVar('TEST', 'this is a')
382         >>> setVar('TEST_append', ' test')
383         >>> setVar('TEST_append', ' of the emergency broadcast system.')
384         >>> update_data()
385         >>> print getVar('TEST')
386         this is a test of the emergency broadcast system.
387
388         Prepending to a variable:
389         >>> setVar('TEST', 'virtual/libc')
390         >>> setVar('TEST_prepend', 'virtual/tmake ')
391         >>> setVar('TEST_prepend', 'virtual/patcher ')
392         >>> update_data()
393         >>> print getVar('TEST')
394         virtual/patcher virtual/tmake virtual/libc
395
396         Overrides:
397         >>> setVar('TEST_arm', 'target')
398         >>> setVar('TEST_ramses', 'machine')
399         >>> setVar('TEST_local', 'local')
400         >>> setVar('OVERRIDES', 'arm')
401
402         >>> setVar('TEST', 'original')
403         >>> update_data()
404         >>> print getVar('TEST')
405         target
406
407         >>> setVar('OVERRIDES', 'arm:ramses:local')
408         >>> setVar('TEST', 'original')
409         >>> update_data()
410         >>> print getVar('TEST')
411         local
412     """
413
414     debug(2, "update_data()")
415
416 #   can't do delete env[...] while iterating over the dictionary, so remember them
417     dodel = []
418     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
419
420     def applyOverrides(var, d = _data_dict):
421         if not overrides:
422             debug(1, "OVERRIDES not defined, nothing to do")
423             return
424         val = getVar(var, d)
425         for o in overrides:
426             if var.endswith("_" + o):
427                 l = len(o)+1
428                 name = var[:-l]
429                 d[name] = d[var]
430
431     for s in keys(d):
432         applyOverrides(s, d)
433         sval = getVar(s, d) or ""
434
435 #       Handle line appends:
436         for (a, o) in getVarFlag(s, '_append', d) or []:
437             # maybe the OVERRIDE was not yet added so keep the append
438             if (o and o in overrides) or not o:
439                 delVarFlag(s, '_append', d)
440             if o:
441                 if not o in overrides:
442                     continue
443             sval+=a
444             setVar(s, sval, d)
445
446 #       Handle line prepends
447         for (a, o) in getVarFlag(s, '_prepend', d) or []:
448             # maybe the OVERRIDE was not yet added so keep the append
449             if (o and o in overrides) or not o:
450                 delVarFlag(s, '_prepend', d)
451             if o:
452                 if not o in overrides:
453                     continue
454             sval=a+sval
455             setVar(s, sval, d)
456
457 #       Handle line deletions
458         name = s + "_delete"
459         nameval = getVar(name, d)
460         if nameval:
461             sval = getVar(s, d)
462             if sval:
463                 new = ''
464                 pattern = nameval.replace('\n','').strip()
465                 for line in sval.split('\n'):
466                     if line.find(pattern) == -1:
467                         new = new + '\n' + line
468                 setVar(s, new, d)
469                 dodel.append(name)
470
471 #   delete all environment vars no longer needed
472     for s in dodel:
473         delVar(s, d)
474
475 def inherits_class(klass, d):
476     val = getVar('__inherit_cache', d) or ""
477     if os.path.join('classes', '%s.bbclass' % klass) in val.split():
478         return True
479     return False
480
481 def _test():
482     """Start a doctest run on this module"""
483     import doctest
484     from bb import data
485     doctest.testmod(data)
486
487 if __name__ == "__main__":
488     _test()