BBHandler.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. data.setVar('__inherit_cache', __inherit_cache, d)
  63. include(fn, file, d, "inherit")
  64. __inherit_cache = data.getVar('__inherit_cache', d) or []
  65. def handle(fn, d, include = 0):
  66. global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __infunc__, __body__, __residue__
  67. __body__ = []
  68. __infunc__ = ""
  69. __classname__ = ""
  70. __residue__ = []
  71. if include == 0:
  72. bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data)")
  73. else:
  74. bb.msg.debug(2, bb.msg.domain.Parsing, "BB " + fn + ": handle(data, include)")
  75. (root, ext) = os.path.splitext(os.path.basename(fn))
  76. base_name = "%s%s" % (root,ext)
  77. init(d)
  78. if ext == ".bbclass":
  79. __classname__ = root
  80. classes.append(__classname__)
  81. if include != 0:
  82. oldfile = data.getVar('FILE', d)
  83. else:
  84. oldfile = None
  85. fn = obtain(fn, d)
  86. bbpath = (data.getVar('BBPATH', d, 1) or '').split(':')
  87. if not os.path.isabs(fn):
  88. f = None
  89. for p in bbpath:
  90. j = os.path.join(p, fn)
  91. if os.access(j, os.R_OK):
  92. abs_fn = j
  93. f = open(j, 'r')
  94. break
  95. if f is None:
  96. raise IOError("file not found")
  97. else:
  98. f = open(fn,'r')
  99. abs_fn = fn
  100. if ext != ".bbclass":
  101. bbpath.insert(0, os.path.dirname(abs_fn))
  102. data.setVar('BBPATH', ":".join(bbpath), d)
  103. if include:
  104. bb.parse.mark_dependency(d, abs_fn)
  105. if ext != ".bbclass":
  106. data.setVar('FILE', fn, d)
  107. i = (data.getVar("INHERIT", d, 1) or "").split()
  108. if not "base" in i and __classname__ != "base":
  109. i[0:0] = ["base"]
  110. inherit(i, d)
  111. lineno = 0
  112. while 1:
  113. lineno = lineno + 1
  114. s = f.readline()
  115. if not s: break
  116. s = s.rstrip()
  117. feeder(lineno, s, fn, base_name, d)
  118. if __inpython__:
  119. # add a blank line to close out any python definition
  120. feeder(IN_PYTHON_EOF, "", fn, base_name, d)
  121. if ext == ".bbclass":
  122. classes.remove(__classname__)
  123. else:
  124. if include == 0:
  125. data.expandKeys(d)
  126. data.update_data(d)
  127. anonqueue = data.getVar("__anonqueue", d, 1) or []
  128. body = [x['content'] for x in anonqueue]
  129. flag = { 'python' : 1, 'func' : 1 }
  130. data.setVar("__anonfunc", "\n".join(body), d)
  131. data.setVarFlags("__anonfunc", flag, d)
  132. from bb import build
  133. try:
  134. t = data.getVar('T', d)
  135. data.setVar('T', '${TMPDIR}/', d)
  136. build.exec_func("__anonfunc", d)
  137. data.delVar('T', d)
  138. if t:
  139. data.setVar('T', t, d)
  140. except Exception, e:
  141. bb.msg.debug(1, bb.msg.domain.Parsing, "Exception when executing anonymous function: %s" % e)
  142. raise
  143. data.delVar("__anonqueue", d)
  144. data.delVar("__anonfunc", d)
  145. set_additional_vars(fn, d, include)
  146. data.update_data(d)
  147. all_handlers = {}
  148. for var in data.getVar('__BBHANDLERS', d) or []:
  149. # try to add the handler
  150. # if we added it remember the choiche
  151. handler = data.getVar(var,d)
  152. if bb.event.register(var,handler) == bb.event.Registered:
  153. all_handlers[var] = handler
  154. tasklist = {}
  155. for var in data.getVar('__BBTASKS', d) or []:
  156. if var not in tasklist:
  157. tasklist[var] = []
  158. deps = data.getVarFlag(var, 'deps', d) or []
  159. for p in deps:
  160. if p not in tasklist[var]:
  161. tasklist[var].append(p)
  162. postdeps = data.getVarFlag(var, 'postdeps', d) or []
  163. for p in postdeps:
  164. if p not in tasklist:
  165. tasklist[p] = []
  166. if var not in tasklist[p]:
  167. tasklist[p].append(var)
  168. bb.build.add_tasks(tasklist, d)
  169. # now add the handlers
  170. if not len(all_handlers) == 0:
  171. data.setVar('__all_handlers__', all_handlers, d)
  172. bbpath.pop(0)
  173. if oldfile:
  174. bb.data.setVar("FILE", oldfile, d)
  175. # we have parsed the bb class now
  176. if ext == ".bbclass" or ext == ".inc":
  177. __parsed_methods__[base_name] = 1
  178. return d
  179. def feeder(lineno, s, fn, root, d):
  180. global __func_start_regexp__, __inherit_regexp__, __export_func_regexp__, __addtask_regexp__, __addhandler_regexp__, __def_regexp__, __python_func_regexp__, __inpython__,__infunc__, __body__, classes, bb, __residue__
  181. if __infunc__:
  182. if s == '}':
  183. __body__.append('')
  184. data.setVar(__infunc__, '\n'.join(__body__), d)
  185. data.setVarFlag(__infunc__, "func", 1, d)
  186. if __infunc__ == "__anonymous":
  187. anonqueue = bb.data.getVar("__anonqueue", d) or []
  188. anonitem = {}
  189. anonitem["content"] = bb.data.getVar("__anonymous", d)
  190. anonitem["flags"] = bb.data.getVarFlags("__anonymous", d)
  191. anonqueue.append(anonitem)
  192. bb.data.setVar("__anonqueue", anonqueue, d)
  193. bb.data.delVarFlags("__anonymous", d)
  194. bb.data.delVar("__anonymous", d)
  195. __infunc__ = ""
  196. __body__ = []
  197. else:
  198. __body__.append(s)
  199. return
  200. if __inpython__:
  201. m = __python_func_regexp__.match(s)
  202. if m and lineno != IN_PYTHON_EOF:
  203. __body__.append(s)
  204. return
  205. else:
  206. # Note we will add root to parsedmethods after having parse
  207. # 'this' file. This means we will not parse methods from
  208. # bb classes twice
  209. if not root in __parsed_methods__:
  210. text = '\n'.join(__body__)
  211. methodpool.insert_method( root, text, fn )
  212. funcs = data.getVar('__functions__', d) or {}
  213. if not funcs.has_key( root ):
  214. funcs[root] = text
  215. else:
  216. funcs[root] = "%s\n%s" % (funcs[root], text)
  217. data.setVar('__functions__', funcs, d)
  218. __body__ = []
  219. __inpython__ = False
  220. if lineno == IN_PYTHON_EOF:
  221. return
  222. # fall through
  223. if s == '' or s[0] == '#': return # skip comments and empty lines
  224. if s[-1] == '\\':
  225. __residue__.append(s[:-1])
  226. return
  227. s = "".join(__residue__) + s
  228. __residue__ = []
  229. m = __func_start_regexp__.match(s)
  230. if m:
  231. __infunc__ = m.group("func") or "__anonymous"
  232. key = __infunc__
  233. if data.getVar(key, d):
  234. # clean up old version of this piece of metadata, as its
  235. # flags could cause problems
  236. data.setVarFlag(key, 'python', None, d)
  237. data.setVarFlag(key, 'fakeroot', None, d)
  238. if m.group("py") is not None:
  239. data.setVarFlag(key, "python", "1", d)
  240. else:
  241. data.delVarFlag(key, "python", d)
  242. if m.group("fr") is not None:
  243. data.setVarFlag(key, "fakeroot", "1", d)
  244. else:
  245. data.delVarFlag(key, "fakeroot", d)
  246. return
  247. m = __def_regexp__.match(s)
  248. if m:
  249. __body__.append(s)
  250. __inpython__ = True
  251. return
  252. m = __export_func_regexp__.match(s)
  253. if m:
  254. fns = m.group(1)
  255. n = __word__.findall(fns)
  256. for f in n:
  257. allvars = []
  258. allvars.append(f)
  259. allvars.append(classes[-1] + "_" + f)
  260. vars = [[ allvars[0], allvars[1] ]]
  261. if len(classes) > 1 and classes[-2] is not None:
  262. allvars.append(classes[-2] + "_" + f)
  263. vars = []
  264. vars.append([allvars[2], allvars[1]])
  265. vars.append([allvars[0], allvars[2]])
  266. for (var, calledvar) in vars:
  267. if data.getVar(var, d) and not data.getVarFlag(var, 'export_func', d):
  268. continue
  269. if data.getVar(var, d):
  270. data.setVarFlag(var, 'python', None, d)
  271. data.setVarFlag(var, 'func', None, d)
  272. for flag in [ "func", "python" ]:
  273. if data.getVarFlag(calledvar, flag, d):
  274. data.setVarFlag(var, flag, data.getVarFlag(calledvar, flag, d), d)
  275. for flag in [ "dirs" ]:
  276. if data.getVarFlag(var, flag, d):
  277. data.setVarFlag(calledvar, flag, data.getVarFlag(var, flag, d), d)
  278. if data.getVarFlag(calledvar, "python", d):
  279. data.setVar(var, "\tbb.build.exec_func('" + calledvar + "', d)\n", d)
  280. else:
  281. data.setVar(var, "\t" + calledvar + "\n", d)
  282. data.setVarFlag(var, 'export_func', '1', d)
  283. return
  284. m = __addtask_regexp__.match(s)
  285. if m:
  286. func = m.group("func")
  287. before = m.group("before")
  288. after = m.group("after")
  289. if func is None:
  290. return
  291. var = "do_" + func
  292. data.setVarFlag(var, "task", 1, d)
  293. bbtasks = data.getVar('__BBTASKS', d) or []
  294. bbtasks.append(var)
  295. data.setVar('__BBTASKS', bbtasks, d)
  296. if after is not None:
  297. # set up deps for function
  298. data.setVarFlag(var, "deps", after.split(), d)
  299. if before is not None:
  300. # set up things that depend on this func
  301. data.setVarFlag(var, "postdeps", before.split(), d)
  302. return
  303. m = __addhandler_regexp__.match(s)
  304. if m:
  305. fns = m.group(1)
  306. hs = __word__.findall(fns)
  307. bbhands = data.getVar('__BBHANDLERS', d) or []
  308. for h in hs:
  309. bbhands.append(h)
  310. data.setVarFlag(h, "handler", 1, d)
  311. data.setVar('__BBHANDLERS', bbhands, d)
  312. return
  313. m = __inherit_regexp__.match(s)
  314. if m:
  315. files = m.group(1)
  316. n = __word__.findall(files)
  317. inherit(n, d)
  318. return
  319. from bb.parse import ConfHandler
  320. return ConfHandler.feeder(lineno, s, fn, d)
  321. __pkgsplit_cache__={}
  322. def vars_from_file(mypkg, d):
  323. if not mypkg:
  324. return (None, None, None)
  325. if mypkg in __pkgsplit_cache__:
  326. return __pkgsplit_cache__[mypkg]
  327. myfile = os.path.splitext(os.path.basename(mypkg))
  328. parts = myfile[0].split('_')
  329. __pkgsplit_cache__[mypkg] = parts
  330. if len(parts) > 3:
  331. raise ParseError("Unable to generate default variables from the filename: %s (too many underscores)" % mypkg)
  332. exp = 3 - len(parts)
  333. tmplist = []
  334. while exp != 0:
  335. exp -= 1
  336. tmplist.append(None)
  337. parts.extend(tmplist)
  338. return parts
  339. def set_additional_vars(file, d, include):
  340. """Deduce rest of variables, e.g. ${A} out of ${SRC_URI}"""
  341. return
  342. # Nothing seems to use this variable
  343. #bb.msg.debug(2, bb.msg.domain.Parsing, "BB %s: set_additional_vars" % file)
  344. #src_uri = data.getVar('SRC_URI', d, 1)
  345. #if not src_uri:
  346. # return
  347. #a = (data.getVar('A', d, 1) or '').split()
  348. #from bb import fetch
  349. #try:
  350. # ud = fetch.init(src_uri.split(), d)
  351. # a += fetch.localpaths(d, ud)
  352. #except fetch.NoMethodError:
  353. # pass
  354. #except bb.MalformedUrl,e:
  355. # raise ParseError("Unable to generate local paths for SRC_URI due to malformed uri: %s" % e)
  356. #del fetch
  357. #data.setVar('A', " ".join(a), d)
  358. # Add us to the handlers list
  359. from bb.parse import handlers
  360. handlers.append({'supports': supports, 'handle': handle, 'init': init})
  361. del handlers