Alterations to OE data behavior.
[vuplus_bitbake] / bin / oe / data.py
1 #!/usr/bin/python
2 """
3 OpenEmbedded 'Data' implementations
4
5 Functions for interacting with the data structure used by the
6 OpenEmbedded (http://openembedded.org) build infrastructure.
7
8 Copyright: (c) 2003 Chris Larson
9
10 Based on functions from the base oe module, Copyright 2003 Holger Schurig
11 """
12
13 import sys, os, re, time, types
14 if sys.argv[0][-5:] == "pydoc":
15         path = os.path.dirname(os.path.dirname(sys.argv[1]))
16 else:
17         path = os.path.dirname(os.path.dirname(sys.argv[0]))
18 sys.path.append(path)
19
20 from oe import note, debug
21
22 def init():
23         return {}
24
25 _data = init()
26
27 def initVar(var, d = _data):
28         """Non-destructive var init for data structure"""
29         if not var in d:
30                 d[var] = {}
31
32         if not "flags" in d[var]:
33                 d[var]["flags"] = {}
34
35 __setvar_regexp__ = {}
36 __setvar_regexp__["_append"]  = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_append")
37 __setvar_regexp__["_prepend"] = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_prepend")
38 __setvar_regexp__["_delete"]  = re.compile('(?P<base>.*?)%s(_(?P<add>.*))?' % "_delete")
39
40 def setVar(var, value, d = _data):
41         """Set a variable to a given value
42
43         Example:
44                 >>> setVar('TEST', 'testcontents')
45                 >>> print getVar('TEST')
46                 testcontents
47         """
48         for v in ["_append", "_prepend", "_delete"]:
49                 match = __setvar_regexp__[v].match(var)
50                 if match:
51                         base = match.group('base')
52                         override = match.group('add')
53                         l = getVarFlag(base, v, d) or []
54                         if override == 'delete':
55                                 if l.count([value, None]):
56                                         del l[l.index([value, None])]
57                         l.append([value, override])
58                         setVarFlag(base, v, l, d)
59                         return
60
61         if not var in d:
62                 initVar(var, d)
63         if getVarFlag(var, 'matchesenv', d):
64                 delVarFlag(var, 'matchesenv', d)
65                 setVarFlag(var, 'export', 1, d)
66         d[var]["content"] = value
67
68 def getVar(var, d = _data, exp = 0):
69         """Gets the value of a variable
70
71         Example:
72                 >>> setVar('TEST', 'testcontents')
73                 >>> print getVar('TEST')
74                 testcontents
75         """
76         if not var in d or not "content" in d[var]:
77                 return None
78         if exp:
79                 return expand(d[var]["content"], d)
80         return d[var]["content"]
81
82 def delVar(var, d = _data):
83         """Removes a variable from the data set
84
85         Example:
86                 >>> setVar('TEST', 'testcontents')
87                 >>> print getVar('TEST')
88                 testcontents
89                 >>> delVar('TEST')
90                 >>> print getVar('TEST')
91                 None
92         """
93         if var in d:
94                 del d[var]
95
96 def setVarFlag(var, flag, flagvalue, d = _data):
97         """Set a flag for a given variable to a given value
98
99         Example:
100                 >>> setVarFlag('TEST', 'python', 1)
101                 >>> print getVarFlag('TEST', 'python')
102                 1
103         """
104 #       print "d[%s][\"flags\"][%s] = %s" % (var, flag, flagvalue)
105         if not var in d:
106                 initVar(var, d)
107         d[var]["flags"][flag] = flagvalue
108
109 def getVarFlag(var, flag, d = _data):
110         """Gets given flag from given var
111
112         Example:
113                 >>> setVarFlag('TEST', 'python', 1)
114                 >>> print getVarFlag('TEST', 'python')
115                 1
116         """
117         if var in d and "flags" in d[var] and flag in d[var]["flags"]:
118                 return d[var]["flags"][flag]
119         return None
120
121 def delVarFlag(var, flag, d = _data):
122         """Removes a given flag from the variable's flags
123
124         Example:
125                 >>> setVarFlag('TEST', 'testflag', 1)
126                 >>> print getVarFlag('TEST', 'testflag')
127                 1
128                 >>> delVarFlag('TEST', 'testflag')
129                 >>> print getVarFlag('TEST', 'testflag')
130                 None
131
132         """
133         if var in d and "flags" in d[var] and flag in d[var]["flags"]:
134                 del d[var]["flags"][flag]
135
136 def setVarFlags(var, flags, d = _data):
137         """Set the flags for a given variable
138
139         Example:
140                 >>> myflags = {}
141                 >>> myflags['test'] = 'blah'
142                 >>> setVarFlags('TEST', myflags)
143                 >>> print getVarFlag('TEST', 'test')
144                 blah
145         """
146         if not var in d:
147                 initVar(var, d)
148         d[var]["flags"] = flags
149
150 def getVarFlags(var, d = _data):
151         """Gets a variable's flags
152
153         Example:
154                 >>> setVarFlag('TEST', 'test', 'blah')
155                 >>> print getVarFlags('TEST')['test']
156                 blah
157         """
158         if var in d and "flags" in d[var]:
159                 return d[var]["flags"]
160         return None
161
162 def delVarFlags(var, d = _data):
163         """Removes a variable's flags
164
165         Example:
166                 >>> setVarFlag('TEST', 'testflag', 1)
167                 >>> print getVarFlag('TEST', 'testflag')
168                 1
169                 >>> delVarFlags('TEST')
170                 >>> print getVarFlags('TEST')
171                 None
172
173         """
174         if var in d and "flags" in d[var]:
175                 del d[var]["flags"]
176
177 def getData(d = _data):
178         """Returns the data object used"""
179         return d
180
181 def setData(newData, d = _data):
182         """Sets the data object to the supplied value"""
183         d = newData
184
185 __expand_var_regexp__ = re.compile(r"\${[^{}]+}")
186 __expand_python_regexp__ = re.compile(r"\${@.+?}")
187
188 def expand(s, d = _data):
189         """Variable expansion using the data store.
190
191         Example:
192                 Standard expansion:
193                 >>> setVar('A', 'sshd')
194                 >>> print expand('/usr/bin/${A}')
195                 /usr/bin/sshd
196
197                 Python expansion:
198                 >>> print expand('result: ${@37 * 72}')
199                 result: 2664
200         """
201         def var_sub(match):
202                 key = match.group()[2:-1]
203                 #print "got key:", key
204                 var = getVar(key, d, 1)
205                 if var is not None:
206                         return var
207                 else:
208                         return match.group()
209
210         def python_sub(match):
211                 code = match.group()[3:-1]
212                 import oe
213                 locals()['d'] = d
214                 s = eval(code)
215                 if type(s) == types.IntType: s = str(s)
216                 return s
217
218         if type(s) is not types.StringType: # sanity check
219                 return s
220
221         while s.find('$') != -1:
222                 olds = s
223                 s = __expand_var_regexp__.sub(var_sub, s)
224                 s = __expand_python_regexp__.sub(python_sub, s)
225                 if len(s)>2048:
226                         debug(1, "expanded string too long")
227                         return s
228                 if s == olds: break
229         return s
230
231 def expandKeys(alterdata = _data, readdata = None):
232         if readdata == None:
233                 readdata = alterdata
234
235         for key in alterdata.keys():
236                 ekey = expand(key, readdata)
237                 if key == ekey:
238                         continue
239                 val = getVar(key, alterdata)
240                 if val is None:
241                         continue
242                 setVar(ekey, val, alterdata)
243
244 def expandData(alterdata = _data, readdata = None):
245         """For each variable in alterdata, expand it, and update the var contents.
246            Replacements use data from readdata.
247
248         Example:
249                 >>> a=init()
250                 >>> b=init()
251                 >>> setVar("dlmsg", "dl_dir is ${DL_DIR}", a)
252                 >>> setVar("DL_DIR", "/path/to/whatever", b)
253                 >>> expandData(a, b)
254                 >>> print getVar("dlmsg", a)
255                 dl_dir is /path/to/whatever
256            """
257         if readdata == None:
258                 readdata = alterdata
259
260         for key in alterdata.keys():
261                 val = getVar(key, alterdata)
262                 if type(val) is not types.StringType:
263                         continue
264                 expanded = expand(val, readdata)
265 #               print "key is %s, val is %s, expanded is %s" % (key, val, expanded)
266                 if val != expanded:
267                         setVar(key, expanded, alterdata)
268
269 import os
270
271 def inheritFromOS(d = _data):
272         """Inherit variables from the environment."""
273         # fakeroot needs to be able to set these
274         non_inherit_vars = [ "LD_LIBRARY_PATH", "LD_PRELOAD" ]
275         for s in os.environ.keys():
276                 if not s in non_inherit_vars:
277                         try:
278                                 setVar(s, os.environ[s], d)
279                                 setVarFlag(s, 'matchesenv', '1', d)
280                         except TypeError:
281                                 pass
282
283 import sys, string
284
285 def emit_var(var, o=sys.__stdout__, d = _data):
286         """Emit a variable to be sourced by a shell."""
287         if getVarFlag(var, "python", d):
288                 return 0
289
290         val = getVar(var, d, 1)
291         if type(val) is not types.StringType:
292                 debug(2, "Warning, %s variable is not a string, not emitting" % var)
293                 return 0
294
295         if getVarFlag(var, 'matchesenv', d):
296                 return 0
297
298         if var.find("-") != -1 or var.find(".") != -1 or var.find('{') != -1 or var.find('}') != -1 or var.find('+') != -1:
299                 debug(2, "Warning, %s variable name contains an invalid char, not emitting to shell" % var)
300                 return 0
301
302         if getVarFlag(var, "func", d):
303                 # NOTE: should probably check for unbalanced {} within the var
304                 o.write("%s() {\n%s\n}\n" % (var, val))
305         else:
306                 if not getVarFlag(var, "export", d):
307                         return 0
308
309                 o.write('export ')
310                 # if we're going to output this within doublequotes,
311                 # to a shell, we need to escape the quotes in the var
312                 alter = re.sub('"', '\\"', val.strip())
313                 o.write('%s="%s"\n' % (var, alter))
314         return 1
315
316
317 def emit_env(o=sys.__stdout__, d = _data):
318         """Emits all items in the data store in a format such that it can be sourced by a shell."""
319
320 #       expandData(d)
321         env = d.keys()
322
323         for e in env:
324                 if getVarFlag(e, "func", d):
325                         continue
326                 emit_var(e, o, d) and o.write('\n')
327
328         for e in env:
329                 if not getVarFlag(e, "func", d):
330                         continue
331                 emit_var(e, o, d) and o.write('\n')
332
333 def update_data(d = _data):
334         """Modifies the environment vars according to local overrides and commands.
335         Examples:
336                 Appending to a variable:
337                 >>> setVar('TEST', 'this is a')
338                 >>> setVar('TEST_append', ' test')
339                 >>> setVar('TEST_append', ' of the emergency broadcast system.')
340                 >>> update_data()
341                 >>> print getVar('TEST')
342                 this is a test of the emergency broadcast system.
343
344                 Prepending to a variable:
345                 >>> setVar('TEST', 'virtual/libc')
346                 >>> setVar('TEST_prepend', 'virtual/tmake ')
347                 >>> setVar('TEST_prepend', 'virtual/patcher ')
348                 >>> update_data()
349                 >>> print getVar('TEST')
350                 virtual/patcher virtual/tmake virtual/libc
351
352                 Overrides:
353                 >>> setVar('TEST_arm', 'target')
354                 >>> setVar('TEST_ramses', 'machine')
355                 >>> setVar('TEST_local', 'local')
356                 >>> setVar('OVERRIDES', 'arm')
357
358                 >>> setVar('TEST', 'original')
359                 >>> update_data()
360                 >>> print getVar('TEST')
361                 target
362
363                 >>> setVar('OVERRIDES', 'arm:ramses:local')
364                 >>> setVar('TEST', 'original')
365                 >>> update_data()
366                 >>> print getVar('TEST')
367                 local
368         """
369
370         debug(2, "update_data()")
371
372         # can't do delete env[...] while iterating over the dictionary, so remember them
373         dodel = []
374         overrides = string.split(getVar('OVERRIDES', d, 1) or "", ":") or []
375
376         def applyOverrides(var, d = _data):
377                 if not overrides:
378                         debug(1, "OVERRIDES not defined, nothing to do")
379                         return
380                 val = getVar(var, d)
381                 for o in overrides:
382                         if var.endswith("_" + o):
383                                 l = len(o)+1
384                                 name = var[:-l]
385                                 d[name] = d[var]
386
387         for s in d.keys():
388                 applyOverrides(s, d)
389                 sval = getVar(s, d) or ""
390
391                 # Handle line appends:
392                 for (a, o) in getVarFlag(s, '_append', d) or []:
393                         delVarFlag(s, '_append', d)
394                         if o:
395                                 if not o in overrides:
396                                         break
397                         sval+=a
398                         setVar(s, sval, d)
399
400                 # Handle line prepends
401                 for (a, o) in getVarFlag(s, '_prepend', d) or []:
402                         delVarFlag(s, '_prepend', d)
403                         if o:
404                                 if not o in overrides:
405                                         break
406                         sval=a+sval
407                         setVar(s, sval, d)
408
409                 # Handle line deletions
410                 name = s + "_delete"
411                 nameval = getVar(name, d)
412                 if nameval:
413                         sval = getVar(s, d)
414                         if sval:
415                                 new = ''
416                                 pattern = string.replace(nameval,"\n","").strip()
417                                 for line in string.split(sval,"\n"):
418                                         if line.find(pattern) == -1:
419                                                 new = new + '\n' + line
420                                 setVar(s, new, d)
421                                 dodel.append(name)
422
423         # delete all environment vars no longer needed
424         for s in dodel:
425                 delVar(s, d)
426
427 def _test():
428         """Start a doctest run on this module"""
429         import doctest
430         from oe import data
431         doctest.testmod(data)
432
433 if __name__ == "__main__":
434         _test()