Initial import.
[vuplus_bitbake] / build / 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
12 This program is free software; you can redistribute it and/or modify it under
13 the terms of the GNU General Public License as published by the Free Software
14 Foundation; either version 2 of the License, or (at your option) any later
15 version.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23 Place, Suite 330, Boston, MA 02111-1307 USA. 
24
25 Based on functions from the base bb module, Copyright 2003 Holger Schurig
26 """
27
28 import sys, os, re, time, types
29 if sys.argv[0][-5:] == "pydoc":
30     path = os.path.dirname(os.path.dirname(sys.argv[1]))
31 else:
32     path = os.path.dirname(os.path.dirname(sys.argv[0]))
33 sys.path.append(path)
34
35 from bb import note, debug
36
37 def init():
38     return {}
39
40 _data = init()
41
42 def initVar(var, d = _data):
43     """Non-destructive var init for data structure"""
44     if not var in d:
45         d[var] = {}
46
47     if not "flags" in d[var]:
48         d[var]["flags"] = {}
49
50 __setvar_regexp__ = {}
51 __setvar_regexp__["_append"]  = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_append")
52 __setvar_regexp__["_prepend"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_prepend")
53 __setvar_regexp__["_delete"]  = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_delete")
54
55 def setVar(var, value, d = _data):
56     """Set a variable to a given value
57
58     Example:
59         >>> setVar('TEST', 'testcontents')
60         >>> print getVar('TEST')
61         testcontents
62     """
63     for v in ["_append", "_prepend", "_delete"]:
64         match = __setvar_regexp__[v].match(var)
65         if match:
66             base = match.group('base')
67             override = match.group('add')
68             l = getVarFlag(base, v, d) or []
69             if override == 'delete':
70                 if l.count([value, None]):
71                     del l[l.index([value, None])]
72             l.append([value, override])
73             setVarFlag(base, v, l, d)
74             return
75
76     if not var in d:
77         initVar(var, d)
78     if getVarFlag(var, 'matchesenv', d):
79         delVarFlag(var, 'matchesenv', d)
80         setVarFlag(var, 'export', 1, d)
81     d[var]["content"] = value
82
83 def getVar(var, d = _data, exp = 0):
84     """Gets the value of a variable
85
86     Example:
87         >>> setVar('TEST', 'testcontents')
88         >>> print getVar('TEST')
89         testcontents
90     """
91     if not var in d or not "content" in d[var]:
92         return None
93     if exp:
94         return expand(d[var]["content"], d, var)
95     return d[var]["content"]
96
97 def delVar(var, d = _data):
98     """Removes a variable from the data set
99
100     Example:
101         >>> setVar('TEST', 'testcontents')
102         >>> print getVar('TEST')
103         testcontents
104         >>> delVar('TEST')
105         >>> print getVar('TEST')
106         None
107     """
108     if var in d:
109         del d[var]
110
111 def setVarFlag(var, flag, flagvalue, d = _data):
112     """Set a flag for a given variable to a given value
113
114     Example:
115         >>> setVarFlag('TEST', 'python', 1)
116         >>> print getVarFlag('TEST', 'python')
117         1
118     """
119 #   print "d[%s][\"flags\"][%s] = %s" % (var, flag, flagvalue)
120     if not var in d:
121         initVar(var, d)
122     d[var]["flags"][flag] = flagvalue
123
124 def getVarFlag(var, flag, d = _data):
125     """Gets given flag from given var
126
127     Example:
128         >>> setVarFlag('TEST', 'python', 1)
129         >>> print getVarFlag('TEST', 'python')
130         1
131     """
132     if var in d and "flags" in d[var] and flag in d[var]["flags"]:
133         return d[var]["flags"][flag]
134     return None
135
136 def delVarFlag(var, flag, d = _data):
137     """Removes a given flag from the variable's flags
138
139     Example:
140         >>> setVarFlag('TEST', 'testflag', 1)
141         >>> print getVarFlag('TEST', 'testflag')
142         1
143         >>> delVarFlag('TEST', 'testflag')
144         >>> print getVarFlag('TEST', 'testflag')
145         None
146
147     """
148     if var in d and "flags" in d[var] and flag in d[var]["flags"]:
149         del d[var]["flags"][flag]
150
151 def setVarFlags(var, flags, d = _data):
152     """Set the flags for a given variable
153
154     Example:
155         >>> myflags = {}
156         >>> myflags['test'] = 'blah'
157         >>> setVarFlags('TEST', myflags)
158         >>> print getVarFlag('TEST', 'test')
159         blah
160     """
161     if not var in d:
162         initVar(var, d)
163     d[var]["flags"] = flags
164
165 def getVarFlags(var, d = _data):
166     """Gets a variable's flags
167
168     Example:
169         >>> setVarFlag('TEST', 'test', 'blah')
170         >>> print getVarFlags('TEST')['test']
171         blah
172     """
173     if var in d and "flags" in d[var]:
174         return d[var]["flags"]
175     return None
176
177 def delVarFlags(var, d = _data):
178     """Removes a variable's flags
179
180     Example:
181         >>> setVarFlag('TEST', 'testflag', 1)
182         >>> print getVarFlag('TEST', 'testflag')
183         1
184         >>> delVarFlags('TEST')
185         >>> print getVarFlags('TEST')
186         None
187
188     """
189     if var in d and "flags" in d[var]:
190         del d[var]["flags"]
191
192 def getData(d = _data):
193     """Returns the data object used"""
194     return d
195
196 def setData(newData, d = _data):
197     """Sets the data object to the supplied value"""
198     d = newData
199
200 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
201 __expand_python_regexp__ = re.compile(r"\${@.+?}")
202
203 def expand(s, d = _data, varname = None):
204     """Variable expansion using the data store.
205
206     Example:
207         Standard expansion:
208         >>> setVar('A', 'sshd')
209         >>> print expand('/usr/bin/${A}')
210         /usr/bin/sshd
211
212         Python expansion:
213         >>> print expand('result: ${@37 * 72}')
214         result: 2664
215     """
216     def var_sub(match):
217         key = match.group()[2:-1]
218         if varname and key:
219             if varname == key:
220                 raise Exception("variable %s references itself!" % varname)
221         var = getVar(key, d, 1)
222         if var is not None:
223             return var
224         else:
225             return match.group()
226
227     def python_sub(match):
228         import bb
229         code = match.group()[3:-1]
230         locals()['d'] = d
231         s = eval(code)
232         if type(s) == types.IntType: s = str(s)
233         return s
234
235     if type(s) is not types.StringType: # sanity check
236         return s
237
238     while s.find('$') != -1:
239         olds = s
240         try:
241             s = __expand_var_regexp__.sub(var_sub, s)
242             s = __expand_python_regexp__.sub(python_sub, s)
243             if s == olds: break
244             if type(s) is not types.StringType: # sanity check
245                 import bb
246                 bb.error('expansion of %s returned non-string %s' % (olds, s))
247         except:
248             import bb
249             bb.note("%s:%s while evaluating:\n%s" % (sys.exc_info()[0], sys.exc_info()[1], s))
250             raise
251     return s
252
253 def expandKeys(alterdata = _data, readdata = None):
254     if readdata == None:
255         readdata = alterdata
256
257     for key in alterdata.keys():
258         ekey = expand(key, readdata)
259         if key == ekey:
260             continue
261         val = getVar(key, alterdata)
262         if val is None:
263             continue
264 #        import copy
265 #        setVarFlags(ekey, copy.copy(getVarFlags(key, readdata)), alterdata)
266         setVar(ekey, val, alterdata)
267
268         for i in ('_append', '_prepend', '_delete'):
269             dest = getVarFlag(ekey, i, alterdata) or []
270             src = getVarFlag(key, i, readdata) or []
271             dest.extend(src)
272             setVarFlag(ekey, i, dest, alterdata)
273
274         delVar(key, alterdata)
275
276 def expandData(alterdata = _data, readdata = None):
277     """For each variable in alterdata, expand it, and update the var contents.
278        Replacements use data from readdata.
279
280     Example:
281         >>> a=init()
282         >>> b=init()
283         >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
284         >>> setVar("DL_DIR", "/path/to/whatever", b)
285         >>> expandData(a, b)
286         >>> print getVar("dlmsg", a)
287         dl_dir is /path/to/whatever
288        """
289     if readdata == None:
290         readdata = alterdata
291
292     for key in alterdata.keys():
293         val = getVar(key, alterdata)
294         if type(val) is not types.StringType:
295             continue
296         expanded = expand(val, readdata)
297 #       print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
298         if val != expanded:
299             setVar(key, expanded, alterdata)
300
301 import os
302
303 def inheritFromOS(d = _data):
304     """Inherit variables from the environment."""
305 #   fakeroot needs to be able to set these
306     non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
307     for s in os.environ.keys():
308         if not s in non_inherit_vars:
309             try:
310                 setVar(s, os.environ[s], d)
311                 setVarFlag(s, 'matchesenv', '1', d)
312             except TypeError:
313                 pass
314
315 import sys
316
317 def emit_var(var, o=sys.__stdout__, d = _data, all=False):
318     """Emit a variable to be sourced by a shell."""
319     if getVarFlag(var, "python", d):
320         return 0
321
322     try:
323         if all:
324             oval = getVar(var, d, 0)
325         val = getVar(var, d, 1)
326     except KeyboardInterrupt:
327         raise
328     except:
329         o.write('# expansion of %s threw %s\n' % (var, sys.exc_info()[0]))
330         return 0
331
332     if all:
333         o.write('# %s=%s\n' % (var, oval))
334
335     if type(val) is not types.StringType:
336         return 0
337
338     if getVarFlag(var, 'matchesenv', d):
339         return 0
340
341     if var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1:
342         return 0
343
344     val.rstrip()
345     if not val:
346         return 0
347
348     if getVarFlag(var, "func", d):
349 #       NOTE: should probably check for unbalanced {} within the var
350         o.write("%s() {\n%s\n}\n" % (var, val))
351     else:
352         if getVarFlag(var, "export", d):
353             o.write('export ')
354         else:
355             if not all:
356                 return 0
357 #       if we're going to output this within doublequotes,
358 #       to a shell, we need to escape the quotes in the var
359         alter = re.sub('"', '\\"', val.strip())
360         o.write('%s="%s"\n' % (var, alter))
361     return 1
362
363
364 def emit_env(o=sys.__stdout__, d = _data, all=False):
365     """Emits all items in the data store in a format such that it can be sourced by a shell."""
366
367     env = d.keys()
368
369     for e in env:
370         if getVarFlag(e, "func", d):
371             continue
372         emit_var(e, o, d, all) and o.write('\n')
373
374     for e in env:
375         if not getVarFlag(e, "func", d):
376             continue
377         emit_var(e, o, d) and o.write('\n')
378
379 def update_data(d = _data):
380     """Modifies the environment vars according to local overrides and commands.
381     Examples:
382         Appending to a variable:
383         >>> setVar('TEST', 'this is a')
384         >>> setVar('TEST_append', ' test')
385         >>> setVar('TEST_append', ' of the emergency broadcast system.')
386         >>> update_data()
387         >>> print getVar('TEST')
388         this is a test of the emergency broadcast system.
389
390         Prepending to a variable:
391         >>> setVar('TEST', 'virtual/libc')
392         >>> setVar('TEST_prepend', 'virtual/tmake ')
393         >>> setVar('TEST_prepend', 'virtual/patcher ')
394         >>> update_data()
395         >>> print getVar('TEST')
396         virtual/patcher virtual/tmake virtual/libc
397
398         Overrides:
399         >>> setVar('TEST_arm', 'target')
400         >>> setVar('TEST_ramses', 'machine')
401         >>> setVar('TEST_local', 'local')
402         >>> setVar('OVERRIDES', 'arm')
403
404         >>> setVar('TEST', 'original')
405         >>> update_data()
406         >>> print getVar('TEST')
407         target
408
409         >>> setVar('OVERRIDES', 'arm:ramses:local')
410         >>> setVar('TEST', 'original')
411         >>> update_data()
412         >>> print getVar('TEST')
413         local
414     """
415
416     debug(2, "update_data()")
417
418 #   can't do delete env[...] while iterating over the dictionary, so remember them
419     dodel = []
420     overrides = (getVar('OVERRIDES', d, 1) or "").split(':') or []
421
422     def applyOverrides(var, d = _data):
423         if not overrides:
424             debug(1, "OVERRIDES not defined, nothing to do")
425             return
426         val = getVar(var, d)
427         for o in overrides:
428             if var.endswith("_" + o):
429                 l = len(o)+1
430                 name = var[:-l]
431                 d[name] = d[var]
432
433     for s in d.keys():
434         applyOverrides(s, d)
435         sval = getVar(s, d) or ""
436
437 #       Handle line appends:
438         for (a, o) in getVarFlag(s, '_append', d) or []:
439             # maybe the OVERRIDE was not yet added so keep the append
440             if (o and o in overrides) or not o:
441                 delVarFlag(s, '_append', d)
442             if o:
443                 if not o in overrides:
444                     continue
445             sval+=a
446             setVar(s, sval, d)
447
448 #       Handle line prepends
449         for (a, o) in getVarFlag(s, '_prepend', d) or []:
450             # maybe the OVERRIDE was not yet added so keep the append
451             if (o and o in overrides) or not o:
452                 delVarFlag(s, '_prepend', d)
453             if o:
454                 if not o in overrides:
455                     continue
456             sval=a+sval
457             setVar(s, sval, d)
458
459 #       Handle line deletions
460         name = s + "_delete"
461         nameval = getVar(name, d)
462         if nameval:
463             sval = getVar(s, d)
464             if sval:
465                 new = ''
466                 pattern = nameval.replace('\n','').strip()
467                 for line in sval.split('\n'):
468                     if line.find(pattern) == -1:
469                         new = new + '\n' + line
470                 setVar(s, new, d)
471                 dodel.append(name)
472
473 #   delete all environment vars no longer needed
474     for s in dodel:
475         delVar(s, d)
476
477 def inherits_class(klass, d):
478     val = getVar('__inherit_cache', d) or ""
479     if os.path.join('classes', '%s.bbclass' % klass) in val.split():
480         return True
481     return False
482
483 def _test():
484     """Start a doctest run on this module"""
485     import doctest
486     from bb import data
487     doctest.testmod(data)
488
489 if __name__ == "__main__":
490     _test()