bitbake/lib/bb/cache.py:
[bitbake.git] / 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 The expandData and update_data are the most expensive
11 operations. At night the cookie monster came by and
12 suggested 'give me cookies on setting the variables and
13 things will work out'. Taking this suggestion into account
14 applying the skills from the not yet passed 'Entwurf und
15 Analyse von Algorithmen' lecture and the cookie 
16 monster seems to be right. We will track setVar more carefully
17 to have faster update_data and expandKeys operations.
18
19 This is a treade-off between speed and memory again but
20 the speed is more critical here.
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 it under
26 the terms of the GNU General Public License as published by the Free Software
27 Foundation; either version 2 of the License, or (at your option) any later
28 version.
29
30 This program is distributed in the hope that it will be useful, but WITHOUT
31 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License along with
35 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
36 Place, Suite 330, Boston, MA 02111-1307 USA. 
37
38 Based on functions from the base bb module, Copyright 2003 Holger Schurig
39 """
40
41 import sys, os, re, time, types
42 if sys.argv[0][-5:] == "pydoc":
43     path = os.path.dirname(os.path.dirname(sys.argv[1]))
44 else:
45     path = os.path.dirname(os.path.dirname(sys.argv[0]))
46 sys.path.insert(0,path)
47
48 from bb import note, debug, data_smart
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         ekey = expand(key, readdata)
274         if key == ekey:
275             continue
276         val = getVar(key, alterdata)
277         if val is None:
278             continue
279 #        import copy
280 #        setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
281         setVar(ekey, val, alterdata)
282
283         for i in ('_append', '_prepend'):
284             dest = getVarFlag(ekey, i, alterdata) or []
285             src = getVarFlag(key, i, readdata) or []
286             dest.extend(src)
287             setVarFlag(ekey, i, dest, alterdata)
288
289         delVar(key, alterdata)
290
291 def expandData(alterdata, readdata = None):
292     """For each variable in alterdata, expand it, and update the var contents.
293        Replacements use data from readdata.
294
295     Example:
296         >>> a=init()
297         >>> b=init()
298         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
299         >>> setVar("DL_DIR", "/path/to/whatever", b)
300         >>> expandData(a, b)
301         >>> print getVar("dlmsg", a)
302         dl_dir is /path/to/whatever
303        """
304     if readdata == None:
305         readdata = alterdata
306
307     for key in keys(alterdata):
308         val = getVar(key, alterdata)
309         if type(val) is not types.StringType:
310             continue
311         expanded = expand(val, readdata)
312 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
313         if val != expanded:
314             setVar(key, expanded, alterdata)
315
316 import os
317
318 def inheritFromOS(d):
319     """Inherit variables from the environment."""
320 #   fakeroot needs to be able to set these
321     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
322     for s in os.environ.keys():
323         if not s in non_inherit_vars:
324             try:
325                 setVar(s, os.environ[s], d)
326                 setVarFlag(s, 'matchesenv', '1', d)
327             except TypeError:
328                 pass
329
330 import sys
331
332 def emit_var(var, o=sys.__stdout__, d = init(), all=False):
333     """Emit a variable to be sourced by a shell."""
334     if getVarFlag(var, "python", d):
335         return 0
336
337     try:
338         if all:
339             oval = getVar(var, d, 0)
340         val = getVar(var, d, 1)
341     except KeyboardInterrupt:
342         raise
343     except:
344         excname = str(sys.exc_info()[0])
345         if excname == "bb.build.FuncFailed":
346             raise
347         o.write('# expansion of %s threw %s\n' % (var, excname))
348         return 0
349
350     if all:
351         o.write('# %s=%s\n' % (var, oval))
352
353     if type(val) is not types.StringType:
354         return 0
355
356     if getVarFlag(var, 'matchesenv', d):
357         return 0
358
359     if (var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1) and not all:
360         return 0
361
362     val.rstrip()
363     if not val:
364         return 0
365
366     if getVarFlag(var, "func", d):
367 #       NOTE: should probably check for unbalanced {} within the var
368         o.write("%s() {\n%s\n}\n" % (var, val))
369     else:
370         if getVarFlag(var, "export", d):
371             o.write('export ')
372         else:
373             if not all:
374                 return 0
375 #       if we're going to output this within doublequotes,
376 #       to a shell, we need to escape the quotes in the var
377         alter = re.sub('"', '\\"', val.strip())
378         o.write('%s="%s"\n' % (var, alter))
379     return 1
380
381
382 def emit_env(o=sys.__stdout__, d = init(), all=False):
383     """Emits all items in the data store in a format such that it can be sourced by a shell."""
384
385     env = keys(d)
386
387     for e in env:
388         if getVarFlag(e, "func", d):
389             continue
390         emit_var(e, o, d, all) and o.write('\n')
391
392     for e in env:
393         if not getVarFlag(e, "func", d):
394             continue
395         emit_var(e, o, d) and o.write('\n')
396
397 def update_data(d):
398     """Modifies the environment vars according to local overrides and commands.
399     Examples:
400         Appending to a variable:
401         >>> d = init()
402         >>> setVar('TEST', 'this is a', d)
403         >>> setVar('TEST_append', ' test', d)
404         >>> setVar('TEST_append', ' of the emergency broadcast system.', d)
405         >>> update_data(d)
406         >>> print getVar('TEST', d)
407         this is a test of the emergency broadcast system.
408
409         Prepending to a variable:
410         >>> setVar('TEST', 'virtual/libc', d)
411         >>> setVar('TEST_prepend', 'virtual/tmake ', d)
412         >>> setVar('TEST_prepend', 'virtual/patcher ', d)
413         >>> update_data(d)
414         >>> print getVar('TEST', d)
415         virtual/patcher virtual/tmake virtual/libc
416
417         Overrides:
418         >>> setVar('TEST_arm', 'target', d)
419         >>> setVar('TEST_ramses', 'machine', d)
420         >>> setVar('TEST_local', 'local', d)
421         >>> setVar('OVERRIDES', 'arm', d)
422
423         >>> setVar('TEST', 'original', d)
424         >>> update_data(d)
425         >>> print getVar('TEST', d)
426         target
427
428         >>> setVar('OVERRIDES', 'arm:ramses:local', d)
429         >>> setVar('TEST', 'original', d)
430         >>> update_data(d)
431         >>> print getVar('TEST', d)
432         local
433     """
434     debug(2, "update_data()")
435
436     # now ask the cookie monster for help
437     #print "Cookie Monster"
438     #print "Append/Prepend %s" % d._special_values
439     #print "Overrides      %s" % d._seen_overrides
440
441     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
442
443     #
444     # Well let us see what breaks here. We used to iterate
445     # over each variable and apply the override and then
446     # do the line expanding.
447     # If we have bad luck - which we will have - the keys
448     # where in some order that is so important for this
449     # method which we don't have anymore.
450     # Anyway we will fix that and write test cases this
451     # time.
452
453     #
454     # First we apply all overrides
455     # Then  we will handle _append and _prepend
456     #
457
458     for o in overrides:
459         # calculate '_'+override
460         l    = len(o)+1
461
462         # see if one should even try
463         if not o in d._seen_overrides:
464             continue
465
466         vars = d._seen_overrides[o]
467         for var in vars:
468             name = var[:-l]
469             try:
470                 d[name] = d[var]
471             except:
472                 note ("Untracked delVar")
473
474     # now on to the appends and prepends
475     if '_append' in d._special_values:
476         appends = d._special_values['_append'] or []
477         for append in appends:
478             for (a, o) in getVarFlag(append, '_append', d) or []:
479                 # maybe the OVERRIDE was not yet added so keep the append
480                 if (o and o in overrides) or not o:
481                     delVarFlag(append, '_append', d)
482                 if o and not o in overrides:
483                     continue
484
485                 sval = getVar(append,d) or ""
486                 sval+=a
487                 setVar(append, sval, d)
488
489
490     if '_prepend' in d._special_values:
491         prepends = d._special_values['_prepend'] or []
492
493         for prepend in prepends:
494             for (a, o) in getVarFlag(prepend, '_prepend', d) or []:
495                 # maybe the OVERRIDE was not yet added so keep the prepend
496                 if (o and o in overrides) or not o:
497                     delVarFlag(prepend, '_prepend', d)
498                 if o and not o in overrides:
499                     continue
500
501                 sval = a + (getVar(prepend,d) or "")
502                 setVar(prepend, sval, d)
503
504
505 def inherits_class(klass, d):
506     val = getVar('__inherit_cache', d) or ""
507     if os.path.join('classes', '%s.bbclass' % klass) in val.split():
508         return True
509     return False
510
511 def _test():
512     """Start a doctest run on this module"""
513     import doctest
514     from bb import data
515     doctest.testmod(data)
516
517 if __name__ == "__main__":
518     _test()