Add persitent data store from trunk, sync the fetcher changes to use the persistent...
[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 def delVar(var, d):
100     """Removes a variable from the data set
101
102     Example:
103         >>> d = init()
104         >>> setVar('TEST', 'testcontents', d)
105         >>> print getVar('TEST', d)
106         testcontents
107         >>> delVar('TEST', d)
108         >>> print getVar('TEST', d)
109         None
110     """
111     d.delVar(var)
112
113 def setVarFlag(var, flag, flagvalue, d):
114     """Set a flag for a given variable to a given value
115
116     Example:
117         >>> d = init()
118         >>> setVarFlag('TEST', 'python', 1, d)
119         >>> print getVarFlag('TEST', 'python', d)
120         1
121     """
122     d.setVarFlag(var,flag,flagvalue)
123
124 def getVarFlag(var, flag, d):
125     """Gets given flag from given var
126
127     Example:
128         >>> d = init()
129         >>> setVarFlag('TEST', 'python', 1, d)
130         >>> print getVarFlag('TEST', 'python', d)
131         1
132     """
133     return d.getVarFlag(var,flag)
134
135 def delVarFlag(var, flag, d):
136     """Removes a given flag from the variable's flags
137
138     Example:
139         >>> d = init()
140         >>> setVarFlag('TEST', 'testflag', 1, d)
141         >>> print getVarFlag('TEST', 'testflag', d)
142         1
143         >>> delVarFlag('TEST', 'testflag', d)
144         >>> print getVarFlag('TEST', 'testflag', d)
145         None
146
147     """
148     d.delVarFlag(var,flag)
149
150 def setVarFlags(var, flags, d):
151     """Set the flags for a given variable
152
153     Note:
154         setVarFlags will not clear previous
155         flags. Think of this method as
156         addVarFlags
157
158     Example:
159         >>> d = init()
160         >>> myflags = {}
161         >>> myflags['test'] = 'blah'
162         >>> setVarFlags('TEST', myflags, d)
163         >>> print getVarFlag('TEST', 'test', d)
164         blah
165     """
166     d.setVarFlags(var,flags)
167
168 def getVarFlags(var, d):
169     """Gets a variable's flags
170
171     Example:
172         >>> d = init()
173         >>> setVarFlag('TEST', 'test', 'blah', d)
174         >>> print getVarFlags('TEST', d)['test']
175         blah
176     """
177     return d.getVarFlags(var)
178
179 def delVarFlags(var, d):
180     """Removes a variable's flags
181
182     Example:
183         >>> data = init()
184         >>> setVarFlag('TEST', 'testflag', 1, data)
185         >>> print getVarFlag('TEST', 'testflag', data)
186         1
187         >>> delVarFlags('TEST', data)
188         >>> print getVarFlags('TEST', data)
189         None
190
191     """
192     d.delVarFlags(var)
193
194 def keys(d):
195     """Return a list of keys in d
196
197     Example:
198         >>> d = init()
199         >>> setVar('TEST',  1, d)
200         >>> setVar('MOO' ,  2, d)
201         >>> setVarFlag('TEST', 'test', 1, d)
202         >>> keys(d)
203         ['TEST', 'MOO']
204     """
205     return d.keys()
206
207 def getData(d):
208     """Returns the data object used"""
209     return d
210
211 def setData(newData, d):
212     """Sets the data object to the supplied value"""
213     d = newData
214
215
216 ##
217 ## Cookie Monsters' query functions
218 ##
219 def _get_override_vars(d, override):
220     """
221     Internal!!!
222
223     Get the Names of Variables that have a specific
224     override. This function returns a iterable
225     Set or an empty list
226     """
227     return []
228
229 def _get_var_flags_triple(d):
230     """
231     Internal!!!
232
233     """
234     return []
235
236 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
237 __expand_python_regexp__ = re.compile(r"\${@.+?}")
238
239 def expand(s, d, varname = None):
240     """Variable expansion using the data store.
241
242     Example:
243         Standard expansion:
244         >>> d = init()
245         >>> setVar('A', 'sshd', d)
246         >>> print expand('/usr/bin/${A}', d)
247         /usr/bin/sshd
248
249         Python expansion:
250         >>> d = init()
251         >>> print expand('result: ${@37 * 72}', d)
252         result: 2664
253
254         Shell expansion:
255         >>> d = init()
256         >>> print expand('${TARGET_MOO}', d)
257         ${TARGET_MOO}
258         >>> setVar('TARGET_MOO', 'yupp', d)
259         >>> print expand('${TARGET_MOO}',d)
260         yupp
261         >>> setVar('SRC_URI', 'http://somebug.${TARGET_MOO}', d)
262         >>> delVar('TARGET_MOO', d)
263         >>> print expand('${SRC_URI}', d)
264         http://somebug.${TARGET_MOO}
265     """
266     return d.expand(s, varname)
267
268 def expandKeys(alterdata, readdata = None):
269     if readdata == None:
270         readdata = alterdata
271
272     for key in keys(alterdata):
273         if not '${' in key:
274             continue
275
276         ekey = expand(key, readdata)
277         if key == ekey:
278             continue
279         val = getVar(key, alterdata)
280         if val is None:
281             continue
282 #        import copy
283 #        setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
284         setVar(ekey, val, alterdata)
285
286         for i in ('_append', '_prepend'):
287             dest = getVarFlag(ekey, i, alterdata) or []
288             src = getVarFlag(key, i, readdata) or []
289             dest.extend(src)
290             setVarFlag(ekey, i, dest, alterdata)
291
292         delVar(key, alterdata)
293
294 def expandData(alterdata, readdata = None):
295     """For each variable in alterdata, expand it, and update the var contents.
296        Replacements use data from readdata.
297
298     Example:
299         >>> a=init()
300         >>> b=init()
301         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
302         >>> setVar("DL_DIR", "/path/to/whatever", b)
303         >>> expandData(a, b)
304         >>> print getVar("dlmsg", a)
305         dl_dir is /path/to/whatever
306        """
307     if readdata == None:
308         readdata = alterdata
309
310     for key in keys(alterdata):
311         val = getVar(key, alterdata)
312         if type(val) is not types.StringType:
313             continue
314         expanded = expand(val, readdata)
315 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
316         if val != expanded:
317             setVar(key, expanded, alterdata)
318
319 import os
320
321 def inheritFromOS(d):
322     """Inherit variables from the environment."""
323 #   fakeroot needs to be able to set these
324     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
325     for s in os.environ.keys():
326         if not s in non_inherit_vars:
327             try:
328                 setVar(s, os.environ[s], d)
329                 setVarFlag(s, 'matchesenv', '1', d)
330             except TypeError:
331                 pass
332
333 import sys
334
335 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
336     """Emit a variable to be sourced by a shell."""
337     if getVarFlag(var, "python", d):
338         return 0
339
340     try:
341         if all:
342             oval = getVar(var, d, 0)
343         val = getVar(var, d, 1)
344     except KeyboardInterrupt:
345         raise
346     except:
347         excname = str(sys.exc_info()[0])
348         if excname == "bb.build.FuncFailed":
349             raise
350         o.write('# expansion of %s threw %s\n' % (var, excname))
351         return 0
352
353     if all:
354         o.write('# %s=%s\n' % (var, oval))
355
356     if type(val) is not types.StringType:
357         return 0
358
359     if getVarFlag(var, 'matchesenv', d):
360         return 0
361
362     if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
363         return 0
364
365     val.rstrip()
366     if not val:
367         return 0
368         
369     varExpanded = expand(var, d)
370
371     if getVarFlag(var, "func", d):
372 #       NOTE: should probably check for unbalanced {} within the var
373         o.write("%s() {\n%s\n}\n" % (varExpanded, val))
374     else:
375         if getVarFlag(var, "unexport", d):
376             o.write('unset %s\n' % varExpanded)
377             return 1
378         if getVarFlag(var, "export", d):
379             o.write('export ')
380         else:
381             if not all:
382                 return 0
383 #       if we're going to output this within doublequotes,
384 #       to a shell, we need to escape the quotes in the var
385         alter = re.sub('"', '\\"', val.strip())
386         o.write('%s="%s"\n' % (varExpanded, alter))
387     return 1
388
389
390 def emit_env(o=sys.__stdout__, d = init(), all=False):
391     """Emits all items in the data store in a format such that it can be sourced by a shell."""
392
393     env = keys(d)
394
395     for e in env:
396         if getVarFlag(e, "func", d):
397             continue
398         emit_var(e, o, d, all) and o.write('\n')
399
400     for e in env:
401         if not getVarFlag(e, "func", d):
402             continue
403         emit_var(e, o, d) and o.write('\n')
404
405 def update_data(d):
406     """Modifies the environment vars according to local overrides and commands.
407     Examples:
408         Appending to a variable:
409         >>> d = init()
410         >>> setVar('TEST', 'this is a', d)
411         >>> setVar('TEST_append', ' test', d)
412         >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
413         >>> update_data(d)
414         >>> print getVar('TEST', d)
415         this is a test of the emergency broadcast system.
416
417         Prepending to a variable:
418         >>> setVar('TEST', 'virtual/libc', d)
419         >>> setVar('TEST_prepend', 'virtual/tmake ', d)
420         >>> setVar('TEST_prepend', 'virtual/patcher ', d)
421         >>> update_data(d)
422         >>> print getVar('TEST', d)
423         virtual/patcher virtual/tmake virtual/libc
424
425         Overrides:
426         >>> setVar('TEST_arm', 'target', d)
427         >>> setVar('TEST_ramses', 'machine', d)
428         >>> setVar('TEST_local', 'local', d)
429         >>> setVar('OVERRIDES', 'arm', d)
430
431         >>> setVar('TEST', 'original', d)
432         >>> update_data(d)
433         >>> print getVar('TEST', d)
434         target
435
436         >>> setVar('OVERRIDES', 'arm:ramses:local', d)
437         >>> setVar('TEST', 'original', d)
438         >>> update_data(d)
439         >>> print getVar('TEST', d)
440         local
441
442         CopyMonster:
443         >>> e = d.createCopy()
444         >>> setVar('TEST_foo', 'foo', e)
445         >>> update_data(e)
446         >>> print getVar('TEST', e)
447         local
448
449         >>> setVar('OVERRIDES', 'arm:ramses:local:foo', e)
450         >>> update_data(e)
451         >>> print getVar('TEST', e)
452         foo
453
454         >>> f = d.createCopy()
455         >>> setVar('TEST_moo', 'something', f)
456         >>> setVar('OVERRIDES', 'moo:arm:ramses:local:foo', e)
457         >>> update_data(e)
458         >>> print getVar('TEST', e)
459         foo
460
461
462         >>> h = init()
463         >>> setVar('SRC_URI', 'file://append.foo;patch=1 ', h)
464         >>> g = h.createCopy()
465         >>> setVar('SRC_URI_append_arm', 'file://other.foo;patch=1', g)
466         >>> setVar('OVERRIDES', 'arm:moo', g)
467         >>> update_data(g)
468         >>> print getVar('SRC_URI', g)
469         file://append.foo;patch=1 file://other.foo;patch=1
470
471     """
472     bb.msg.debug(2, bb.msg.domain.Data, "update_data()")
473
474     # now ask the cookie monster for help
475     #print "Cookie Monster"
476     #print "Append/Prepend %s" % d._special_values
477     #print "Overrides      %s" % d._seen_overrides
478
479     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
480
481     #
482     # Well let us see what breaks here. We used to iterate
483     # over each variable and apply the override and then
484     # do the line expanding.
485     # If we have bad luck - which we will have - the keys
486     # where in some order that is so important for this
487     # method which we don't have anymore.
488     # Anyway we will fix that and write test cases this
489     # time.
490
491     #
492     # First we apply all overrides
493     # Then  we will handle _append and _prepend
494     #
495
496     for o in overrides:
497         # calculate '_'+override
498         l    = len(o)+1
499
500         # see if one should even try
501         if not d._seen_overrides.has_key(o):
502             continue
503
504         vars = d._seen_overrides[o]
505         for var in vars:
506             name = var[:-l]
507             try:
508                 d[name] = d[var]
509             except:
510                 bb.msg.note(1, bb.msg.domain.Data, "Untracked delVar")
511
512     # now on to the appends and prepends
513     if d._special_values.has_key('_append'):
514         appends = d._special_values['_append'] or []
515         for append in appends:
516             for (a, o) in getVarFlag(append, '_append', d) or []:
517                 # maybe the OVERRIDE was not yet added so keep the append
518                 if (o and o in overrides) or not o:
519                     delVarFlag(append, '_append', d)
520                 if o and not o in overrides:
521                     continue
522
523                 sval = getVar(append,d) or ""
524                 sval+=a
525                 setVar(append, sval, d)
526
527
528     if d._special_values.has_key('_prepend'):
529         prepends = d._special_values['_prepend'] or []
530
531         for prepend in prepends:
532             for (a, o) in getVarFlag(prepend, '_prepend', d) or []:
533                 # maybe the OVERRIDE was not yet added so keep the prepend
534                 if (o and o in overrides) or not o:
535                     delVarFlag(prepend, '_prepend', d)
536                 if o and not o in overrides:
537                     continue
538
539                 sval = a + (getVar(prepend,d) or "")
540                 setVar(prepend, sval, d)
541
542
543 def inherits_class(klass, d):
544     val = getVar('__inherit_cache', d) or []
545     if os.path.join('classes', '%s.bbclass' % klass) in val:
546         return True
547     return False
548
549 def _test():
550     """Start a doctest run on this module"""
551     import doctest
552     from bb import data
553     doctest.testmod(data)
554
555 if __name__ == "__main__":
556     _test()