summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2017-07-19 11:56:06 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2017-07-21 08:41:12 +0100
commit7eb654cb4d82b54e3e4df0a57face61063b72c45 (patch)
treef1d3e07fadfa211cfb832295847ac771aaa80d9c /bitbake
parente1285712fa634e2d88f263fa9aa624bdcd22b3fa (diff)
downloadpoky-7eb654cb4d82b54e3e4df0a57face61063b72c45.tar.gz
bitbake: tinfoil: add functionality for running full builds
Up to this point, if you wanted to run build tasks in the normal way they get run from a python script, there was no other way than to shell out to bitbake. Worse than that, you couldn't have tinfoil active during that because only one bitbake instance could be running at once. As long as we're prepared to handle the events produced, we can create a wrapper around calling the buildTargets command. Borrow code from knotty to do this in such a way that we get the expected running task display (courtesy of TermFilter) and Ctrl+C handling. (Bitbake rev: 43761eee756be52a1021be53a40dc591a6c35fa7) Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/lib/bb/tinfoil.py154
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')