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
6 Reads a .bb file and obtains its metadata
8 Copyright (C) 2003, 2004 Chris Larson
9 Copyright (C) 2003, 2004 Phil Blundell
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
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.
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."""
24 import re, bb, os, sys, time
25 import bb.fetch, bb.build, bb.utils
26 from bb import data, fetch, methodpool
28 from ConfHandler import include, localpath, obtain, init
29 from bb.parse import ParseError
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+")
47 # We need to indicate EOF to the feeder. This code is so messy that
48 # factoring it out to a close_parse_file method is out of question.
49 # We will use the IN_PYTHON_EOF as an indicator to just close the method
51 # The two parts using it are tightly integrated anyway
52 IN_PYTHON_EOF = -9999999999999
54 __parsed_methods__ = methodpool.get_parsed_dict()
57 localfn = localpath(fn, d)
58 return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
60 def inherit(files, d):
61 __inherit_cache = data.getVar('__inherit_cache', d) or []
65 file = data.expand(f, d)
66 if file[0] != "/" and file[-8:] != ".bbclass":
67 file = os.path.join('classes', '%s.bbclass' % file)
69 if not file in __inherit_cache:
70 bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s:%d: inheriting %s" % (fn, lineno, file))
71 __inherit_cache.append( file )
72 include(fn, file, d, "inherit")
73 data.setVar('__inherit_cache', __inherit_cache, d)
76 def handle(fn, d, include = 0):
77 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
85 bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data)")
87 bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)")
89 (root, ext) = os.path.splitext(os.path.basename(fn))
90 base_name = "%s%s" % (root,ext)
95 classes.append(__classname__)
98 oldfile = data.getVar('FILE', d)
103 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
104 if not os.path.isabs(fn):
107 p = data.expand(p, d)
108 j = os.path.join(p, fn)
109 if os.access(j, os.R_OK):
114 raise IOError("file not found")
119 if ext != ".bbclass":
120 bbpath.insert(0, os.path.dirname(abs_fn))
121 data.setVar('BBPATH', ":".join(bbpath), d)
124 bb.parse.mark_dependency(d, abs_fn)
126 if ext != ".bbclass":
127 data.setVar('FILE', fn, d)
128 i = (data.getVar("INHERIT", d, 1) or "").split()
129 if not "base" in i and __classname__ != "base":
139 feeder(lineno, s, fn, base_name, d)
141 # add a blank line to close out any python definition
142 feeder(IN_PYTHON_EOF, "", fn, base_name, d)
143 if ext == ".bbclass":
144 classes.remove(__classname__)
149 anonqueue = data.getVar("__anonqueue", d, 1) or []
150 body = [x['content'] for x in anonqueue]
151 flag = { 'python' : 1, 'func' : 1 }
152 data.setVar("__anonfunc", "\n".join(body), d)
153 data.setVarFlags("__anonfunc", flag, d)
156 t = data.getVar('T', d)
157 data.setVar('T', '${TMPDIR}/', d)
158 build.exec_func("__anonfunc", d)
161 data.setVar('T', t, d)
163 bb.msg.debug(1, bb.msg.domain.Parsing, "executing anonymous function: %s" % e)
165 data.delVar("__anonqueue", d)
166 data.delVar("__anonfunc", d)
167 set_additional_vars(fn, d, include)
171 for var in data.keys(d):
172 # try to add the handler
173 # if we added it remember the choiche
174 if data.getVarFlag(var, 'handler', d):
175 handler = data.getVar(var,d)
176 if bb.event.register(var,handler) == bb.event.Registered:
177 all_handlers[var] = handler
181 if not data.getVarFlag(var, 'task', d):
184 deps = data.getVarFlag(var, 'deps', d) or []
185 postdeps = data.getVarFlag(var, 'postdeps', d) or []
186 bb.build.add_task(var, deps, d)
188 pdeps = data.getVarFlag(p, 'deps', d) or []
190 data.setVarFlag(p, 'deps', pdeps, d)
191 bb.build.add_task(p, pdeps, d)
193 # now add the handlers
194 if not len(all_handlers) == 0:
195 data.setVar('__all_handlers__', all_handlers, d)
199 bb.data.setVar("FILE", oldfile, d)
201 # we have parsed the bb class now
202 if ext == ".bbclass" or ext == ".inc":
203 __parsed_methods__[base_name] = 1
207 def feeder(lineno, s, fn, root, d):
208 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__
212 data.setVar(__infunc__, '\n'.join(__body__), d)
213 data.setVarFlag(__infunc__, "func", 1, d)
214 if __infunc__ == "__anonymous":
215 anonqueue = bb.data.getVar("__anonqueue", d) or []
217 anonitem["content"] = bb.data.getVar("__anonymous", d)
218 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
219 anonqueue.append(anonitem)
220 bb.data.setVar("__anonqueue", anonqueue, d)
221 bb.data.delVarFlags("__anonymous", d)
222 bb.data.delVar("__anonymous", d)
230 m = __python_func_regexp__.match(s)
231 if m and lineno != IN_PYTHON_EOF:
235 # Note we will add root to parsedmethods after having parse
236 # 'this' file. This means we will not parse methods from
238 if not root in __parsed_methods__:
239 text = '\n'.join(__body__)
240 methodpool.insert_method( root, text, fn )
241 funcs = data.getVar('__functions__', d) or {}
242 if not funcs.has_key( root ):
245 funcs[root] = "%s\n%s" % (funcs[root], text)
247 data.setVar('__functions__', funcs, d)
251 if lineno == IN_PYTHON_EOF:
256 if s == '' or s[0] == '#': return # skip comments and empty lines
259 __residue__.append(s[:-1])
262 s = "".join(__residue__) + s
265 m = __func_start_regexp__.match(s)
267 __infunc__ = m.group("func") or "__anonymous"
269 if data.getVar(key, d):
270 # clean up old version of this piece of metadata, as its
271 # flags could cause problems
272 data.setVarFlag(key, 'python', None, d)
273 data.setVarFlag(key, 'fakeroot', None, d)
274 if m.group("py") is not None:
275 data.setVarFlag(key, "python", "1", d)
277 data.delVarFlag(key, "python", d)
278 if m.group("fr") is not None:
279 data.setVarFlag(key, "fakeroot", "1", d)
281 data.delVarFlag(key, "fakeroot", d)
284 m = __def_regexp__.match(s)
290 m = __export_func_regexp__.match(s)
293 n = __word__.findall(fns)
297 allvars.append(classes[-1] + "_" + f)
299 vars = [[ allvars[0], allvars[1] ]]
300 if len(classes) > 1 and classes[-2] is not None:
301 allvars.append(classes[-2] + "_" + f)
303 vars.append([allvars[2], allvars[1]])
304 vars.append([allvars[0], allvars[2]])
306 for (var, calledvar) in vars:
307 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
310 if data.getVar(var, d):
311 data.setVarFlag(var, 'python', None, d)
312 data.setVarFlag(var, 'func', None, d)
314 for flag in [ "func", "python" ]:
315 if data.getVarFlag(calledvar, flag, d):
316 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
317 for flag in [ "dirs" ]:
318 if data.getVarFlag(var, flag, d):
319 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
321 if data.getVarFlag(calledvar, "python", d):
322 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
324 data.setVar(var, "\t" + calledvar + "\n", d)
325 data.setVarFlag(var, 'export_func', '1', d)
329 m = __addtask_regexp__.match(s)
331 func = m.group("func")
332 before = m.group("before")
333 after = m.group("after")
338 data.setVarFlag(var, "task", 1, d)
340 if after is not None:
341 # set up deps for function
342 data.setVarFlag(var, "deps", after.split(), d)
343 if before is not None:
344 # set up things that depend on this func
345 data.setVarFlag(var, "postdeps", before.split(), d)
348 m = __addhandler_regexp__.match(s)
351 hs = __word__.findall(fns)
353 data.setVarFlag(h, "handler", 1, d)
356 m = __inherit_regexp__.match(s)
360 n = __word__.findall(files)
364 from bb.parse import ConfHandler
365 return ConfHandler.feeder(lineno, s, fn, d)
367 __pkgsplit_cache__={}
368 def vars_from_file(mypkg, d):
370 return (None, None, None)
371 if mypkg in __pkgsplit_cache__:
372 return __pkgsplit_cache__[mypkg]
374 myfile = os.path.splitext(os.path.basename(mypkg))
375 parts = myfile[0].split('_')
376 __pkgsplit_cache__[mypkg] = parts
382 parts.extend(tmplist)
385 def set_additional_vars(file, d, include):
386 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
388 bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file)
390 src_uri = data.getVar('SRC_URI', d)
393 src_uri = data.expand(src_uri, d)
395 a = data.getVar('A', d)
397 a = data.expand(a, d).split()
403 fetch.init(src_uri.split(), d)
404 except fetch.NoMethodError:
406 except bb.MalformedUrl,e:
407 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
409 a += fetch.localpaths(d)
411 data.setVar('A', " ".join(a), d)
414 # Add us to the handlers list
415 from bb.parse import handlers
416 handlers.append({'supports': supports, 'handle': handle, 'init': init})