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') |
