b7d707a9206cbdad4831ff2ee1b08d35d95b2f30
[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_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     Example:
215         >>> d = init()
216         >>> myflags = {}
217         >>> myflags['test'] = 'blah'
218         >>> setVarFlags('TEST', myflags, d)
219         >>> print getVarFlag('TEST', 'test', d)
220         blah
221     """
222     d.setVarFlags(var,flags)
223
224 def getVarFlags(var, d):
225     """Gets a variable's flags
226
227     Example:
228         >>> d = init()
229         >>> setVarFlag('TEST', 'test', 'blah', d)
230         >>> print getVarFlags('TEST', d)['test']
231         blah
232     """
233     return d.getVarFlags(var)
234
235 def delVarFlags(var, d):
236     """Removes a variable's flags
237
238     Example:
239         >>> data = init()
240         >>> setVarFlag('TEST', 'testflag', 1, data)
241         >>> print getVarFlag('TEST', 'testflag', data)
242         1
243         >>> delVarFlags('TEST', data)
244         >>> print getVarFlags('TEST', data)
245         None
246
247     """
248     d.delVarFlags(var)
249
250 def keys(d):
251     """Return a list of keys in d
252
253     Example:
254         >>> d = init()
255         >>> setVar('TEST',  1, d)
256         >>> setVar('MOO' ,  2, d)
257         >>> setVarFlag('TEST', 'test', 1, d)
258         >>> keys(d)
259         ['TEST', 'MOO']
260     """
261     return d.keys()
262
263 def getData(d):
264     """Returns the data object used"""
265     return d
266
267 def setData(newData, d):
268     """Sets the data object to the supplied value"""
269     d = newData
270
271 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
272 __expand_python_regexp__ = re.compile(r"\${@.+?}")
273
274 def expand(s, d, varname = None):
275     """Variable expansion using the data store.
276
277     Example:
278         Standard expansion:
279         >>> d = init()
280         >>> setVar('A', 'sshd', d)
281         >>> print expand('/usr/bin/${A}', d)
282         /usr/bin/sshd
283
284         Python expansion:
285         >>> d = init()
286         >>> print expand('result: ${@37 * 72}', d)
287         result: 2664
288
289         Shell expansion:
290         >>> d = init()
291         >>> print expand('${TARGET_MOO}', d)
292         ${TARGET_MOO}
293         >>> setVar('TARGET_MOO', 'yupp', d)
294         >>> print expand('${TARGET_MOO}',d)
295         yupp
296         >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
297         >>> delVar('TARGET_MOO', d)
298         >>> print expand('${SRC_URI}', d)
299         http://somebug.${TARGET_MOO}
300     """
301     def var_sub(match):
302         key = match.group()[2:-1]
303         if varname and key:
304             if varname == key:
305                 raise Exception("variable %s references itself!" % varname)
306         var = getVar(key, d, 1)
307         if var is not None:
308             return var
309         else:
310             return match.group()
311
312     def python_sub(match):
313         import bb
314         code = match.group()[3:-1]
315         locals()['d'] = d
316         s = eval(code)
317         if type(s) == types.IntType: s = str(s)
318         return s
319
320     if type(s) is not types.StringType: # sanity check
321         return s
322
323     while s.find('$') != -1:
324         olds = s
325         try:
326             s = __expand_var_regexp__.sub(var_sub, s)
327             s = __expand_python_regexp__.sub(python_sub, s)
328             if s == olds: break
329             if type(s) is not types.StringType: # sanity check
330                 import bb
331                 bb.error('expansion of %s returned non-string %s' % (olds, s))
332         except KeyboardInterrupt:
333             raise
334         except:
335             note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
336             raise
337     return s
338
339 def expandKeys(alterdata, readdata = None):
340     if readdata == None:
341         readdata = alterdata
342
343     for key in keys(alterdata):
344         ekey = expand(key, readdata)
345         if key == ekey:
346             continue
347         val = getVar(key, alterdata)
348         if val is None:
349             continue
350 #        import copy
351 #        setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
352         setVar(ekey, val, alterdata)
353
354         for i in ('_append', '_prepend', '_delete'):
355             dest = getVarFlag(ekey, i, alterdata) or []
356             src = getVarFlag(key, i, readdata) or []
357             dest.extend(src)
358             setVarFlag(ekey, i, dest, alterdata)
359
360         delVar(key, alterdata)
361
362 def expandData(alterdata, readdata = None):
363     """For each variable in alterdata, expand it, and update the var contents.
364        Replacements use data from readdata.
365
366     Example:
367         >>> a=init()
368         >>> b=init()
369         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
370         >>> setVar("DL_DIR", "/path/to/whatever", b)
371         >>> expandData(a, b)
372         >>> print getVar("dlmsg", a)
373         dl_dir is /path/to/whatever
374        """
375     if readdata == None:
376         readdata = alterdata
377
378     for key in keys(alterdata):
379         val = getVar(key, alterdata)
380         if type(val) is not types.StringType:
381             continue
382         expanded = expand(val, readdata)
383 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
384         if val != expanded:
385             setVar(key, expanded, alterdata)
386
387 import os
388
389 def inheritFromOS(d):
390     """Inherit variables from the environment."""
391 #   fakeroot needs to be able to set these
392     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
393     for s in os.environ.keys():
394         if not s in non_inherit_vars:
395             try:
396                 setVar(s, os.environ[s], d)
397                 setVarFlag(s, 'matchesenv', '1', d)
398             except TypeError:
399                 pass
400
401 import sys
402
403 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
404     """Emit a variable to be sourced by a shell."""
405     if getVarFlag(var, "python", d):
406         return 0
407
408     try:
409         if all:
410             oval = getVar(var, d, 0)
411         val = getVar(var, d, 1)
412     except KeyboardInterrupt:
413         raise
414     except:
415         excname = str(sys.exc_info()[0])
416         if excname == "bb.build.FuncFailed":
417             raise
418         o.write('# expansion of %s threw %s\n' % (var, excname))
419         return 0
420
421     if all:
422         o.write('# %s=%s\n' % (var, oval))
423
424     if type(val) is not types.StringType:
425         return 0
426
427     if getVarFlag(var, 'matchesenv', d):
428         return 0
429
430     if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
431         return 0
432
433     val.rstrip()
434     if not val:
435         return 0
436
437     if getVarFlag(var, "func", d):
438 #       NOTE: should probably check for unbalanced {} within the var
439         o.write("%s() {\n%s\n}\n" % (var, val))
440     else:
441         if getVarFlag(var, "export", d):
442             o.write('export ')
443         else:
444             if not all:
445                 return 0
446 #       if we're going to output this within doublequotes,
447 #       to a shell, we need to escape the quotes in the var
448         alter = re.sub('"', '\\"', val.strip())
449         o.write('%s="%s"\n' % (var, alter))
450     return 1
451
452
453 def emit_env(o=sys.__stdout__, d = init(), all=False):
454     """Emits all items in the data store in a format such that it can be sourced by a shell."""
455
456     env = keys(d)
457
458     for e in env:
459         if getVarFlag(e, "func", d):
460             continue
461         emit_var(e, o, d, all) and o.write('\n')
462
463     for e in env:
464         if not getVarFlag(e, "func", d):
465             continue
466         emit_var(e, o, d) and o.write('\n')
467
468 def update_data(d):
469     """Modifies the environment vars according to local overrides and commands.
470     Examples:
471         Appending to a variable:
472         >>> d = init()
473         >>> setVar('TEST', 'this is a', d)
474         >>> setVar('TEST_append', ' test', d)
475         >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
476         >>> update_data(d)
477         >>> print getVar('TEST', d)
478         this is a test of the emergency broadcast system.
479
480         Prepending to a variable:
481         >>> setVar('TEST', 'virtual/libc', d)
482         >>> setVar('TEST_prepend', 'virtual/tmake ', d)
483         >>> setVar('TEST_prepend', 'virtual/patcher ', d)
484         >>> update_data(d)
485         >>> print getVar('TEST', d)
486         virtual/patcher virtual/tmake virtual/libc
487
488         Overrides:
489         >>> setVar('TEST_arm', 'target', d)
490         >>> setVar('TEST_ramses', 'machine', d)
491         >>> setVar('TEST_local', 'local', d)
492         >>> setVar('OVERRIDES', 'arm', d)
493
494         >>> setVar('TEST', 'original', d)
495         >>> update_data(d)
496         >>> print getVar('TEST', d)
497         target
498
499         >>> setVar('OVERRIDES', 'arm:ramses:local', d)
500         >>> setVar('TEST', 'original', d)
501         >>> update_data(d)
502         >>> print getVar('TEST', d)
503         local
504     """
505
506     debug(2, "update_data()")
507
508 #   can't do delete env[...] while iterating over the dictionary, so remember them
509     dodel = []
510     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
511
512     def applyOverrides(var, d):
513         if not overrides:
514             debug(1, "OVERRIDES not defined, nothing to do")
515             return
516         val = getVar(var, d)
517         for o in overrides:
518             if var.endswith("_" + o):
519                 l = len(o)+1
520                 name = var[:-l]
521                 d[name] = d[var]
522
523     for s in keys(d):
524         applyOverrides(s, d)
525         sval = getVar(s, d) or ""
526
527 #       Handle line appends:
528         for (a, o) in getVarFlag(s, '_append', d) or []:
529             # maybe the OVERRIDE was not yet added so keep the append
530             if (o and o in overrides) or not o:
531                 delVarFlag(s, '_append', d)
532             if o:
533                 if not o in overrides:
534                     continue
535             sval+=a
536             setVar(s, sval, d)
537
538 #       Handle line prepends
539         for (a, o) in getVarFlag(s, '_prepend', d) or []:
540             # maybe the OVERRIDE was not yet added so keep the append
541             if (o and o in overrides) or not o:
542                 delVarFlag(s, '_prepend', d)
543             if o:
544                 if not o in overrides:
545                     continue
546             sval=a+sval
547             setVar(s, sval, d)
548
549 #       Handle line deletions
550         name = s + "_delete"
551         nameval = getVar(name, d)
552         if nameval:
553             sval = getVar(s, d)
554             if sval:
555                 new = ''
556                 pattern = nameval.replace('\n','').strip()
557                 for line in sval.split('\n'):
558                     if line.find(pattern) == -1:
559                         new = new + '\n' + line
560                 setVar(s, new, d)
561                 dodel.append(name)
562
563 #   delete all environment vars no longer needed
564     for s in dodel:
565         delVar(s, d)
566
567 def inherits_class(klass, d):
568     val = getVar('__inherit_cache', d) or ""
569     if os.path.join('classes', '%s.bbclass' % klass) in val.split():
570         return True
571     return False
572
573 def _test():
574     """Start a doctest run on this module"""
575     import doctest
576     from bb import data
577     doctest.testmod(data)
578
579 if __name__ == "__main__":
580     _test()