bin/bitbake:
[vuplus_bitbake] / lib / bb / parse / parse_py / BBHandler.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 """class for handling .bb files
5
6    Reads a .bb file and obtains its metadata
7
8    Copyright (C) 2003, 2004  Chris Larson
9    Copyright (C) 2003, 2004  Phil Blundell
10    
11    This program is free software; you can redistribute it and/or modify it under
12    the terms of the GNU General Public License as published by the Free Software
13    Foundation; either version 2 of the License, or (at your option) any later
14    version.
15    
16    This program is distributed in the hope that it will be useful, but WITHOUT
17    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18    FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License along with
21    this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22    Place, Suite 330, Boston, MA 02111-1307 USA.""" 
23
24 import re, bb, os, sys, time
25 import bb.fetch, bb.build, bb.utils
26 from bb import debug, data, fetch, fatal
27
28 from ConfHandler import include, localpath, obtain, init
29 from bb.parse import ParseError
30
31 __func_start_regexp__    = re.compile( r"(((?P<py>python)|(?P<fr>fakeroot))\s*)*(?P<func>[\w\.\-\+\{\}\$]+)?\s*\(\s*\)\s*{$" )
32 __inherit_regexp__       = re.compile( r"inherit\s+(.+)" )
33 __export_func_regexp__   = re.compile( r"EXPORT_FUNCTIONS\s+(.+)" )
34 __addtask_regexp__       = re.compile("addtask\s+(?P<func>\w+)\s*((before\s*(?P<before>((.*(?=after))|(.*))))|(after\s*(?P<after>((.*(?=before))|(.*)))))*")
35 __addhandler_regexp__    = re.compile( r"addhandler\s+(.+)" )
36 __def_regexp__           = re.compile( r"def\s+(\w+).*:" )
37 __python_func_regexp__   = re.compile( r"(\s+.*)|(^$)" )
38 __word__ = re.compile(r"\S+")
39
40 __infunc__ = ""
41 __inpython__ = False
42 __body__   = []
43 __bbpath_found__ = 0
44 __classname__ = ""
45 classes = [ None, ]
46
47 #
48 # A cache of parsed bbclasses. We will use this cache to make a
49 # decision if we should compile and execute a method.
50 # This dict contains a list of classes which might have methods
51 # we have already added.
52 #
53 __parsed_methods__ = {}
54
55 def supports(fn, d):
56     localfn = localpath(fn, d)
57     return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
58
59 def inherit(files, d):
60     __inherit_cache = data.getVar('__inherit_cache', d) or ""
61     fn = ""
62     lineno = 0
63     for f in files:
64         file = data.expand(f, d)
65         if file[0] != "/" and file[-8:] != ".bbclass":
66             file = os.path.join('classes', '%s.bbclass' % file)
67
68         if not file in __inherit_cache.split():
69             debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
70             __inherit_cache += " %s" % file
71             include(fn, file, d)
72     data.setVar('__inherit_cache', __inherit_cache, d)
73
74
75 def handle(fn, d, include = 0):
76     global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
77     __body__ = []
78     __bbpath_found__ = 0
79     __infunc__ = ""
80     __classname__ = ""
81     __residue__ = []
82
83     if include == 0:
84         debug(2, "BB " + fn + ": handle(data)")
85     else:
86         debug(2, "BB " + fn + ": handle(data, include)")
87
88     (root, ext) = os.path.splitext(os.path.basename(fn))
89     base_name = "%s%s" % (root,ext)
90     init(d)
91
92     if ext == ".bbclass":
93         __classname__ = root
94         classes.append(__classname__)
95
96     if include != 0:
97         oldfile = data.getVar('FILE', d)
98     else:
99         oldfile = None
100
101     fn = obtain(fn, d)
102     bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
103     if not os.path.isabs(fn):
104         f = None
105         for p in bbpath:
106             p = data.expand(p, d)
107             j = os.path.join(p, fn)
108             if os.access(j, os.R_OK):
109                 abs_fn = j
110                 f = open(j, 'r')
111                 break
112         if f is None:
113             raise IOError("file not found")
114     else:
115         f = open(fn,'r')
116         abs_fn = fn
117
118     if ext != ".bbclass":
119         bbpath.insert(0, os.path.dirname(abs_fn))
120         data.setVar('BBPATH', ":".join(bbpath), d)
121
122     if include:
123         bb.parse.mark_dependency(d, abs_fn)
124
125     if ext != ".bbclass":
126         data.setVar('FILE', fn, d)
127         i = (data.getVar("INHERIT", d, 1) or "").split()
128         if not "base" in i and __classname__ != "base":
129             i[0:0] = ["base"]
130         inherit(i, d)
131
132     lineno = 0
133     while 1:
134         lineno = lineno + 1
135         s = f.readline()
136         if not s: break
137         s = s.rstrip()
138         feeder(lineno, s, fn, base_name, d)
139     if __inpython__:
140         # add a blank line to close out any python definition
141         feeder(lineno + 1, "", fn, base_name, d)
142     if ext == ".bbclass":
143         classes.remove(__classname__)
144     else:
145         if include == 0:
146             data.expandKeys(d)
147             data.update_data(d)
148             anonqueue = data.getVar("__anonqueue", d, 1) or []
149             for anon in anonqueue:
150                 data.setVar("__anonfunc", anon["content"], d)
151                 data.setVarFlags("__anonfunc", anon["flags"], d)
152                 from bb import build
153                 try:
154                     t = data.getVar('T', d)
155                     data.setVar('T', '${TMPDIR}/', d)
156                     build.exec_func("__anonfunc", d)
157                     data.delVar('T', d)
158                     if t:
159                         data.setVar('T', t, d)
160                 except Exception, e:
161                     bb.debug(1, "executing anonymous function: %s" % e)
162                     raise
163             data.delVar("__anonqueue", d)
164             data.delVar("__anonfunc", d)
165             set_additional_vars(fn, d, include)
166             data.update_data(d)
167
168             for var in data.keys(d):
169                 if data.getVarFlag(var, 'handler', d):
170                     bb.event.register(var, data.getVar(var, d))
171                     continue
172
173                 if not data.getVarFlag(var, 'task', d):
174                     continue
175
176                 deps = data.getVarFlag(var, 'deps', d) or []
177                 postdeps = data.getVarFlag(var, 'postdeps', d) or []
178                 bb.build.add_task(var, deps, d)
179                 for p in postdeps:
180                     pdeps = data.getVarFlag(p, 'deps', d) or []
181                     pdeps.append(var)
182                     data.setVarFlag(p, 'deps', pdeps, d)
183                     bb.build.add_task(p, pdeps, d)
184         bbpath.pop(0)
185     if oldfile:
186         bb.data.setVar("FILE", oldfile, d)
187
188     # we have parsed the bb class now
189     if ext == ".bbclass" or ext == ".inc":
190         __parsed_methods__[base_name] = 1
191
192     return d
193
194 def feeder(lineno, s, fn, root, d):
195     global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, __bbpath_found__, classes, bb, __residue__
196     if __infunc__:
197         if s == '}':
198             __body__.append('')
199             data.setVar(__infunc__, '\n'.join(__body__), d)
200             data.setVarFlag(__infunc__, "func", 1, d)
201             if __infunc__ == "__anonymous":
202                 anonqueue = bb.data.getVar("__anonqueue", d) or []
203                 anonitem = {}
204                 anonitem["content"] = bb.data.getVar("__anonymous", d)
205                 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
206                 anonqueue.append(anonitem)
207                 bb.data.setVar("__anonqueue", anonqueue, d)
208                 bb.data.delVarFlags("__anonymous", d)
209                 bb.data.delVar("__anonymous", d)
210             __infunc__ = ""
211             __body__ = []
212         else:
213             __body__.append(s)
214         return
215
216     if __inpython__:
217         m = __python_func_regexp__.match(s)
218         if m:
219             __body__.append(s)
220             return
221         else:
222             if not root  in __parsed_methods__:
223                 text = '\n'.join(__body__)
224                 comp = bb.utils.better_compile(text, "<bb>", fn )
225                 bb.utils.better_exec(comp, __builtins__, text, fn)
226                 funcs = data.getVar('__functions__', d) or ""
227                 data.setVar('__functions__', "%s\n%s" % (funcs, text), d)
228             __body__ = []
229             __inpython__ = False
230
231 #           fall through
232
233     if s == '' or s[0] == '#': return          # skip comments and empty lines
234
235     if s[-1] == '\\':
236         __residue__.append(s[:-1])
237         return
238
239     s = "".join(__residue__) + s
240     __residue__ = []
241
242     m = __func_start_regexp__.match(s)
243     if m:
244         __infunc__ = m.group("func") or "__anonymous"
245         key = __infunc__
246         if data.getVar(key, d):
247 #           clean up old version of this piece of metadata, as its
248 #           flags could cause problems
249             data.setVarFlag(key, 'python', None, d)
250             data.setVarFlag(key, 'fakeroot', None, d)
251         if m.group("py") is not None:
252             data.setVarFlag(key, "python", "1", d)
253         else:
254             data.delVarFlag(key, "python", d)
255         if m.group("fr") is not None:
256             data.setVarFlag(key, "fakeroot", "1", d)
257         else:
258             data.delVarFlag(key, "fakeroot", d)
259         return
260
261     m = __def_regexp__.match(s)
262     if m:
263         __body__.append(s)
264         __inpython__ = True
265         return
266
267     m = __export_func_regexp__.match(s)
268     if m:
269         fns = m.group(1)
270         n = __word__.findall(fns)
271         for f in n:
272             allvars = []
273             allvars.append(f)
274             allvars.append(classes[-1] + "_" + f)
275
276             vars = [[ allvars[0], allvars[1] ]]
277             if len(classes) > 1 and classes[-2] is not None:
278                 allvars.append(classes[-2] + "_" + f)
279                 vars = []
280                 vars.append([allvars[2], allvars[1]])
281                 vars.append([allvars[0], allvars[2]])
282
283             for (var, calledvar) in vars:
284                 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
285                     continue
286
287                 if data.getVar(var, d):
288                     data.setVarFlag(var, 'python', None, d)
289                     data.setVarFlag(var, 'func', None, d)
290
291                 for flag in [ "func", "python" ]:
292                     if data.getVarFlag(calledvar, flag, d):
293                         data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
294                 for flag in [ "dirs" ]:
295                     if data.getVarFlag(var, flag, d):
296                         data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
297
298                 if data.getVarFlag(calledvar, "python", d):
299                     data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
300                 else:
301                     data.setVar(var, "\t" + calledvar + "\n", d)
302                 data.setVarFlag(var, 'export_func', '1', d)
303
304         return
305
306     m = __addtask_regexp__.match(s)
307     if m:
308         func = m.group("func")
309         before = m.group("before")
310         after = m.group("after")
311         if func is None:
312             return
313         var = "do_" + func
314
315         data.setVarFlag(var, "task", 1, d)
316
317         if after is not None:
318 #           set up deps for function
319             data.setVarFlag(var, "deps", after.split(), d)
320         if before is not None:
321 #           set up things that depend on this func
322             data.setVarFlag(var, "postdeps", before.split(), d)
323         return
324
325     m = __addhandler_regexp__.match(s)
326     if m:
327         fns = m.group(1)
328         hs = __word__.findall(fns)
329         for h in hs:
330             data.setVarFlag(h, "handler", 1, d)
331         return
332
333     m = __inherit_regexp__.match(s)
334     if m:
335
336         files = m.group(1)
337         n = __word__.findall(files)
338         inherit(n, d)
339         return
340
341     from bb.parse import ConfHandler
342     return ConfHandler.feeder(lineno, s, fn, d)
343
344 __pkgsplit_cache__={}
345 def vars_from_file(mypkg, d):
346     if not mypkg:
347         return (None, None, None)
348     if mypkg in __pkgsplit_cache__:
349         return __pkgsplit_cache__[mypkg]
350
351     myfile = os.path.splitext(os.path.basename(mypkg))
352     parts = myfile[0].split('_')
353     __pkgsplit_cache__[mypkg] = parts
354     exp = 3 - len(parts)
355     tmplist = []
356     while exp != 0:
357         exp -= 1
358         tmplist.append(None)
359     parts.extend(tmplist)
360     return parts
361
362 def set_additional_vars(file, d, include):
363     """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
364
365     debug(2,"BB %s: set_additional_vars" % file)
366
367     src_uri = data.getVar('SRC_URI', d)
368     if not src_uri:
369         return
370     src_uri = data.expand(src_uri, d)
371
372     a = data.getVar('A', d)
373     if a:
374         a = data.expand(a, d).split()
375     else:
376         a = []
377
378     from bb import fetch
379     try:
380         fetch.init(src_uri.split(), d)
381     except fetch.NoMethodError:
382         pass
383     except bb.MalformedUrl,e:
384         raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
385
386     a += fetch.localpaths(d)
387     del fetch
388     data.setVar('A', " ".join(a), d)
389
390
391 # Add us to the handlers list
392 from bb.parse import handlers
393 handlers.append({'supports': supports, 'handle': handle, 'init': init})
394 del handlers