bitbake-1.8: Backport fixes for bugs from trunk
[bitbake.git] / lib / bb / data.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 'Data' implementations
5
6 Functions for interacting with the data structure used by the
7 BitBake build tools.
8
9 The expandData and update_data are the most expensive
10 operations. At night the cookie monster came by and
11 suggested 'give me cookies on setting the variables and
12 things will work out'. Taking this suggestion into account
13 applying the skills from the not yet passed 'Entwurf und
14 Analyse von Algorithmen' lecture and the cookie 
15 monster seems to be right. We will track setVar more carefully
16 to have faster update_data and expandKeys operations.
17
18 This is a treade-off between speed and memory again but
19 the speed is more critical here.
20 """
21
22 # Copyright (C) 2003, 2004  Chris Larson
23 # Copyright (C) 2005        Holger Hans Peter Freyther
24 #
25 # This program is free software; you can redistribute it and/or modify
26 # it under the terms of the GNU General Public License version 2 as
27 # published by the Free Software Foundation.
28 #
29 # This program is distributed in the hope that it will be useful,
30 # but WITHOUT ANY WARRANTY; without even the implied warranty of
31 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32 # GNU General Public License for more details.
33 #
34 # You should have received a copy of the GNU General Public License along
35 # with this program; if not, write to the Free Software Foundation, Inc.,
36 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
37 #
38 #Based on functions from the base bb module, Copyright 2003 Holger Schurig
39
40 import sys, os, re, time, types
41 if sys.argv[0][-5:] == "pydoc":
42     path = os.path.dirname(os.path.dirname(sys.argv[1]))
43 else:
44     path = os.path.dirname(os.path.dirname(sys.argv[0]))
45 sys.path.insert(0,path)
46
47 from bb import data_smart
48 import bb
49
50 _dict_type = data_smart.DataSmart
51
52 def init():
53     return _dict_type()
54
55 def init_db(parent = None):
56     if parent:
57         return parent.createCopy()
58     else:
59         return _dict_type()
60
61 def createCopy(source):
62      """Link the source set to the destination
63      If one does not find the value in the destination set,
64      search will go on to the source set to get the value.
65      Value from source are copy-on-write. i.e. any try to
66      modify one of them will end up putting the modified value
67      in the destination set.
68      """
69      return source.createCopy()
70
71 def initVar(var, d):
72     """Non-destructive var init for data structure"""
73     d.initVar(var)
74
75
76 def setVar(var, value, d):
77     """Set a variable to a given value
78
79     Example:
80         >>> d = init()
81         >>> setVar('TEST', 'testcontents', d)
82         >>> print getVar('TEST', d)
83         testcontents
84     """
85     d.setVar(var,value)
86
87
88 def getVar(var, d, exp = 0):
89     """Gets the value of a variable
90
91     Example:
92         >>> d = init()
93         >>> setVar('TEST', 'testcontents', d)
94         >>> print getVar('TEST', d)
95         testcontents
96     """
97     return d.getVar(var,exp)
98
99
100 def renameVar(key, newkey, d):
101     """Renames a variable from key to newkey
102
103     Example:
104         >>> d = init()
105         >>> setVar('TEST', 'testcontents', d)
106         >>> renameVar('TEST', 'TEST2', d)
107         >>> print getVar('TEST2', d)
108         testcontents
109     """
110     d.renameVar(key, newkey)
111
112 def delVar(var, d):
113     """Removes a variable from the data set
114
115     Example:
116         >>> d = init()
117         >>> setVar('TEST', 'testcontents', d)
118         >>> print getVar('TEST', d)
119         testcontents
120         >>> delVar('TEST', d)
121         >>> print getVar('TEST', d)
122         None
123     """
124     d.delVar(var)
125
126 def setVarFlag(var, flag, flagvalue, d):
127     """Set a flag for a given variable to a given value
128
129     Example:
130         >>> d = init()
131         >>> setVarFlag('TEST', 'python', 1, d)
132         >>> print getVarFlag('TEST', 'python', d)
133         1
134     """
135     d.setVarFlag(var,flag,flagvalue)
136
137 def getVarFlag(var, flag, d):
138     """Gets given flag from given var
139
140     Example:
141         >>> d = init()
142         >>> setVarFlag('TEST', 'python', 1, d)
143         >>> print getVarFlag('TEST', 'python', d)
144         1
145     """
146     return d.getVarFlag(var,flag)
147
148 def delVarFlag(var, flag, d):
149     """Removes a given flag from the variable's flags
150
151     Example:
152         >>> d = init()
153         >>> setVarFlag('TEST', 'testflag', 1, d)
154         >>> print getVarFlag('TEST', 'testflag', d)
155         1
156         >>> delVarFlag('TEST', 'testflag', d)
157         >>> print getVarFlag('TEST', 'testflag', d)
158         None
159
160     """
161     d.delVarFlag(var,flag)
162
163 def setVarFlags(var, flags, d):
164     """Set the flags for a given variable
165
166     Note:
167         setVarFlags will not clear previous
168         flags. Think of this method as
169         addVarFlags
170
171     Example:
172         >>> d = init()
173         >>> myflags = {}
174         >>> myflags['test'] = 'blah'
175         >>> setVarFlags('TEST', myflags, d)
176         >>> print getVarFlag('TEST', 'test', d)
177         blah
178     """
179     d.setVarFlags(var,flags)
180
181 def getVarFlags(var, d):
182     """Gets a variable's flags
183
184     Example:
185         >>> d = init()
186         >>> setVarFlag('TEST', 'test', 'blah', d)
187         >>> print getVarFlags('TEST', d)['test']
188         blah
189     """
190     return d.getVarFlags(var)
191
192 def delVarFlags(var, d):
193     """Removes a variable's flags
194
195     Example:
196         >>> data = init()
197         >>> setVarFlag('TEST', 'testflag', 1, data)
198         >>> print getVarFlag('TEST', 'testflag', data)
199         1
200         >>> delVarFlags('TEST', data)
201         >>> print getVarFlags('TEST', data)
202         None
203
204     """
205     d.delVarFlags(var)
206
207 def keys(d):
208     """Return a list of keys in d
209
210     Example:
211         >>> d = init()
212         >>> setVar('TEST',  1, d)
213         >>> setVar('MOO' ,  2, d)
214         >>> setVarFlag('TEST', 'test', 1, d)
215         >>> keys(d)
216         ['TEST', 'MOO']
217     """
218     return d.keys()
219
220 def getData(d):
221     """Returns the data object used"""
222     return d
223
224 def setData(newData, d):
225     """Sets the data object to the supplied value"""
226     d = newData
227
228
229 ##
230 ## Cookie Monsters' query functions
231 ##
232 def _get_override_vars(d, override):
233     """
234     Internal!!!
235
236     Get the Names of Variables that have a specific
237     override. This function returns a iterable
238     Set or an empty list
239     """
240     return []
241
242 def _get_var_flags_triple(d):
243     """
244     Internal!!!
245
246     """
247     return []
248
249 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
250 __expand_python_regexp__ = re.compile(r"\${@.+?}")
251
252 def expand(s, d, varname = None):
253     """Variable expansion using the data store.
254
255     Example:
256         Standard expansion:
257         >>> d = init()
258         >>> setVar('A', 'sshd', d)
259         >>> print expand('/usr/bin/${A}', d)
260         /usr/bin/sshd
261
262         Python expansion:
263         >>> d = init()
264         >>> print expand('result: ${@37 * 72}', d)
265         result: 2664
266
267         Shell expansion:
268         >>> d = init()
269         >>> print expand('${TARGET_MOO}', d)
270         ${TARGET_MOO}
271         >>> setVar('TARGET_MOO', 'yupp', d)
272         >>> print expand('${TARGET_MOO}',d)
273         yupp
274         >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
275         >>> delVar('TARGET_MOO', d)
276         >>> print expand('${SRC_URI}', d)
277         http://somebug.${TARGET_MOO}
278     """
279     return d.expand(s, varname)
280
281 def expandKeys(alterdata, readdata = None):
282     if readdata == None:
283         readdata = alterdata
284
285     for key in keys(alterdata):
286         if not '${' in key:
287             continue
288
289         ekey = expand(key, readdata)
290         if key == ekey:
291             continue
292
293         renameVar(key, ekey, alterdata)
294
295 def expandData(alterdata, readdata = None):
296     """For each variable in alterdata, expand it, and update the var contents.
297        Replacements use data from readdata.
298
299     Example:
300         >>> a=init()
301         >>> b=init()
302         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
303         >>> setVar("DL_DIR", "/path/to/whatever", b)
304         >>> expandData(a, b)
305         >>> print getVar("dlmsg", a)
306         dl_dir is /path/to/whatever
307        """
308     if readdata == None:
309         readdata = alterdata
310
311     for key in keys(alterdata):
312         val = getVar(key, alterdata)
313         if type(val) is not types.StringType:
314             continue
315         expanded = expand(val, readdata)
316 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
317         if val != expanded:
318             setVar(key, expanded, alterdata)
319
320 import os
321
322 def inheritFromOS(d):
323     """Inherit variables from the environment."""
324 #   fakeroot needs to be able to set these
325     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
326     for s in os.environ.keys():
327         if not s in non_inherit_vars:
328             try:
329                 setVar(s, os.environ[s], d)
330                 setVarFlag(s, 'matchesenv', '1', d)
331             except TypeError:
332                 pass
333
334 import sys
335
336 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
337     """Emit a variable to be sourced by a shell."""
338     if getVarFlag(var, "python", d):
339         return 0
340
341     export = getVarFlag(var, "export", d)
342     unexport = getVarFlag(var, "unexport", d)
343     func = getVarFlag(var, "func", d)
344     if not all and not export and not unexport and not func:
345         return 0
346
347     try:
348         if all:
349             oval = getVar(var, d, 0)
350         val = getVar(var, d, 1)
351     except KeyboardInterrupt:
352         raise
353     except:
354         excname = str(sys.exc_info()[0])
355         if excname == "bb.build.FuncFailed":
356             raise
357         o.write('# expansion of %s threw %s\n' % (var, excname))
358         return 0
359
360     if all:
361         o.write('# %s=%s\n' % (var, oval))
362
363     if type(val) is not types.StringType:
364         return 0
365
366     if getVarFlag(var, 'matchesenv', d):
367         return 0
368
369     if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
370         return 0
371
372     varExpanded = expand(var, d)
373
374     if unexport:
375         o.write('unset %s\n' % varExpanded)
376         return 1
377
378     val.rstrip()
379     if not val:
380         return 0
381
382     if func:
383         # NOTE: should probably check for unbalanced {} within the var
384         o.write("%s() {\n%s\n}\n" % (varExpanded, val))
385         return 1
386
387     if export:
388         o.write('export ')
389
390     # if we're going to output this within doublequotes,
391     # to a shell, we need to escape the quotes in the var
392     alter = re.sub('"', '\\"', val.strip())
393     o.write('%s="%s"\n' % (varExpanded, alter))
394     return 1
395
396
397 def emit_env(o=sys.__stdout__, d = init(), all=False):
398     """Emits all items in the data store in a format such that it can be sourced by a shell."""
399
400     env = keys(d)
401
402     for e in env:
403         if getVarFlag(e, "func", d):
404             continue
405         emit_var(e, o, d, all) and o.write('\n')
406
407     for e in env:
408         if not getVarFlag(e, "func", d):
409             continue
410         emit_var(e, o, d) and o.write('\n')
411
412 def update_data(d):
413     """Modifies the environment vars according to local overrides and commands.
414     Examples:
415         Appending to a variable:
416         >>> d = init()
417         >>> setVar('TEST', 'this is a', d)
418         >>> setVar('TEST_append', ' test', d)
419         >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
420         >>> update_data(d)
421         >>> print getVar('TEST', d)
422         this is a test of the emergency broadcast system.
423
424         Prepending to a variable:
425         >>> setVar('TEST', 'virtual/libc', d)
426         >>> setVar('TEST_prepend', 'virtual/tmake ', d)
427         >>> setVar('TEST_prepend', 'virtual/patcher ', d)
428         >>> update_data(d)
429         >>> print getVar('TEST', d)
430         virtual/patcher virtual/tmake virtual/libc
431
432         Overrides:
433         >>> setVar('TEST_arm', 'target', d)
434         >>> setVar('TEST_ramses', 'machine', d)
435         >>> setVar('TEST_local', 'local', d)
436         >>> setVar('OVERRIDES', 'arm', d)
437
438         >>> setVar('TEST', 'original', d)
439         >>> update_data(d)
440         >>> print getVar('TEST', d)
441         target
442
443         >>> setVar('OVERRIDES', 'arm:ramses:local', d)
444         >>> setVar('TEST', 'original', d)
445         >>> update_data(d)
446         >>> print getVar('TEST', d)
447         local
448
449         CopyMonster:
450         >>> e = d.createCopy()
451         >>> setVar('TEST_foo', 'foo', e)
452         >>> update_data(e)
453         >>> print getVar('TEST', e)
454         local
455
456         >>> setVar('OVERRIDES', 'arm:ramses:local:foo', e)
457         >>> update_data(e)
458         >>> print getVar('TEST', e)
459         foo
460
461         >>> f = d.createCopy()
462         >>> setVar('TEST_moo', 'something', f)
463         >>> setVar('OVERRIDES', 'moo:arm:ramses:local:foo', e)
464         >>> update_data(e)
465         >>> print getVar('TEST', e)
466         foo
467
468
469         >>> h = init()
470         >>> setVar('SRC_URI', 'file://append.foo;patch=1 ', h)
471         >>> g = h.createCopy()
472         >>> setVar('SRC_URI_append_arm', 'file://other.foo;patch=1', g)
473         >>> setVar('OVERRIDES', 'arm:moo', g)
474         >>> update_data(g)
475         >>> print getVar('SRC_URI', g)
476         file://append.foo;patch=1 file://other.foo;patch=1
477
478     """
479     bb.msg.debug(2, bb.msg.domain.Data, "update_data()")
480
481     # now ask the cookie monster for help
482     #print "Cookie Monster"
483     #print "Append/Prepend %s" % d._special_values
484     #print "Overrides      %s" % d._seen_overrides
485
486     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
487
488     #
489     # Well let us see what breaks here. We used to iterate
490     # over each variable and apply the override and then
491     # do the line expanding.
492     # If we have bad luck - which we will have - the keys
493     # where in some order that is so important for this
494     # method which we don't have anymore.
495     # Anyway we will fix that and write test cases this
496     # time.
497
498     #
499     # First we apply all overrides
500     # Then  we will handle _append and _prepend
501     #
502
503     for o in overrides:
504         # calculate '_'+override
505         l    = len(o)+1
506
507         # see if one should even try
508         if not d._seen_overrides.has_key(o):
509             continue
510
511         vars = d._seen_overrides[o]
512         for var in vars:
513             name = var[:-l]
514             try:
515                 d[name] = d[var]
516             except:
517                 bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar")
518
519     # now on to the appends and prepends
520     if d._special_values.has_key('_append'):
521         appends = d._special_values['_append'] or []
522         for append in appends:
523             for (a, o) in getVarFlag(append, '_append', d) or []:
524                 # maybe the OVERRIDE was not yet added so keep the append
525                 if (o and o in overrides) or not o:
526                     delVarFlag(append, '_append', d)
527                 if o and not o in overrides:
528                     continue
529
530                 sval = getVar(append,d) or ""
531                 sval+=a
532                 setVar(append, sval, d)
533
534
535     if d._special_values.has_key('_prepend'):
536         prepends = d._special_values['_prepend'] or []
537
538         for prepend in prepends:
539             for (a, o) in getVarFlag(prepend, '_prepend', d) or []:
540                 # maybe the OVERRIDE was not yet added so keep the prepend
541                 if (o and o in overrides) or not o:
542                     delVarFlag(prepend, '_prepend', d)
543                 if o and not o in overrides:
544                     continue
545
546                 sval = a + (getVar(prepend,d) or "")
547                 setVar(prepend, sval, d)
548
549
550 def inherits_class(klass, d):
551     val = getVar('__inherit_cache', d) or []
552     if os.path.join('classes', '%s.bbclass' % klass) in val:
553         return True
554     return False
555
556 def _test():
557     """Start a doctest run on this module"""
558     import doctest
559     from bb import data
560     doctest.testmod(data)
561
562 if __name__ == "__main__":
563     _test()