[OE-core] [PATCH] ui/knotty: Add a footer to the build output for interactive terminals

Jack Mitchell ml at communistcode.co.uk
Fri Mar 16 09:48:23 UTC 2012


On 15/03/12 22:56, Richard Purdie wrote:
> I've sent this before, this is an updated version with several bugfixes
> and improvements. Its a major change but one I think people will like
> overall as I hear a lot of complaints about the verbose console
> messages. v0 never got complaints so I will merge this fairly quickly
> unless there are objections.
>
> ---
> On terminals which support it, add summary information to the end of the
> build output about the number of tasks currently running and how many tasks
> we've run so far.
>
> This provides a summary at a glace of what the current state of the build is
> and what the build is currently doing which is lacking in the current UI.
>
> Also disable echo of characters on stdin since this corrupts the disable,
> particularly Crtl+C.
>
> The "waiting for X tasks" code can be merged into this code too since
> that is only useful on interactive terminals and this improves the
> readability of that output too.
>
> Improvements since v0:
>
> * The tasks are ordered in execution order.
> * The display is only updated when the list of tasks changes or there
>    is output above the footer.
> * Errors early in the init process don't corrupt the terminal
> * Running task x of y and package messages are suppressed from the console
>
> Signed-off-by: Richard Purdie<richard.purdie at linuxfoundation.org>
> ---
> diff --git a/bitbake/lib/bb/ui/knotty.py b/bitbake/lib/bb/ui/knotty.py
> index 14989d4..4a7e6b9 100644
> --- a/bitbake/lib/bb/ui/knotty.py
> +++ b/bitbake/lib/bb/ui/knotty.py
> @@ -72,6 +72,26 @@ def pluralise(singular, plural, qty):
>
>   def main(server, eventHandler):
>
> +    cuu = None
> +    stdinbackup = None
> +
> +    if interactive:
> +        import curses
> +        import termios
> +        import copy
> +        try:
> +            fd = sys.stdin.fileno()
> +            stdinbackup = termios.tcgetattr(fd)
> +            new = copy.deepcopy(stdinbackup)
> +            new[3] = new[3]&  ~termios.ECHO
> +            termios.tcsetattr(fd, termios.TCSADRAIN, new)
> +            curses.setupterm()
> +            ed = curses.tigetstr("ed")
> +            if ed:
> +                cuu = curses.tigetstr("cuu")
> +        except:
> +            cuu = None
> +
>       # Get values of variables which control our output
>       includelogs = server.runCommand(["getVariable", "BBINCLUDELOGS"])
>       loglines = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
> @@ -115,8 +135,56 @@ def main(server, eventHandler):
>       errors = 0
>       warnings = 0
>       taskfailures = []
> +    main.footer_present = False
> +    main.lastpids = []
> +
> +    def updateFooter():
> +        if not cuu:
> +            return
> +        activetasks = helper.running_tasks
> +        failedtasks = helper.failed_tasks
> +        runningpids = helper.running_pids
> +        if main.footer_present and (main.lastpids == runningpids):
> +            return
> +        if main.footer_present:
> +            clearFooter()
> +        if not activetasks:
> +            return
> +        lines = 1
> +        tasks = []
> +        for t in runningpids:
> +            tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
> +
> +        if shutdown:
> +            print("Waiting for %s running tasks to finish:" % len(activetasks))
> +        else:
> +            print("Currently %s running tasks (%s of %s):" % (len(activetasks), helper.tasknumber_current, helper.tasknumber_total))
> +        for tasknum, task in enumerate(tasks):
> +            print("%s: %s" % (tasknum, task))
> +            lines = lines + 1
> +        main.footer_present = lines
> +        main.lastpids = runningpids[:]
> +
> +    def clearFooter():
> +        if main.footer_present:
> +            lines = main.footer_present
> +            sys.stdout.write(curses.tparm(cuu, lines))
> +            sys.stdout.write(curses.tparm(ed))
> +        main.footer_present = False
> +
> +    class InteractConsoleLogFilter(logging.Filter):
> +        def filter(self, record):
> +            if record.levelno == format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("package ")):
> +                return False
> +            clearFooter()
> +            return True
> +
> +    if interactive:
> +        console.addFilter(InteractConsoleLogFilter())
> +
>       while True:
>           try:
> +            updateFooter()
>               event = eventHandler.waitEvent(0.25)
>               if event is None:
>                   if shutdown>  1:
> @@ -126,12 +194,6 @@ def main(server, eventHandler):
>               if isinstance(event, bb.runqueue.runQueueExitWait):
>                   if not shutdown:
>                       shutdown = 1
> -            if shutdown and helper.needUpdate:
> -                activetasks, failedtasks = helper.getTasks()
> -                if activetasks:
> -                    print("Waiting for %s active tasks to finish:" % len(activetasks))
> -                    for tasknum, task in enumerate(activetasks):
> -                        print("%s: %s (pid %s)" % (tasknum, activetasks[task]["title"], task))
>
>               if isinstance(event, logging.LogRecord):
>                   if event.levelno>= format.ERROR:
> @@ -151,6 +213,7 @@ def main(server, eventHandler):
>                   return_value = 1
>                   logfile = event.logfile
>                   if logfile and os.path.exists(logfile):
> +                    clearFooter()
>                       print("ERROR: Logfile of failure stored in: %s" % logfile)
>                       if includelogs and not event.errprinted:
>                           print("Log data follows:")
> @@ -281,10 +344,12 @@ def main(server, eventHandler):
>               logger.error("Unknown event: %s", event)
>
>           except EnvironmentError as ioerror:
> +            clearFooter()
>               # ignore interrupted io
>               if ioerror.args[0] == 4:
>                   pass
>           except KeyboardInterrupt:
> +            clearFooter()
>               if shutdown == 1:
>                   print("\nSecond Keyboard Interrupt, stopping...\n")
>                   server.runCommand(["stateStop"])
> @@ -315,4 +380,6 @@ def main(server, eventHandler):
>           if return_value == 0:
>               return_value = 1
>
> +    if stdinbackup:
> +        termios.tcsetattr(fd, termios.TCSADRAIN, stdinbackup)
>       return return_value
> diff --git a/bitbake/lib/bb/ui/uihelper.py b/bitbake/lib/bb/ui/uihelper.py
> index c96f381..2c78695 100644
> --- a/bitbake/lib/bb/ui/uihelper.py
> +++ b/bitbake/lib/bb/ui/uihelper.py
> @@ -23,6 +23,8 @@ class BBUIHelper:
>       def __init__(self):
>           self.needUpdate = False
>           self.running_tasks = {}
> +        # Running PIDs preserves the order tasks were executed in
> +        self.running_pids = []
>           self.failed_tasks = []
>           self.tasknumber_current = 0
>           self.tasknumber_total = 0
> @@ -30,16 +32,20 @@ class BBUIHelper:
>       def eventHandler(self, event):
>           if isinstance(event, bb.build.TaskStarted):
>               self.running_tasks[event.pid] = { 'title' : "%s %s" % (event._package, event._task) }
> +            self.running_pids.append(event.pid)
>               self.needUpdate = True
>           if isinstance(event, bb.build.TaskSucceeded):
>               del self.running_tasks[event.pid]
> +            self.running_pids.remove(event.pid)
>               self.needUpdate = True
>           if isinstance(event, bb.build.TaskFailedSilent):
>               del self.running_tasks[event.pid]
> +            self.running_pids.remove(event.pid)
>               # Don't add to the failed tasks list since this is e.g. a setscene task failure
>               self.needUpdate = True
>           if isinstance(event, bb.build.TaskFailed):
>               del self.running_tasks[event.pid]
> +            self.running_pids.remove(event.pid)
>               self.failed_tasks.append( { 'title' : "%s %s" % (event._package, event._task)})
>               self.needUpdate = True
>           if isinstance(event, bb.runqueue.runQueueTaskStarted):
>
>
>
> _______________________________________________
> Openembedded-core mailing list
> Openembedded-core at lists.openembedded.org
> http://lists.linuxtogo.org/cgi-bin/mailman/listinfo/openembedded-core

I like the look of this Richard, will make me look at bit less like an 
insane nodding dog!

Cheers,

-- 

   Jack Mitchell (jack at embed.me.uk)
   Embedded Systems Engineer
   http://www.embed.me.uk

--





More information about the Openembedded-core mailing list