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