diff options
-rw-r--r-- | bitbake/lib/bb/tinfoil.py | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/bitbake/lib/bb/tinfoil.py b/bitbake/lib/bb/tinfoil.py index f31d7b2dee..2a51526187 100644 --- a/bitbake/lib/bb/tinfoil.py +++ b/bitbake/lib/bb/tinfoil.py | |||
@@ -2,6 +2,7 @@ | |||
2 | # | 2 | # |
3 | # Copyright (C) 2012-2017 Intel Corporation | 3 | # Copyright (C) 2012-2017 Intel Corporation |
4 | # Copyright (C) 2011 Mentor Graphics Corporation | 4 | # Copyright (C) 2011 Mentor Graphics Corporation |
5 | # Copyright (C) 2006-2012 Richard Purdie | ||
5 | # | 6 | # |
6 | # This program is free software; you can redistribute it and/or modify | 7 | # This program is free software; you can redistribute it and/or modify |
7 | # it under the terms of the GNU General Public License version 2 as | 8 | # it under the terms of the GNU General Public License version 2 as |
@@ -218,6 +219,7 @@ class Tinfoil: | |||
218 | self.ui_module = None | 219 | self.ui_module = None |
219 | self.server_connection = None | 220 | self.server_connection = None |
220 | self.recipes_parsed = False | 221 | self.recipes_parsed = False |
222 | self.quiet = 0 | ||
221 | if setup_logging: | 223 | if setup_logging: |
222 | # This is the *client-side* logger, nothing to do with | 224 | # This is the *client-side* logger, nothing to do with |
223 | # logging messages from the server | 225 | # logging messages from the server |
@@ -230,6 +232,8 @@ class Tinfoil: | |||
230 | self.shutdown() | 232 | self.shutdown() |
231 | 233 | ||
232 | def prepare(self, config_only=False, config_params=None, quiet=0, extra_features=None): | 234 | def prepare(self, config_only=False, config_params=None, quiet=0, extra_features=None): |
235 | self.quiet = quiet | ||
236 | |||
233 | if self.tracking: | 237 | if self.tracking: |
234 | extrafeatures = [bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING] | 238 | extrafeatures = [bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING] |
235 | else: | 239 | else: |
@@ -434,6 +438,156 @@ class Tinfoil: | |||
434 | """ | 438 | """ |
435 | return self.run_command('buildFile', buildfile, task, internal) | 439 | return self.run_command('buildFile', buildfile, task, internal) |
436 | 440 | ||
441 | def build_targets(self, targets, task=None, handle_events=True, extra_events=None, event_callback=None): | ||
442 | """ | ||
443 | Builds the specified targets. This is equivalent to a normal invocation | ||
444 | of bitbake. Has built-in event handling which is enabled by default and | ||
445 | can be extended if needed. | ||
446 | Parameters: | ||
447 | targets: | ||
448 | One or more targets to build. Can be a list or a | ||
449 | space-separated string. | ||
450 | task: | ||
451 | The task to run; if None then the value of BB_DEFAULT_TASK | ||
452 | will be used. Default None. | ||
453 | handle_events: | ||
454 | True to handle events in a similar way to normal bitbake | ||
455 | invocation with knotty; False to return immediately (on the | ||
456 | assumption that the caller will handle the events instead). | ||
457 | Default True. | ||
458 | extra_events: | ||
459 | An optional list of events to add to the event mask (if | ||
460 | handle_events=True). If you add events here you also need | ||
461 | to specify a callback function in event_callback that will | ||
462 | handle the additional events. Default None. | ||
463 | event_callback: | ||
464 | An optional function taking a single parameter which | ||
465 | will be called first upon receiving any event (if | ||
466 | handle_events=True) so that the caller can override or | ||
467 | extend the event handling. Default None. | ||
468 | """ | ||
469 | if isinstance(targets, str): | ||
470 | targets = targets.split() | ||
471 | if not task: | ||
472 | task = self.config_data.getVar('BB_DEFAULT_TASK') | ||
473 | |||
474 | if handle_events: | ||
475 | # A reasonable set of default events matching up with those we handle below | ||
476 | eventmask = [ | ||
477 | 'bb.event.BuildStarted', | ||
478 | 'bb.event.BuildCompleted', | ||
479 | 'logging.LogRecord', | ||
480 | 'bb.event.NoProvider', | ||
481 | 'bb.command.CommandCompleted', | ||
482 | 'bb.command.CommandFailed', | ||
483 | 'bb.build.TaskStarted', | ||
484 | 'bb.build.TaskFailed', | ||
485 | 'bb.build.TaskSucceeded', | ||
486 | 'bb.build.TaskFailedSilent', | ||
487 | 'bb.build.TaskProgress', | ||
488 | 'bb.runqueue.runQueueTaskStarted', | ||
489 | 'bb.runqueue.sceneQueueTaskStarted', | ||
490 | 'bb.event.ProcessStarted', | ||
491 | 'bb.event.ProcessProgress', | ||
492 | 'bb.event.ProcessFinished', | ||
493 | ] | ||
494 | if extra_events: | ||
495 | eventmask.extend(extra_events) | ||
496 | ret = self.set_event_mask(eventmask) | ||
497 | |||
498 | ret = self.run_command('buildTargets', targets, task) | ||
499 | if handle_events: | ||
500 | result = False | ||
501 | # Borrowed from knotty, instead somewhat hackily we use the helper | ||
502 | # as the object to store "shutdown" on | ||
503 | helper = bb.ui.uihelper.BBUIHelper() | ||
504 | # We set up logging optionally in the constructor so now we need to | ||
505 | # grab the handlers to pass to TerminalFilter | ||
506 | console = None | ||
507 | errconsole = None | ||
508 | for handler in self.logger.handlers: | ||
509 | if isinstance(handler, logging.StreamHandler): | ||
510 | if handler.stream == sys.stdout: | ||
511 | console = handler | ||
512 | elif handler.stream == sys.stderr: | ||
513 | errconsole = handler | ||
514 | format_str = "%(levelname)s: %(message)s" | ||
515 | format = bb.msg.BBLogFormatter(format_str) | ||
516 | helper.shutdown = 0 | ||
517 | parseprogress = None | ||
518 | termfilter = bb.ui.knotty.TerminalFilter(helper, helper, console, errconsole, format, quiet=self.quiet) | ||
519 | try: | ||
520 | while True: | ||
521 | try: | ||
522 | event = self.wait_event(0.25) | ||
523 | if event: | ||
524 | if event_callback and event_callback(event): | ||
525 | continue | ||
526 | if helper.eventHandler(event): | ||
527 | continue | ||
528 | if isinstance(event, bb.event.ProcessStarted): | ||
529 | if self.quiet > 1: | ||
530 | continue | ||
531 | parseprogress = bb.ui.knotty.new_progress(event.processname, event.total) | ||
532 | parseprogress.start(False) | ||
533 | continue | ||
534 | if isinstance(event, bb.event.ProcessProgress): | ||
535 | if self.quiet > 1: | ||
536 | continue | ||
537 | if parseprogress: | ||
538 | parseprogress.update(event.progress) | ||
539 | else: | ||
540 | bb.warn("Got ProcessProgress event for someting that never started?") | ||
541 | continue | ||
542 | if isinstance(event, bb.event.ProcessFinished): | ||
543 | if self.quiet > 1: | ||
544 | continue | ||
545 | if parseprogress: | ||
546 | parseprogress.finish() | ||
547 | parseprogress = None | ||
548 | continue | ||
549 | if isinstance(event, bb.command.CommandCompleted): | ||
550 | result = True | ||
551 | break | ||
552 | if isinstance(event, bb.command.CommandFailed): | ||
553 | self.logger.error(str(event)) | ||
554 | result = False | ||
555 | break | ||
556 | if isinstance(event, logging.LogRecord): | ||
557 | if event.taskpid == 0 or event.levelno > logging.INFO: | ||
558 | self.logger.handle(event) | ||
559 | continue | ||
560 | if isinstance(event, bb.event.NoProvider): | ||
561 | self.logger.error(str(event)) | ||
562 | result = False | ||
563 | break | ||
564 | |||
565 | elif helper.shutdown > 1: | ||
566 | break | ||
567 | termfilter.updateFooter() | ||
568 | except KeyboardInterrupt: | ||
569 | termfilter.clearFooter() | ||
570 | if helper.shutdown == 1: | ||
571 | print("\nSecond Keyboard Interrupt, stopping...\n") | ||
572 | ret = self.run_command("stateForceShutdown") | ||
573 | if ret and ret[2]: | ||
574 | self.logger.error("Unable to cleanly stop: %s" % ret[2]) | ||
575 | elif helper.shutdown == 0: | ||
576 | print("\nKeyboard Interrupt, closing down...\n") | ||
577 | interrupted = True | ||
578 | ret = self.run_command("stateShutdown") | ||
579 | if ret and ret[2]: | ||
580 | self.logger.error("Unable to cleanly shutdown: %s" % ret[2]) | ||
581 | helper.shutdown = helper.shutdown + 1 | ||
582 | termfilter.clearFooter() | ||
583 | finally: | ||
584 | termfilter.finish() | ||
585 | if helper.failed_tasks: | ||
586 | result = False | ||
587 | return result | ||
588 | else: | ||
589 | return ret | ||
590 | |||
437 | def shutdown(self): | 591 | def shutdown(self): |
438 | if self.server_connection: | 592 | if self.server_connection: |
439 | self.run_command('clientComplete') | 593 | self.run_command('clientComplete') |