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