All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jack Mitchell <ml@communistcode.co.uk>
To: openembedded-core@lists.openembedded.org
Subject: Re: [PATCH] ui/knotty: Add a footer to the build output for interactive terminals
Date: Fri, 16 Mar 2012 09:48:23 +0000	[thread overview]
Message-ID: <4F630C67.8070707@communistcode.co.uk> (raw)
In-Reply-To: <1331852164.18586.166.camel@ted>

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@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@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@embed.me.uk)
   Embedded Systems Engineer
   http://www.embed.me.uk

--




  reply	other threads:[~2012-03-16  9:56 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-15 22:56 [PATCH] ui/knotty: Add a footer to the build output for interactive terminals Richard Purdie
2012-03-16  9:48 ` Jack Mitchell [this message]
2012-03-19 11:48 ` [OE-core] " Koen Kooi
2012-03-19 11:48   ` Koen Kooi
2012-03-20 12:24 ` [OE-core] " Koen Kooi
2012-03-20 12:24   ` Koen Kooi
2012-03-21 16:19   ` [OE-core] " Martin Jansa
2012-03-21 16:19     ` [bitbake-devel] " Martin Jansa

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F630C67.8070707@communistcode.co.uk \
    --to=ml@communistcode.co.uk \
    --cc=openembedded-core@lists.openembedded.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.