event.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. # ex:ts=4:sw=4:sts=4:et
  2. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  3. """
  4. BitBake 'Event' implementation
  5. Classes and functions for manipulating 'events' in the
  6. BitBake build tools.
  7. """
  8. # Copyright (C) 2003, 2004 Chris Larson
  9. #
  10. # This program is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License version 2 as
  12. # published by the Free Software Foundation.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License along
  20. # with this program; if not, write to the Free Software Foundation, Inc.,
  21. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  22. import os, sys
  23. import warnings
  24. import bb.utils
  25. import pickle
  26. # This is the pid for which we should generate the event. This is set when
  27. # the runqueue forks off.
  28. worker_pid = 0
  29. worker_pipe = None
  30. class Event:
  31. """Base class for events"""
  32. def __init__(self):
  33. self.pid = worker_pid
  34. NotHandled = 0
  35. Handled = 1
  36. Registered = 10
  37. AlreadyRegistered = 14
  38. # Internal
  39. _handlers = {}
  40. _ui_handlers = {}
  41. _ui_handler_seq = 0
  42. # For compatibility
  43. bb.utils._context["NotHandled"] = NotHandled
  44. bb.utils._context["Handled"] = Handled
  45. def fire_class_handlers(event, d):
  46. import bb.msg
  47. if isinstance(event, bb.msg.MsgBase):
  48. return
  49. for handler in _handlers:
  50. h = _handlers[handler]
  51. event.data = d
  52. if type(h).__name__ == "code":
  53. locals = {"e": event}
  54. bb.utils.simple_exec(h, locals)
  55. ret = bb.utils.better_eval("tmpHandler(e)", locals)
  56. if ret is not None:
  57. warnings.warn("Using Handled/NotHandled in event handlers is deprecated",
  58. DeprecationWarning, stacklevel = 2)
  59. else:
  60. h(event)
  61. del event.data
  62. def fire_ui_handlers(event, d):
  63. errors = []
  64. for h in _ui_handlers:
  65. #print "Sending event %s" % event
  66. try:
  67. # We use pickle here since it better handles object instances
  68. # which xmlrpc's marshaller does not. Events *must* be serializable
  69. # by pickle.
  70. _ui_handlers[h].event.send((pickle.dumps(event)))
  71. except:
  72. errors.append(h)
  73. for h in errors:
  74. del _ui_handlers[h]
  75. def fire(event, d):
  76. """Fire off an Event"""
  77. # We can fire class handlers in the worker process context and this is
  78. # desired so they get the task based datastore.
  79. # UI handlers need to be fired in the server context so we defer this. They
  80. # don't have a datastore so the datastore context isn't a problem.
  81. fire_class_handlers(event, d)
  82. if worker_pid != 0:
  83. worker_fire(event, d)
  84. else:
  85. fire_ui_handlers(event, d)
  86. def worker_fire(event, d):
  87. data = "<event>" + pickle.dumps(event) + "</event>"
  88. try:
  89. if os.write(worker_pipe, data) != len (data):
  90. print("Error sending event to server (short write)")
  91. except OSError:
  92. sys.exit(1)
  93. def fire_from_worker(event, d):
  94. if not event.startswith("<event>") or not event.endswith("</event>"):
  95. print("Error, not an event")
  96. return
  97. event = pickle.loads(event[7:-8])
  98. fire_ui_handlers(event, d)
  99. def register(name, handler):
  100. """Register an Event handler"""
  101. # already registered
  102. if name in _handlers:
  103. return AlreadyRegistered
  104. if handler is not None:
  105. # handle string containing python code
  106. if type(handler).__name__ == "str":
  107. tmp = "def tmpHandler(e):\n%s" % handler
  108. comp = bb.utils.better_compile(tmp, "tmpHandler(e)", "bb.event._registerCode")
  109. _handlers[name] = comp
  110. else:
  111. _handlers[name] = handler
  112. return Registered
  113. def remove(name, handler):
  114. """Remove an Event handler"""
  115. _handlers.pop(name)
  116. def register_UIHhandler(handler):
  117. bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1
  118. _ui_handlers[_ui_handler_seq] = handler
  119. return _ui_handler_seq
  120. def unregister_UIHhandler(handlerNum):
  121. if handlerNum in _ui_handlers:
  122. del _ui_handlers[handlerNum]
  123. return
  124. def getName(e):
  125. """Returns the name of a class or class instance"""
  126. if getattr(e, "__name__", None) == None:
  127. return e.__class__.__name__
  128. else:
  129. return e.__name__
  130. class ConfigParsed(Event):
  131. """Configuration Parsing Complete"""
  132. class RecipeParsed(Event):
  133. """ Recipe Parsing Complete """
  134. def __init__(self, fn):
  135. self.fn = fn
  136. Event.__init__(self)
  137. class StampUpdate(Event):
  138. """Trigger for any adjustment of the stamp files to happen"""
  139. def __init__(self, targets, stampfns):
  140. self._targets = targets
  141. self._stampfns = stampfns
  142. Event.__init__(self)
  143. def getStampPrefix(self):
  144. return self._stampfns
  145. def getTargets(self):
  146. return self._targets
  147. stampPrefix = property(getStampPrefix)
  148. targets = property(getTargets)
  149. class BuildBase(Event):
  150. """Base class for bbmake run events"""
  151. def __init__(self, n, p, failures = 0):
  152. self._name = n
  153. self._pkgs = p
  154. Event.__init__(self)
  155. self._failures = failures
  156. def getPkgs(self):
  157. return self._pkgs
  158. def setPkgs(self, pkgs):
  159. self._pkgs = pkgs
  160. def getName(self):
  161. return self._name
  162. def setName(self, name):
  163. self._name = name
  164. def getCfg(self):
  165. return self.data
  166. def setCfg(self, cfg):
  167. self.data = cfg
  168. def getFailures(self):
  169. """
  170. Return the number of failed packages
  171. """
  172. return self._failures
  173. pkgs = property(getPkgs, setPkgs, None, "pkgs property")
  174. name = property(getName, setName, None, "name property")
  175. cfg = property(getCfg, setCfg, None, "cfg property")
  176. class BuildStarted(BuildBase):
  177. """bbmake build run started"""
  178. class BuildCompleted(BuildBase):
  179. """bbmake build run completed"""
  180. class NoProvider(Event):
  181. """No Provider for an Event"""
  182. def __init__(self, item, runtime=False, dependees=None):
  183. Event.__init__(self)
  184. self._item = item
  185. self._runtime = runtime
  186. self._dependees = dependees
  187. def getItem(self):
  188. return self._item
  189. def isRuntime(self):
  190. return self._runtime
  191. class MultipleProviders(Event):
  192. """Multiple Providers"""
  193. def __init__(self, item, candidates, runtime = False):
  194. Event.__init__(self)
  195. self._item = item
  196. self._candidates = candidates
  197. self._is_runtime = runtime
  198. def isRuntime(self):
  199. """
  200. Is this a runtime issue?
  201. """
  202. return self._is_runtime
  203. def getItem(self):
  204. """
  205. The name for the to be build item
  206. """
  207. return self._item
  208. def getCandidates(self):
  209. """
  210. Get the possible Candidates for a PROVIDER.
  211. """
  212. return self._candidates
  213. class ParseProgress(Event):
  214. """
  215. Parsing Progress Event
  216. """
  217. def __init__(self, cached, parsed, skipped, masked, virtuals, errors, total):
  218. Event.__init__(self)
  219. self.cached = cached
  220. self.parsed = parsed
  221. self.skipped = skipped
  222. self.virtuals = virtuals
  223. self.masked = masked
  224. self.errors = errors
  225. self.sofar = cached + parsed
  226. self.total = total
  227. class DepTreeGenerated(Event):
  228. """
  229. Event when a dependency tree has been generated
  230. """
  231. def __init__(self, depgraph):
  232. Event.__init__(self)
  233. self._depgraph = depgraph