lib/bb/data.py:
[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 class DataDictCache:
42     """
43     Databacked Dictionary implementation
44     """
45     def __init__(self, cache_dir):
46         self.cache_dir = cache_dir
47         self.files     = []
48
49     def has_key(self,key):
50         return key in self.files
51
52     def keys(self):
53         return self.files
54
55     def __setitem__(self, key, data):
56         """
57         Add the key to the list of known files and
58         place the data in the cache?
59         """
60         if key in self.files:
61             return
62
63         self.files.append(key)
64
65     def __getitem__(self, key):
66         if not key in self.files:
67             return None
68
69         # not cached yet
70         return _dict_p_type(self.cache_dir, key,False,None)
71
72
73
74 def init():
75     return _dict_type()
76
77 def init_db(cache,name,clean,parent = None):
78     return _dict_p_type(cache,name,clean,parent)
79
80 def init_db_mtime(cache,cache_bbfile):
81     return _dict_p_type.mtime(cache,cache_bbfile)
82
83 def pkgdata(use_cache, cache):
84     """
85     Return some sort of dictionary to lookup parsed dictionaires
86     """
87     if use_cache:
88         return DataDictCache(cache)
89     return {}
90
91 def createCopy(source):
92      """Link the source set to the destination
93      If one does not find the value in the destination set,
94      search will go on to the source set to get the value.
95      Value from source are copy-on-write. i.e. any try to
96      modify one of them will end up putting the modified value
97      in the destination set.
98      """
99      return source.createCopy()
100
101 def initVar(var, d):
102     """Non-destructive var init for data structure"""
103     d.initVar(var)
104
105
106 def setVar(var, value, d):
107     """Set a variable to a given value
108
109     Example:
110         >>> setVar('TEST', 'testcontents')
111         >>> print getVar('TEST')
112         testcontents
113     """
114     d.setVar(var,value)
115
116
117 def getVar(var, d, exp = 0):
118     """Gets the value of a variable
119
120     Example:
121         >>> setVar('TEST', 'testcontents')
122         >>> print getVar('TEST')
123         testcontents
124     """
125     return d.getVar(var,exp)
126
127 def delVar(var, d):
128     """Removes a variable from the data set
129
130     Example:
131         >>> setVar('TEST', 'testcontents')
132         >>> print getVar('TEST')
133         testcontents
134         >>> delVar('TEST')
135         >>> print getVar('TEST')
136         None
137     """
138     d.delVar(var)
139
140 def setVarFlag(var, flag, flagvalue, d):
141     """Set a flag for a given variable to a given value
142
143     Example:
144         >>> setVarFlag('TEST', 'python', 1)
145         >>> print getVarFlag('TEST', 'python')
146         1
147     """
148     d.setVarFlag(var,flag,flagvalue)
149
150 def getVarFlag(var, flag, d):
151     """Gets given flag from given var
152
153     Example:
154         >>> setVarFlag('TEST', 'python', 1)
155         >>> print getVarFlag('TEST', 'python')
156         1
157     """
158     return d.getVarFlag(var,flag)
159
160 def delVarFlag(var, flag, d):
161     """Removes a given flag from the variable's flags
162
163     Example:
164         >>> setVarFlag('TEST', 'testflag', 1)
165         >>> print getVarFlag('TEST', 'testflag')
166         1
167         >>> delVarFlag('TEST', 'testflag')
168         >>> print getVarFlag('TEST', 'testflag')
169         None
170
171     """
172     d.delVarFlag(var,flag)
173
174 def setVarFlags(var, flags, d):
175     """Set the flags for a given variable
176
177     Example:
178         >>> myflags = {}
179         >>> myflags['test'] = 'blah'
180         >>> setVarFlags('TEST', myflags)
181         >>> print getVarFlag('TEST', 'test')
182         blah
183     """
184     d.setVarFlags(var,flags)
185
186 def getVarFlags(var, d):
187     """Gets a variable's flags
188
189     Example:
190         >>> setVarFlag('TEST', 'test', 'blah')
191         >>> print getVarFlags('TEST')['test']
192         blah
193     """
194     return d.getVarFlags(var)
195
196 def delVarFlags(var, d):
197     """Removes a variable's flags
198
199     Example:
200         >>> data = init()
201         >>> setVarFlag('TEST', 'testflag', 1, data)
202         >>> print getVarFlag('TEST', 'testflag', data)
203         1
204         >>> delVarFlags('TEST', data)
205         >>> print getVarFlags('TEST', data)
206         None
207
208     """
209     d.delVarFlags(var)
210
211 def keys(d):
212     """Return a list of keys in d
213
214     Example:
215         >>> d = init()
216         >>> setVar('TEST',  1, d)
217         >>> setVar('MOO' ,  2, d)
218         >>> setVarFlag('TEST', 'test', 1, d)
219         >>> keys(d)
220         ['TEST', 'MOO']
221     """
222     return d.keys()
223
224 def getData(d):
225     """Returns the data object used"""
226     return d
227
228 def setData(newData, d):
229     """Sets the data object to the supplied value"""
230     d = newData
231
232 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
233 __expand_python_regexp__ = re.compile(r"\${@.+?}")
234
235 def expand(s, d, varname = None):
236     """Variable expansion using the data store.
237
238     Example:
239         Standard expansion:
240         >>> setVar('A', 'sshd')
241         >>> print expand('/usr/bin/${A}')
242         /usr/bin/sshd
243
244         Python expansion:
245         >>> print expand('result: ${@37 * 72}')
246         result: 2664
247     """
248     def var_sub(match):
249         key = match.group()[2:-1]
250         if varname and key:
251             if varname == key:
252                 raise Exception("variable %s references itself!" % varname)
253         var = getVar(key, d, 1)
254         if var is not None:
255             return var
256         else:
257             return match.group()
258
259     def python_sub(match):
260         import bb
261         code = match.group()[3:-1]
262         locals()['d'] = d
263         s = eval(code)
264         if type(s) == types.IntType: s = str(s)
265         return s
266
267     if type(s) is not types.StringType: # sanity check
268         return s
269
270     while s.find('$') != -1:
271         olds = s
272         try:
273             s = __expand_var_regexp__.sub(var_sub, s)
274             s = __expand_python_regexp__.sub(python_sub, s)
275             if s == olds: break
276             if type(s) is not types.StringType: # sanity check
277                 import bb
278                 bb.error('expansion of %s returned non-string %s' % (olds, s))
279         except KeyboardInterrupt:
280             raise
281         except:
282             note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
283             raise
284     return s
285
286 def expandKeys(alterdata, readdata = None):
287     if readdata == None:
288         readdata = alterdata
289
290     for key in keys(alterdata):
291         ekey = expand(key, readdata)
292         if key == ekey:
293             continue
294         val = getVar(key, alterdata)
295         if val is None:
296             continue
297 #        import copy
298 #        setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
299         setVar(ekey, val, alterdata)
300
301         for i in ('_append', '_prepend', '_delete'):
302             dest = getVarFlag(ekey, i, alterdata) or []
303             src = getVarFlag(key, i, readdata) or []
304             dest.extend(src)
305             setVarFlag(ekey, i, dest, alterdata)
306
307         delVar(key, alterdata)
308
309 def expandData(alterdata, readdata = None):
310     """For each variable in alterdata, expand it, and update the var contents.
311        Replacements use data from readdata.
312
313     Example:
314         >>> a=init()
315         >>> b=init()
316         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
317         >>> setVar("DL_DIR", "/path/to/whatever", b)
318         >>> expandData(a, b)
319         >>> print getVar("dlmsg", a)
320         dl_dir is /path/to/whatever
321        """
322     if readdata == None:
323         readdata = alterdata
324
325     for key in keys(alterdata):
326         val = getVar(key, alterdata)
327         if type(val) is not types.StringType:
328             continue
329         expanded = expand(val, readdata)
330 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
331         if val != expanded:
332             setVar(key, expanded, alterdata)
333
334 import os
335
336 def inheritFromOS(d):
337     """Inherit variables from the environment."""
338 #   fakeroot needs to be able to set these
339     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
340     for s in os.environ.keys():
341         if not s in non_inherit_vars:
342             try:
343                 setVar(s, os.environ[s], d)
344                 setVarFlag(s, 'matchesenv', '1', d)
345             except TypeError:
346                 pass
347
348 import sys
349
350 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
351     """Emit a variable to be sourced by a shell."""
352     if getVarFlag(var, "python", d):
353         return 0
354
355     try:
356         if all:
357             oval = getVar(var, d, 0)
358         val = getVar(var, d, 1)
359     except KeyboardInterrupt:
360         raise
361     except:
362         excname = str(sys.exc_info()[0])
363         if excname == "bb.build.FuncFailed":
364             raise
365         o.write('# expansion of %s threw %s\n' % (var, excname))
366         return 0
367
368     if all:
369         o.write('# %s=%s\n' % (var, oval))
370
371     if type(val) is not types.StringType:
372         return 0
373
374     if getVarFlag(var, 'matchesenv', d):
375         return 0
376
377     if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
378         return 0
379
380     val.rstrip()
381     if not val:
382         return 0
383
384     if getVarFlag(var, "func", d):
385 #       NOTE: should probably check for unbalanced {} within the var
386         o.write("%s() {\n%s\n}\n" % (var, val))
387     else:
388         if getVarFlag(var, "export", d):
389             o.write('export ')
390         else:
391             if not all:
392                 return 0
393 #       if we're going to output this within doublequotes,
394 #       to a shell, we need to escape the quotes in the var
395         alter = re.sub('"', '\\"', val.strip())
396         o.write('%s="%s"\n' % (var, alter))
397     return 1
398
399
400 def emit_env(o=sys.__stdout__, d = init(), all=False):
401     """Emits all items in the data store in a format such that it can be sourced by a shell."""
402
403     env = keys(d)
404
405     for e in env:
406         if getVarFlag(e, "func", d):
407             continue
408         emit_var(e, o, d, all) and o.write('\n')
409
410     for e in env:
411         if not getVarFlag(e, "func", d):
412             continue
413         emit_var(e, o, d) and o.write('\n')
414
415 def update_data(d):
416     """Modifies the environment vars according to local overrides and commands.
417     Examples:
418         Appending to a variable:
419         >>> setVar('TEST', 'this is a')
420         >>> setVar('TEST_append', ' test')
421         >>> setVar('TEST_append', ' of the emergency broadcast system.')
422         >>> update_data()
423         >>> print getVar('TEST')
424         this is a test of the emergency broadcast system.
425
426         Prepending to a variable:
427         >>> setVar('TEST', 'virtual/libc')
428         >>> setVar('TEST_prepend', 'virtual/tmake ')
429         >>> setVar('TEST_prepend', 'virtual/patcher ')
430         >>> update_data()
431         >>> print getVar('TEST')
432         virtual/patcher virtual/tmake virtual/libc
433
434         Overrides:
435         >>> setVar('TEST_arm', 'target')
436         >>> setVar('TEST_ramses', 'machine')
437         >>> setVar('TEST_local', 'local')
438         >>> setVar('OVERRIDES', 'arm')
439
440         >>> setVar('TEST', 'original')
441         >>> update_data()
442         >>> print getVar('TEST')
443         target
444
445         >>> setVar('OVERRIDES', 'arm:ramses:local')
446         >>> setVar('TEST', 'original')
447         >>> update_data()
448         >>> print getVar('TEST')
449         local
450     """
451
452     debug(2, "update_data()")
453
454 #   can't do delete env[...] while iterating over the dictionary, so remember them
455     dodel = []
456     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
457
458     def applyOverrides(var, d):
459         if not overrides:
460             debug(1, "OVERRIDES not defined, nothing to do")
461             return
462         val = getVar(var, d)
463         for o in overrides:
464             if var.endswith("_" + o):
465                 l = len(o)+1
466                 name = var[:-l]
467                 d[name] = d[var]
468
469     for s in keys(d):
470         applyOverrides(s, d)
471         sval = getVar(s, d) or ""
472
473 #       Handle line appends:
474         for (a, o) in getVarFlag(s, '_append', d) or []:
475             # maybe the OVERRIDE was not yet added so keep the append
476             if (o and o in overrides) or not o:
477                 delVarFlag(s, '_append', d)
478             if o:
479                 if not o in overrides:
480                     continue
481             sval+=a
482             setVar(s, sval, d)
483
484 #       Handle line prepends
485         for (a, o) in getVarFlag(s, '_prepend', d) or []:
486             # maybe the OVERRIDE was not yet added so keep the append
487             if (o and o in overrides) or not o:
488                 delVarFlag(s, '_prepend', d)
489             if o:
490                 if not o in overrides:
491                     continue
492             sval=a+sval
493             setVar(s, sval, d)
494
495 #       Handle line deletions
496         name = s + "_delete"
497         nameval = getVar(name, d)
498         if nameval:
499             sval = getVar(s, d)
500             if sval:
501                 new = ''
502                 pattern = nameval.replace('\n','').strip()
503                 for line in sval.split('\n'):
504                     if line.find(pattern) == -1:
505                         new = new + '\n' + line
506                 setVar(s, new, d)
507                 dodel.append(name)
508
509 #   delete all environment vars no longer needed
510     for s in dodel:
511         delVar(s, d)
512
513 def inherits_class(klass, d):
514     val = getVar('__inherit_cache', d) or ""
515     if os.path.join('classes', '%s.bbclass' % klass) in val.split():
516         return True
517     return False
518
519 def _test():
520     """Start a doctest run on this module"""
521     import doctest
522     from bb import data
523     doctest.testmod(data)
524
525 if __name__ == "__main__":
526     _test()