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 debug, data, fetch, fatal, 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 __parsed_methods__ = methodpool.get_parsed_dict()
50 localfn = localpath(fn, d)
51 return localfn[-3:] == ".bb" or localfn[-8:] == ".bbclass" or localfn[-4:] == ".inc"
53 def inherit(files, d):
54 __inherit_cache = data.getVar('__inherit_cache', d) or ""
58 file = data.expand(f, d)
59 if file[0] != "/" and file[-8:] != ".bbclass":
60 file = os.path.join('classes', '%s.bbclass' % file)
62 if not file in __inherit_cache.split():
63 debug(2, "BB %s:%d: inheriting %s" % (fn, lineno, file))
64 __inherit_cache += " %s" % file
66 data.setVar('__inherit_cache', __inherit_cache, d)
69 def handle(fn, d, include = 0):
70 global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __bbpath_found__, __residue__
78 debug(2, "BB " + fn + ": handle(data)")
80 debug(2, "BB " + fn + ": handle(data, include)")
82 (root, ext) = os.path.splitext(os.path.basename(fn))
83 base_name = "%s%s" % (root,ext)
88 classes.append(__classname__)
91 oldfile = data.getVar('FILE', d)
96 bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
97 if not os.path.isabs(fn):
100 p = data.expand(p, d)
101 j = os.path.join(p, fn)
102 if os.access(j, os.R_OK):
107 raise IOError("file not found")
112 if ext != ".bbclass":
113 bbpath.insert(0, os.path.dirname(abs_fn))
114 data.setVar('BBPATH', ":".join(bbpath), d)
117 bb.parse.mark_dependency(d, abs_fn)
119 if ext != ".bbclass":
120 data.setVar('FILE', fn, d)
121 i = (data.getVar("INHERIT", d, 1) or "").split()
122 if not "base" in i and __classname__ != "base":
132 feeder(lineno, s, fn, base_name, d)
134 # add a blank line to close out any python definition
135 feeder(lineno + 1, "", fn, base_name, d)
136 if ext == ".bbclass":
137 classes.remove(__classname__)
142 anonqueue = data.getVar("__anonqueue", d, 1) or []
143 for anon in anonqueue:
144 data.setVar("__anonfunc", anon["content"], d)
145 data.setVarFlags("__anonfunc", anon["flags"], d)
148 t = data.getVar('T', d)
149 data.setVar('T', '${TMPDIR}/', d)
150 build.exec_func("__anonfunc", d)
153 data.setVar('T', t, d)
155 bb.debug(1, "executing anonymous function: %s" % e)
157 data.delVar("__anonqueue", d)
158 data.delVar("__anonfunc", d)
159 set_additional_vars(fn, d, include)
163 for var in data.keys(d):
164 # try to add the handler
165 # if we added it remember the choiche
166 if data.getVarFlag(var, 'handler', d):
167 handler = data.getVar(var,d)
168 if bb.event.register(var,handler) == bb.event.Registered:
169 all_handlers[var] = handler
173 if not data.getVarFlag(var, 'task', d):
176 deps = data.getVarFlag(var, 'deps', d) or []
177 postdeps = data.getVarFlag(var, 'postdeps', d) or []
178 bb.build.add_task(var, deps, d)
180 pdeps = data.getVarFlag(p, 'deps', d) or []
182 data.setVarFlag(p, 'deps', pdeps, d)
183 bb.build.add_task(p, pdeps, d)
185 # now add the handlers
186 if not len(all_handlers) == 0:
187 data.setVar('__all_handlers__', all_handlers, d)
191 bb.data.setVar("FILE", oldfile, d)
193 # we have parsed the bb class now
194 if ext == ".bbclass" or ext == ".inc":
195 __parsed_methods__[base_name] = 1
199 def feeder(lineno, s, fn, root, d):
200 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__
204 data.setVar(__infunc__, '\n'.join(__body__), d)
205 data.setVarFlag(__infunc__, "func", 1, d)
206 if __infunc__ == "__anonymous":
207 anonqueue = bb.data.getVar("__anonqueue", d) or []
209 anonitem["content"] = bb.data.getVar("__anonymous", d)
210 anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
211 anonqueue.append(anonitem)
212 bb.data.setVar("__anonqueue", anonqueue, d)
213 bb.data.delVarFlags("__anonymous", d)
214 bb.data.delVar("__anonymous", d)
222 m = __python_func_regexp__.match(s)
227 if not root in __parsed_methods__:
228 text = '\n'.join(__body__)
229 methodpool.insert_method( root, text, fn )
230 funcs = data.getVar('__functions__', d) or {}
231 if not funcs.has_key( root ):
234 funcs[root] = "%s\n%s" % (funcs[root], text)
236 data.setVar('__functions__', funcs, d)
242 if s == '' or s[0] == '#': return # skip comments and empty lines
245 __residue__.append(s[:-1])
248 s = "".join(__residue__) + s
251 m = __func_start_regexp__.match(s)
253 __infunc__ = m.group("func") or "__anonymous"
255 if data.getVar(key, d):
256 # clean up old version of this piece of metadata, as its
257 # flags could cause problems
258 data.setVarFlag(key, 'python', None, d)
259 data.setVarFlag(key, 'fakeroot', None, d)
260 if m.group("py") is not None:
261 data.setVarFlag(key, "python", "1", d)
263 data.delVarFlag(key, "python", d)
264 if m.group("fr") is not None:
265 data.setVarFlag(key, "fakeroot", "1", d)
267 data.delVarFlag(key, "fakeroot", d)
270 m = __def_regexp__.match(s)
276 m = __export_func_regexp__.match(s)
279 n = __word__.findall(fns)
283 allvars.append(classes[-1] + "_" + f)
285 vars = [[ allvars[0], allvars[1] ]]
286 if len(classes) > 1 and classes[-2] is not None:
287 allvars.append(classes[-2] + "_" + f)
289 vars.append([allvars[2], allvars[1]])
290 vars.append([allvars[0], allvars[2]])
292 for (var, calledvar) in vars:
293 if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
296 if data.getVar(var, d):
297 data.setVarFlag(var, 'python', None, d)
298 data.setVarFlag(var, 'func', None, d)
300 for flag in [ "func", "python" ]:
301 if data.getVarFlag(calledvar, flag, d):
302 data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
303 for flag in [ "dirs" ]:
304 if data.getVarFlag(var, flag, d):
305 data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
307 if data.getVarFlag(calledvar, "python", d):
308 data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
310 data.setVar(var, "\t" + calledvar + "\n", d)
311 data.setVarFlag(var, 'export_func', '1', d)
315 m = __addtask_regexp__.match(s)
317 func = m.group("func")
318 before = m.group("before")
319 after = m.group("after")
324 data.setVarFlag(var, "task", 1, d)
326 if after is not None:
327 # set up deps for function
328 data.setVarFlag(var, "deps", after.split(), d)
329 if before is not None:
330 # set up things that depend on this func
331 data.setVarFlag(var, "postdeps", before.split(), d)
334 m = __addhandler_regexp__.match(s)
337 hs = __word__.findall(fns)
339 data.setVarFlag(h, "handler", 1, d)
342 m = __inherit_regexp__.match(s)
346 n = __word__.findall(files)
350 from bb.parse import ConfHandler
351 return ConfHandler.feeder(lineno, s, fn, d)
353 __pkgsplit_cache__={}
354 def vars_from_file(mypkg, d):
356 return (None, None, None)
357 if mypkg in __pkgsplit_cache__:
358 return __pkgsplit_cache__[mypkg]
360 myfile = os.path.splitext(os.path.basename(mypkg))
361 parts = myfile[0].split('_')
362 __pkgsplit_cache__[mypkg] = parts
368 parts.extend(tmplist)
371 def set_additional_vars(file, d, include):
372 """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
374 debug(2,"BB %s: set_additional_vars" % file)
376 src_uri = data.getVar('SRC_URI', d)
379 src_uri = data.expand(src_uri, d)
381 a = data.getVar('A', d)
383 a = data.expand(a, d).split()
389 fetch.init(src_uri.split(), d)
390 except fetch.NoMethodError:
392 except bb.MalformedUrl,e:
393 raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
395 a += fetch.localpaths(d)
397 data.setVar('A', " ".join(a), d)
400 # Add us to the handlers list
401 from bb.parse import handlers
402 handlers.append({'supports': supports, 'handle': handle, 'init': init})