bin/bitbake: Add better environmental variable handling. By default it will now only...
[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     todolist = {}
286     for key in keys(alterdata):
287         if not '${' in key:
288             continue
289
290         ekey = expand(key, readdata)
291         if key == ekey:
292             continue
293         todolist[key] = ekey
294
295     # These two for loops are split for performance to maximise the 
296     # usefulness of the expand cache
297
298     for key in todolist:
299         ekey = todolist[key]
300         renameVar(key, ekey, alterdata)
301
302 def expandData(alterdata, readdata = None):
303     """For each variable in alterdata, expand it, and update the var contents.
304        Replacements use data from readdata.
305
306     Example:
307         >>> a=init()
308         >>> b=init()
309         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
310         >>> setVar("DL_DIR", "/path/to/whatever", b)
311         >>> expandData(a, b)
312         >>> print getVar("dlmsg", a)
313         dl_dir is /path/to/whatever
314        """
315     if readdata == None:
316         readdata = alterdata
317
318     for key in keys(alterdata):
319         val = getVar(key, alterdata)
320         if type(val) is not types.StringType:
321             continue
322         expanded = expand(val, readdata)
323 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
324         if val != expanded:
325             setVar(key, expanded, alterdata)
326
327 def inheritFromOS(d):
328     """Inherit variables from the environment."""
329     for s in os.environ.keys():
330         try:
331             setVar(s, os.environ[s], d)
332         except TypeError:
333             pass
334         os.unsetenv(s)
335         del os.environ[s]
336
337 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
338     """Emit a variable to be sourced by a shell."""
339     if getVarFlag(var, "python", d):
340         return 0
341
342     export = getVarFlag(var, "export", d)
343     unexport = getVarFlag(var, "unexport", d)
344     func = getVarFlag(var, "func", d)
345     if not all and not export and not unexport and not func:
346         return 0
347
348     try:
349         if all:
350             oval = getVar(var, d, 0)
351         val = getVar(var, d, 1)
352     except KeyboardInterrupt:
353         raise
354     except:
355         excname = str(sys.exc_info()[0])
356         if excname == "bb.build.FuncFailed":
357             raise
358         o.write('# expansion of %s threw %s\n' % (var, excname))
359         return 0
360
361     if all:
362         o.write('# %s=%s\n' % (var, oval))
363
364     if type(val) is not types.StringType:
365         return 0
366
367     if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
368         return 0
369
370     varExpanded = expand(var, d)
371
372     if unexport:
373         o.write('unset %s\n' % varExpanded)
374         return 1
375
376     val.rstrip()
377     if not val:
378         return 0
379
380     if func:
381         # NOTE: should probably check for unbalanced {} within the var
382         o.write("%s() {\n%s\n}\n" % (varExpanded, val))
383         return 1
384
385     if export:
386         o.write('export ')
387
388     # if we're going to output this within doublequotes,
389     # to a shell, we need to escape the quotes in the var
390     alter = re.sub('"', '\\"', val.strip())
391     o.write('%s="%s"\n' % (varExpanded, alter))
392     return 1
393
394
395 def emit_env(o=sys.__stdout__, d = init(), all=False):
396     """Emits all items in the data store in a format such that it can be sourced by a shell."""
397
398     env = keys(d)
399
400     for e in env:
401         if getVarFlag(e, "func", d):
402             continue
403         emit_var(e, o, d, all) and o.write('\n')
404
405     for e in env:
406         if not getVarFlag(e, "func", d):
407             continue
408         emit_var(e, o, d) and o.write('\n')
409
410 def update_data(d):
411     """Modifies the environment vars according to local overrides and commands.
412     Examples:
413         Appending to a variable:
414         >>> d = init()
415         >>> setVar('TEST', 'this is a', d)
416         >>> setVar('TEST_append', ' test', d)
417         >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
418         >>> update_data(d)
419         >>> print getVar('TEST', d)
420         this is a test of the emergency broadcast system.
421
422         Prepending to a variable:
423         >>> setVar('TEST', 'virtual/libc', d)
424         >>> setVar('TEST_prepend', 'virtual/tmake ', d)
425         >>> setVar('TEST_prepend', 'virtual/patcher ', d)
426         >>> update_data(d)
427         >>> print getVar('TEST', d)
428         virtual/patcher virtual/tmake virtual/libc
429
430         Overrides:
431         >>> setVar('TEST_arm', 'target', d)
432         >>> setVar('TEST_ramses', 'machine', d)
433         >>> setVar('TEST_local', 'local', d)
434         >>> setVar('OVERRIDES', 'arm', d)
435
436         >>> setVar('TEST', 'original', d)
437         >>> update_data(d)
438         >>> print getVar('TEST', d)
439         target
440
441         >>> setVar('OVERRIDES', 'arm:ramses:local', d)
442         >>> setVar('TEST', 'original', d)
443         >>> update_data(d)
444         >>> print getVar('TEST', d)
445         local
446
447         CopyMonster:
448         >>> e = d.createCopy()
449         >>> setVar('TEST_foo', 'foo', e)
450         >>> update_data(e)
451         >>> print getVar('TEST', e)
452         local
453
454         >>> setVar('OVERRIDES', 'arm:ramses:local:foo', e)
455         >>> update_data(e)
456         >>> print getVar('TEST', e)
457         foo
458
459         >>> f = d.createCopy()
460         >>> setVar('TEST_moo', 'something', f)
461         >>> setVar('OVERRIDES', 'moo:arm:ramses:local:foo', e)
462         >>> update_data(e)
463         >>> print getVar('TEST', e)
464         foo
465
466
467         >>> h = init()
468         >>> setVar('SRC_URI', 'file://append.foo;patch=1 ', h)
469         >>> g = h.createCopy()
470         >>> setVar('SRC_URI_append_arm', 'file://other.foo;patch=1', g)
471         >>> setVar('OVERRIDES', 'arm:moo', g)
472         >>> update_data(g)
473         >>> print getVar('SRC_URI', g)
474         file://append.foo;patch=1 file://other.foo;patch=1
475
476     """
477     bb.msg.debug(2, bb.msg.domain.Data, "update_data()")
478
479     # now ask the cookie monster for help
480     #print "Cookie Monster"
481     #print "Append/Prepend %s" % d._special_values
482     #print "Overrides      %s" % d._seen_overrides
483
484     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
485
486     #
487     # Well let us see what breaks here. We used to iterate
488     # over each variable and apply the override and then
489     # do the line expanding.
490     # If we have bad luck - which we will have - the keys
491     # where in some order that is so important for this
492     # method which we don't have anymore.
493     # Anyway we will fix that and write test cases this
494     # time.
495
496     #
497     # First we apply all overrides
498     # Then  we will handle _append and _prepend
499     #
500
501     for o in overrides:
502         # calculate '_'+override
503         l    = len(o)+1
504
505         # see if one should even try
506         if not d._seen_overrides.has_key(o):
507             continue
508
509         vars = d._seen_overrides[o]
510         for var in vars:
511             name = var[:-l]
512             try:
513                 d[name] = d[var]
514             except:
515                 bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar")
516
517     # now on to the appends and prepends
518     if d._special_values.has_key('_append'):
519         appends = d._special_values['_append'] or []
520         for append in appends:
521             for (a, o) in getVarFlag(append, '_append', d) or []:
522                 # maybe the OVERRIDE was not yet added so keep the append
523                 if (o and o in overrides) or not o:
524                     delVarFlag(append, '_append', d)
525                 if o and not o in overrides:
526                     continue
527
528                 sval = getVar(append,d) or ""
529                 sval+=a
530                 setVar(append, sval, d)
531
532
533     if d._special_values.has_key('_prepend'):
534         prepends = d._special_values['_prepend'] or []
535
536         for prepend in prepends:
537             for (a, o) in getVarFlag(prepend, '_prepend', d) or []:
538                 # maybe the OVERRIDE was not yet added so keep the prepend
539                 if (o and o in overrides) or not o:
540                     delVarFlag(prepend, '_prepend', d)
541                 if o and not o in overrides:
542                     continue
543
544                 sval = a + (getVar(prepend,d) or "")
545                 setVar(prepend, sval, d)
546
547
548 def inherits_class(klass, d):
549     val = getVar('__inherit_cache', d) or []
550     if os.path.join('classes', '%s.bbclass' % klass) in val:
551         return True
552     return False
553
554 def _test():
555     """Start a doctest run on this module"""
556     import doctest
557     from bb import data
558     doctest.testmod(data)
559
560 if __name__ == "__main__":
561     _test()