BBHandler.py 12 KB

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