diff options
Diffstat (limited to 'bitbake/lib/bb/event.py')
-rw-r--r-- | bitbake/lib/bb/event.py | 179 |
1 files changed, 111 insertions, 68 deletions
diff --git a/bitbake/lib/bb/event.py b/bitbake/lib/bb/event.py index 23e1f3187b..4761c86880 100644 --- a/bitbake/lib/bb/event.py +++ b/bitbake/lib/bb/event.py | |||
@@ -40,7 +40,7 @@ class HeartbeatEvent(Event): | |||
40 | """Triggered at regular time intervals of 10 seconds. Other events can fire much more often | 40 | """Triggered at regular time intervals of 10 seconds. Other events can fire much more often |
41 | (runQueueTaskStarted when there are many short tasks) or not at all for long periods | 41 | (runQueueTaskStarted when there are many short tasks) or not at all for long periods |
42 | of time (again runQueueTaskStarted, when there is just one long-running task), so this | 42 | of time (again runQueueTaskStarted, when there is just one long-running task), so this |
43 | event is more suitable for doing some task-independent work occassionally.""" | 43 | event is more suitable for doing some task-independent work occasionally.""" |
44 | def __init__(self, time): | 44 | def __init__(self, time): |
45 | Event.__init__(self) | 45 | Event.__init__(self) |
46 | self.time = time | 46 | self.time = time |
@@ -68,29 +68,39 @@ _catchall_handlers = {} | |||
68 | _eventfilter = None | 68 | _eventfilter = None |
69 | _uiready = False | 69 | _uiready = False |
70 | _thread_lock = threading.Lock() | 70 | _thread_lock = threading.Lock() |
71 | _thread_lock_enabled = False | 71 | _heartbeat_enabled = False |
72 | 72 | _should_exit = threading.Event() | |
73 | if hasattr(__builtins__, '__setitem__'): | ||
74 | builtins = __builtins__ | ||
75 | else: | ||
76 | builtins = __builtins__.__dict__ | ||
77 | 73 | ||
78 | def enable_threadlock(): | 74 | def enable_threadlock(): |
79 | global _thread_lock_enabled | 75 | # Always needed now |
80 | _thread_lock_enabled = True | 76 | return |
81 | 77 | ||
82 | def disable_threadlock(): | 78 | def disable_threadlock(): |
83 | global _thread_lock_enabled | 79 | # Always needed now |
84 | _thread_lock_enabled = False | 80 | return |
81 | |||
82 | def enable_heartbeat(): | ||
83 | global _heartbeat_enabled | ||
84 | _heartbeat_enabled = True | ||
85 | |||
86 | def disable_heartbeat(): | ||
87 | global _heartbeat_enabled | ||
88 | _heartbeat_enabled = False | ||
89 | |||
90 | # | ||
91 | # In long running code, this function should be called periodically | ||
92 | # to check if we should exit due to an interuption (.e.g Ctrl+C from the UI) | ||
93 | # | ||
94 | def check_for_interrupts(d): | ||
95 | global _should_exit | ||
96 | if _should_exit.is_set(): | ||
97 | bb.warn("Exiting due to interrupt.") | ||
98 | raise bb.BBHandledException() | ||
85 | 99 | ||
86 | def execute_handler(name, handler, event, d): | 100 | def execute_handler(name, handler, event, d): |
87 | event.data = d | 101 | event.data = d |
88 | addedd = False | ||
89 | if 'd' not in builtins: | ||
90 | builtins['d'] = d | ||
91 | addedd = True | ||
92 | try: | 102 | try: |
93 | ret = handler(event) | 103 | ret = handler(event, d) |
94 | except (bb.parse.SkipRecipe, bb.BBHandledException): | 104 | except (bb.parse.SkipRecipe, bb.BBHandledException): |
95 | raise | 105 | raise |
96 | except Exception: | 106 | except Exception: |
@@ -104,8 +114,7 @@ def execute_handler(name, handler, event, d): | |||
104 | raise | 114 | raise |
105 | finally: | 115 | finally: |
106 | del event.data | 116 | del event.data |
107 | if addedd: | 117 | |
108 | del builtins['d'] | ||
109 | 118 | ||
110 | def fire_class_handlers(event, d): | 119 | def fire_class_handlers(event, d): |
111 | if isinstance(event, logging.LogRecord): | 120 | if isinstance(event, logging.LogRecord): |
@@ -118,7 +127,7 @@ def fire_class_handlers(event, d): | |||
118 | if _eventfilter: | 127 | if _eventfilter: |
119 | if not _eventfilter(name, handler, event, d): | 128 | if not _eventfilter(name, handler, event, d): |
120 | continue | 129 | continue |
121 | if d and not name in (d.getVar("__BBHANDLERS_MC") or []): | 130 | if d is not None and not name in (d.getVar("__BBHANDLERS_MC") or set()): |
122 | continue | 131 | continue |
123 | execute_handler(name, handler, event, d) | 132 | execute_handler(name, handler, event, d) |
124 | 133 | ||
@@ -132,8 +141,14 @@ def print_ui_queue(): | |||
132 | if not _uiready: | 141 | if not _uiready: |
133 | from bb.msg import BBLogFormatter | 142 | from bb.msg import BBLogFormatter |
134 | # Flush any existing buffered content | 143 | # Flush any existing buffered content |
135 | sys.stdout.flush() | 144 | try: |
136 | sys.stderr.flush() | 145 | sys.stdout.flush() |
146 | except: | ||
147 | pass | ||
148 | try: | ||
149 | sys.stderr.flush() | ||
150 | except: | ||
151 | pass | ||
137 | stdout = logging.StreamHandler(sys.stdout) | 152 | stdout = logging.StreamHandler(sys.stdout) |
138 | stderr = logging.StreamHandler(sys.stderr) | 153 | stderr = logging.StreamHandler(sys.stderr) |
139 | formatter = BBLogFormatter("%(levelname)s: %(message)s") | 154 | formatter = BBLogFormatter("%(levelname)s: %(message)s") |
@@ -174,36 +189,30 @@ def print_ui_queue(): | |||
174 | 189 | ||
175 | def fire_ui_handlers(event, d): | 190 | def fire_ui_handlers(event, d): |
176 | global _thread_lock | 191 | global _thread_lock |
177 | global _thread_lock_enabled | ||
178 | 192 | ||
179 | if not _uiready: | 193 | if not _uiready: |
180 | # No UI handlers registered yet, queue up the messages | 194 | # No UI handlers registered yet, queue up the messages |
181 | ui_queue.append(event) | 195 | ui_queue.append(event) |
182 | return | 196 | return |
183 | 197 | ||
184 | if _thread_lock_enabled: | 198 | with bb.utils.lock_timeout(_thread_lock): |
185 | _thread_lock.acquire() | 199 | errors = [] |
186 | 200 | for h in _ui_handlers: | |
187 | errors = [] | 201 | #print "Sending event %s" % event |
188 | for h in _ui_handlers: | 202 | try: |
189 | #print "Sending event %s" % event | 203 | if not _ui_logfilters[h].filter(event): |
190 | try: | 204 | continue |
191 | if not _ui_logfilters[h].filter(event): | 205 | # We use pickle here since it better handles object instances |
192 | continue | 206 | # which xmlrpc's marshaller does not. Events *must* be serializable |
193 | # We use pickle here since it better handles object instances | 207 | # by pickle. |
194 | # which xmlrpc's marshaller does not. Events *must* be serializable | 208 | if hasattr(_ui_handlers[h].event, "sendpickle"): |
195 | # by pickle. | 209 | _ui_handlers[h].event.sendpickle((pickle.dumps(event))) |
196 | if hasattr(_ui_handlers[h].event, "sendpickle"): | 210 | else: |
197 | _ui_handlers[h].event.sendpickle((pickle.dumps(event))) | 211 | _ui_handlers[h].event.send(event) |
198 | else: | 212 | except: |
199 | _ui_handlers[h].event.send(event) | 213 | errors.append(h) |
200 | except: | 214 | for h in errors: |
201 | errors.append(h) | 215 | del _ui_handlers[h] |
202 | for h in errors: | ||
203 | del _ui_handlers[h] | ||
204 | |||
205 | if _thread_lock_enabled: | ||
206 | _thread_lock.release() | ||
207 | 216 | ||
208 | def fire(event, d): | 217 | def fire(event, d): |
209 | """Fire off an Event""" | 218 | """Fire off an Event""" |
@@ -232,26 +241,31 @@ noop = lambda _: None | |||
232 | def register(name, handler, mask=None, filename=None, lineno=None, data=None): | 241 | def register(name, handler, mask=None, filename=None, lineno=None, data=None): |
233 | """Register an Event handler""" | 242 | """Register an Event handler""" |
234 | 243 | ||
235 | if data and data.getVar("BB_CURRENT_MC"): | 244 | if data is not None and data.getVar("BB_CURRENT_MC"): |
236 | mc = data.getVar("BB_CURRENT_MC") | 245 | mc = data.getVar("BB_CURRENT_MC") |
237 | name = '%s%s' % (mc.replace('-', '_'), name) | 246 | name = '%s%s' % (mc.replace('-', '_'), name) |
238 | 247 | ||
239 | # already registered | 248 | # already registered |
240 | if name in _handlers: | 249 | if name in _handlers: |
250 | if data is not None: | ||
251 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set()) | ||
252 | bbhands_mc.add(name) | ||
253 | data.setVar("__BBHANDLERS_MC", bbhands_mc) | ||
241 | return AlreadyRegistered | 254 | return AlreadyRegistered |
242 | 255 | ||
243 | if handler is not None: | 256 | if handler is not None: |
244 | # handle string containing python code | 257 | # handle string containing python code |
245 | if isinstance(handler, str): | 258 | if isinstance(handler, str): |
246 | tmp = "def %s(e):\n%s" % (name, handler) | 259 | tmp = "def %s(e, d):\n%s" % (name, handler) |
260 | # Inject empty lines to make code match lineno in filename | ||
261 | if lineno is not None: | ||
262 | tmp = "\n" * (lineno-1) + tmp | ||
247 | try: | 263 | try: |
248 | code = bb.methodpool.compile_cache(tmp) | 264 | code = bb.methodpool.compile_cache(tmp) |
249 | if not code: | 265 | if not code: |
250 | if filename is None: | 266 | if filename is None: |
251 | filename = "%s(e)" % name | 267 | filename = "%s(e, d)" % name |
252 | code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST) | 268 | code = compile(tmp, filename, "exec", ast.PyCF_ONLY_AST) |
253 | if lineno is not None: | ||
254 | ast.increment_lineno(code, lineno-1) | ||
255 | code = compile(code, filename, "exec") | 269 | code = compile(code, filename, "exec") |
256 | bb.methodpool.compile_cache_add(tmp, code) | 270 | bb.methodpool.compile_cache_add(tmp, code) |
257 | except SyntaxError: | 271 | except SyntaxError: |
@@ -274,16 +288,16 @@ def register(name, handler, mask=None, filename=None, lineno=None, data=None): | |||
274 | _event_handler_map[m] = {} | 288 | _event_handler_map[m] = {} |
275 | _event_handler_map[m][name] = True | 289 | _event_handler_map[m][name] = True |
276 | 290 | ||
277 | if data: | 291 | if data is not None: |
278 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or []) | 292 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set()) |
279 | bbhands_mc.append(name) | 293 | bbhands_mc.add(name) |
280 | data.setVar("__BBHANDLERS_MC", bbhands_mc) | 294 | data.setVar("__BBHANDLERS_MC", bbhands_mc) |
281 | 295 | ||
282 | return Registered | 296 | return Registered |
283 | 297 | ||
284 | def remove(name, handler, data=None): | 298 | def remove(name, handler, data=None): |
285 | """Remove an Event handler""" | 299 | """Remove an Event handler""" |
286 | if data: | 300 | if data is not None: |
287 | if data.getVar("BB_CURRENT_MC"): | 301 | if data.getVar("BB_CURRENT_MC"): |
288 | mc = data.getVar("BB_CURRENT_MC") | 302 | mc = data.getVar("BB_CURRENT_MC") |
289 | name = '%s%s' % (mc.replace('-', '_'), name) | 303 | name = '%s%s' % (mc.replace('-', '_'), name) |
@@ -295,8 +309,8 @@ def remove(name, handler, data=None): | |||
295 | if name in _event_handler_map[event]: | 309 | if name in _event_handler_map[event]: |
296 | _event_handler_map[event].pop(name) | 310 | _event_handler_map[event].pop(name) |
297 | 311 | ||
298 | if data: | 312 | if data is not None: |
299 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or []) | 313 | bbhands_mc = (data.getVar("__BBHANDLERS_MC") or set()) |
300 | if name in bbhands_mc: | 314 | if name in bbhands_mc: |
301 | bbhands_mc.remove(name) | 315 | bbhands_mc.remove(name) |
302 | data.setVar("__BBHANDLERS_MC", bbhands_mc) | 316 | data.setVar("__BBHANDLERS_MC", bbhands_mc) |
@@ -313,21 +327,23 @@ def set_eventfilter(func): | |||
313 | _eventfilter = func | 327 | _eventfilter = func |
314 | 328 | ||
315 | def register_UIHhandler(handler, mainui=False): | 329 | def register_UIHhandler(handler, mainui=False): |
316 | bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 | 330 | with bb.utils.lock_timeout(_thread_lock): |
317 | _ui_handlers[_ui_handler_seq] = handler | 331 | bb.event._ui_handler_seq = bb.event._ui_handler_seq + 1 |
318 | level, debug_domains = bb.msg.constructLogOptions() | 332 | _ui_handlers[_ui_handler_seq] = handler |
319 | _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains) | 333 | level, debug_domains = bb.msg.constructLogOptions() |
320 | if mainui: | 334 | _ui_logfilters[_ui_handler_seq] = UIEventFilter(level, debug_domains) |
321 | global _uiready | 335 | if mainui: |
322 | _uiready = _ui_handler_seq | 336 | global _uiready |
323 | return _ui_handler_seq | 337 | _uiready = _ui_handler_seq |
338 | return _ui_handler_seq | ||
324 | 339 | ||
325 | def unregister_UIHhandler(handlerNum, mainui=False): | 340 | def unregister_UIHhandler(handlerNum, mainui=False): |
326 | if mainui: | 341 | if mainui: |
327 | global _uiready | 342 | global _uiready |
328 | _uiready = False | 343 | _uiready = False |
329 | if handlerNum in _ui_handlers: | 344 | with bb.utils.lock_timeout(_thread_lock): |
330 | del _ui_handlers[handlerNum] | 345 | if handlerNum in _ui_handlers: |
346 | del _ui_handlers[handlerNum] | ||
331 | return | 347 | return |
332 | 348 | ||
333 | def get_uihandler(): | 349 | def get_uihandler(): |
@@ -482,7 +498,7 @@ class BuildCompleted(BuildBase, OperationCompleted): | |||
482 | BuildBase.__init__(self, n, p, failures) | 498 | BuildBase.__init__(self, n, p, failures) |
483 | 499 | ||
484 | class DiskFull(Event): | 500 | class DiskFull(Event): |
485 | """Disk full case build aborted""" | 501 | """Disk full case build halted""" |
486 | def __init__(self, dev, type, freespace, mountpoint): | 502 | def __init__(self, dev, type, freespace, mountpoint): |
487 | Event.__init__(self) | 503 | Event.__init__(self) |
488 | self._dev = dev | 504 | self._dev = dev |
@@ -666,6 +682,17 @@ class ReachableStamps(Event): | |||
666 | Event.__init__(self) | 682 | Event.__init__(self) |
667 | self.stamps = stamps | 683 | self.stamps = stamps |
668 | 684 | ||
685 | class StaleSetSceneTasks(Event): | ||
686 | """ | ||
687 | An event listing setscene tasks which are 'stale' and will | ||
688 | be rerun. The metadata may use to clean up stale data. | ||
689 | tasks is a mapping of tasks and matching stale stamps. | ||
690 | """ | ||
691 | |||
692 | def __init__(self, tasks): | ||
693 | Event.__init__(self) | ||
694 | self.tasks = tasks | ||
695 | |||
669 | class FilesMatchingFound(Event): | 696 | class FilesMatchingFound(Event): |
670 | """ | 697 | """ |
671 | Event when a list of files matching the supplied pattern has | 698 | Event when a list of files matching the supplied pattern has |
@@ -749,7 +776,7 @@ class LogHandler(logging.Handler): | |||
749 | class MetadataEvent(Event): | 776 | class MetadataEvent(Event): |
750 | """ | 777 | """ |
751 | Generic event that target for OE-Core classes | 778 | Generic event that target for OE-Core classes |
752 | to report information during asynchrous execution | 779 | to report information during asynchronous execution |
753 | """ | 780 | """ |
754 | def __init__(self, eventtype, eventdata): | 781 | def __init__(self, eventtype, eventdata): |
755 | Event.__init__(self) | 782 | Event.__init__(self) |
@@ -830,3 +857,19 @@ class FindSigInfoResult(Event): | |||
830 | def __init__(self, result): | 857 | def __init__(self, result): |
831 | Event.__init__(self) | 858 | Event.__init__(self) |
832 | self.result = result | 859 | self.result = result |
860 | |||
861 | class GetTaskSignatureResult(Event): | ||
862 | """ | ||
863 | Event to return results from GetTaskSignatures command | ||
864 | """ | ||
865 | def __init__(self, sig): | ||
866 | Event.__init__(self) | ||
867 | self.sig = sig | ||
868 | |||
869 | class ParseError(Event): | ||
870 | """ | ||
871 | Event to indicate parse failed | ||
872 | """ | ||
873 | def __init__(self, msg): | ||
874 | super().__init__() | ||
875 | self._msg = msg | ||