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.split():
70 bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s:%d: inheriting %s" % (fn, lineno, file))
71 __inherit_cache += " %s" % 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 for anon in anonqueue:
151 data.setVar("__anonfunc", anon["content"], d)
152 data.setVarFlags("__anonfunc", anon["flags"], d)
155 t = data.getVar('T', d)
156 data.setVar('T', '${TMPDIR}/', d)
157 build.exec_func("__anonfunc", d)
160 data.setVar('T', t, d)
162 bb.msg.debug(1, bb.msg.domain.Parsing, "executing anonymous function: %s" % e)
164 data.delVar("__anonqueue", d)
165 data.delVar("__anonfunc", d)
166 set_additional_vars(fn, d, include)
170 for var in data.keys(d):
171 # try to add the handler
172 # if we added it remember the choiche
173 if data.getVarFlag(var, 'handler', d):
174 handler = data.getVar(var,d)
175 if bb.event.register(var,handler) == bb.event.Registered:
176 all_handlers[var] = handler
180 if not data.getVarFlag(var, 'task', d):
183 deps = data.getVarFlag(var, 'deps', d) or []
184 postdeps = data.getVarFlag(var, 'postdeps', d) or []
185 bb.build.add_task(var, deps, d)
187 pdeps = data.getVarFlag(p, 'deps', d) or []
189 data.setVarFlag(p, 'deps', pdeps, d)
190 bb.build.add_task(p, pdeps, d)
192 # now add the handlers
193 if not len(all_handlers) == 0:
194 data.setVar('__all_handlers__', all_handlers, d)
198 bb.data.setVar("FILE", oldfile, d)
200 # we have parsed the bb class now
201 if ext == ".bbclass" or ext == ".inc":
202 __parsed_methods__[base_name] = 1
206 def feeder(lineno, s, fn, root, d):
207 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__
211 data.setVar(__infunc__, '\n'.join(__body__), d)
212 data.setVarFlag(__infunc__, "func", 1, d)
213 if __infunc__ == "__anonymous":
214 anonqueue = bb.data.getVar("__anonqueue", d) or []
216 anonitem["content"] = bb.data.getVar("__anonymous", d)
217 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
218 anonqueue.append(anonitem)
219 bb.data.setVar("__anonqueue", anonqueue, d)
220 bb.data.delVarFlags("__anonymous", d)
221 bb.data.delVar("__anonymous", d)
229 m = __python_func_regexp__.match(s)
230 if m and lineno != IN_PYTHON_EOF:
234 # Note we will add root to parsedmethods after having parse
235 # 'this' file. This means we will not parse methods from
237 if not root in __parsed_methods__:
238 text = '\n'.join(__body__)
239 methodpool.insert_method( root, text, fn )
240 funcs = data.getVar('__functions__', d) or {}
241 if not funcs.has_key( root ):
244 funcs[root] = "%s\n%s" % (funcs[root], text)
246 data.setVar('__functions__', funcs, d)
250 if lineno == IN_PYTHON_EOF:
255 if s == '' or s[0] == '#': return # skip comments and empty lines
258 __residue__.append(s[:-1])
261 s = "".join(__residue__) + s
264 m = __func_start_regexp__.match(s)
266 __infunc__ = m.group("func") or "__anonymous"
268 if data.getVar(key, d):
269 # clean up old version of this piece of metadata, as its
270 # flags could cause problems
271 data.setVarFlag(key, 'python', None, d)
272 data.setVarFlag(key, 'fakeroot', None, d)
273 if m.group("py") is not None:
274 data.setVarFlag(key, "python", "1", d)
276 data.delVarFlag(key, "python", d)
277 if m.group("fr") is not None:
278 data.setVarFlag(key, "fakeroot", "1", d)
280 data.delVarFlag(key, "fakeroot", d)
283 m = __def_regexp__.match(s)
289 m = __export_func_regexp__.match(s)
292 n = __word__.findall(fns)
296 allvars.append(classes[-1] + "_" + f)
298 vars = [[ allvars[0], allvars[1] ]]
299 if len(classes) > 1 and classes[-2] is not None:
300 allvars.append(classes[-2] + "_" + f)
302 vars.append([allvars[2], allvars[1]])
303 vars.append([allvars[0], allvars[2]])
305 for (var, calledvar) in vars:
306 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
309 if data.getVar(var, d):
310 data.setVarFlag(var, 'python', None, d)
311 data.setVarFlag(var, 'func', None, d)
313 for flag in [ "func", "python" ]:
314 if data.getVarFlag(calledvar, flag, d):
315 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
316 for flag in [ "dirs" ]:
317 if data.getVarFlag(var, flag, d):
318 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
320 if data.getVarFlag(calledvar, "python", d):
321 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
323 data.setVar(var, "\t" + calledvar + "\n", d)
324 data.setVarFlag(var, 'export_func', '1', d)
328 m = __addtask_regexp__.match(s)
330 func = m.group("func")
331 before = m.group("before")
332 after = m.group("after")
337 data.setVarFlag(var, "task", 1, d)
339 if after is not None:
340 # set up deps for function
341 data.setVarFlag(var, "deps", after.split(), d)
342 if before is not None:
343 # set up things that depend on this func
344 data.setVarFlag(var, "postdeps", before.split(), d)
347 m = __addhandler_regexp__.match(s)
350 hs = __word__.findall(fns)
352 data.setVarFlag(h, "handler", 1, d)
355 m = __inherit_regexp__.match(s)
359 n = __word__.findall(files)
363 from bb.parse import ConfHandler
364 return ConfHandler.feeder(lineno, s, fn, d)
366 __pkgsplit_cache__={}
367 def vars_from_file(mypkg, d):
369 return (None, None, None)
370 if mypkg in __pkgsplit_cache__:
371 return __pkgsplit_cache__[mypkg]
373 myfile = os.path.splitext(os.path.basename(mypkg))
374 parts = myfile[0].split('_')
375 __pkgsplit_cache__[mypkg] = parts
381 parts.extend(tmplist)
384 def set_additional_vars(file, d, include):
385 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
387 bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file)
389 src_uri = data.getVar('SRC_URI', d)
392 src_uri = data.expand(src_uri, d)
394 a = data.getVar('A', d)
396 a = data.expand(a, d).split()
402 fetch.init(src_uri.split(), d)
403 except fetch.NoMethodError:
405 except bb.MalformedUrl,e:
406 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
408 a += fetch.localpaths(d)
410 data.setVar('A', " ".join(a), d)
413 # Add us to the handlers list
414 from bb.parse import handlers
415 handlers.append({'supports': supports, 'handle': handle, 'init': init})