BBHandler.py 14 KB

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