[bitbake-devel] [PATCH v3 11/15] knotty: Merge knotty2 functionality into knotty
Jason Wessel
jason.wessel at windriver.com
Wed Jun 6 20:28:35 UTC 2012
The knotty 2 functionality can be activated in realtime
by pressing "t" for top mode or reverted with "0" for
normal mode.
Signed-off-by: Jason Wessel <jason.wessel at windriver.com>
---
lib/bb/ui/knotty.py | 172 ++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 150 insertions(+), 22 deletions(-)
diff --git a/lib/bb/ui/knotty.py b/lib/bb/ui/knotty.py
index 58fb8f1..765ad27 100644
--- a/lib/bb/ui/knotty.py
+++ b/lib/bb/ui/knotty.py
@@ -74,50 +74,156 @@ def pluralise(singular, plural, qty):
else:
return plural % qty
+class InteractConsoleLogFilter(logging.Filter):
+ def __init__(self, tf, format):
+ self.tf = tf
+ self.format = format
+
+ def filter(self, record):
+ if record.levelno == self.format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("package ")):
+ return False
+ self.tf.clearFooter()
+ return True
+
class TerminalFilter(object):
def __init__(self, main, helper, console, format):
+ import curses
self.main = main
+ self.console = console
self.helper = helper
+ self.topMode = False
+ self.cuu = None
+ self.interactive = sys.stdout.isatty()
+ self.footer_present = False
+ self.lastpids = []
+ self.curses = curses
+ self.confilter = InteractConsoleLogFilter(self, format)
+ self.curses_init = False
+ self.columns = 80
+
+ def cursesInit(self):
+ if self.curses_init:
+ return
+ self.curses_init = True
+ if self.interactive:
+ try:
+ self.curses.setupterm()
+ self.ed = self.curses.tigetstr("ed")
+ if self.ed:
+ self.cuu = self.curses.tigetstr("cuu")
+ self.columns = self.getTerminalColumns()
+ self.sigUpdate()
+ except Exception as e:
+ self.cuu = None
+
+ def setTopMode(self):
+ if self.topMode:
+ return
+ self.cursesInit()
+ self.topMode = True
+ self.console.addFilter(self.confilter)
+
+ def setNormalMode(self):
+ if not self.topMode:
+ return
+ self.topMode = False
+ try:
+ self.console.removeFilter(self.confilter)
+ except:
+ pass
def clearFooter(self):
- return
+ if not self.topMode:
+ return
+ if self.footer_present:
+ lines = self.footer_present
+ sys.stdout.write(self.curses.tparm(self.cuu, lines))
+ sys.stdout.write(self.curses.tparm(self.ed))
+ self.footer_present = False
- def sigUpdate(self):
- return
def updateFooterForce(self):
+ self.footer_present = False
self.printFooter(True)
def updateFooter(self):
self.printFooter(False)
def printFooter(self, force_update):
- if not force_update:
- if not main.shutdown or not self.helper.needUpdate:
- return
-
activetasks = self.helper.running_tasks
+ failedtasks = self.helper.failed_tasks
runningpids = self.helper.running_pids
+ if self.topMode:
+ if not self.cuu:
+ return
+ if self.footer_present and (self.lastpids == runningpids):
+ return
+ if self.footer_present:
+ self.clearFooter()
+ else:
+ if not force_update:
+ if not main.shutdown or not self.helper.needUpdate:
+ return
+ if len(runningpids) == 0:
+ return
+ self.helper.getTasks()
- if len(runningpids) == 0:
+ if not activetasks:
return
-
- self.helper.getTasks()
-
+ lines = 1
tasks = []
for t in runningpids:
tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
- if main.shutdown:
+ if self.main.shutdown:
print("Waiting for %s running tasks to finish:" % len(activetasks))
else:
- print("Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total))
+ if self.helper.tasknumber_current == 0:
+ print("Currently %s running SetScene tasks (%s of %s):" % (len(activetasks), self.helper.sc_tasknumber_current, self.helper.sc_tasknumber_total))
+ else:
+ print("Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total))
for tasknum, task in enumerate(tasks):
- print("%s: %s" % (tasknum, task))
+ content = "%s: %s" % (tasknum, task)
+ print content
+ lines = lines + 1 + int(len(content) / (self.columns + 1))
+ self.footer_present = lines
+ self.lastpids = runningpids[:]
def finish(self):
return
+ def sigwinch_handle(self, sig, data):
+ self.columns = self.getTerminalColumns()
+
+ def sigUpdate(self):
+ import signal
+ if self.interactive and self.cuu:
+ signal.signal(signal.SIGWINCH, self.sigwinch_handle)
+
+ def getTerminalColumns(self):
+ def ioctl_GWINSZ(fd):
+ try:
+ import fcntl, termios, struct, os
+ cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
+ except:
+ return None
+ return cr
+ cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
+ if not cr:
+ try:
+ fd = os.open(os.ctermid(), os.O_RDONLY)
+ cr = ioctl_GWINSZ(fd)
+ os.close(fd)
+ except:
+ pass
+ if not cr:
+ try:
+ cr = (env['LINES'], env['COLUMNS'])
+ except:
+ cr = (25, 80)
+ return cr[1]
+
+
class StdinMgr:
def __init__(self):
self.stdinbackup = None
@@ -145,23 +251,26 @@ class StdinMgr:
termios.tcsetattr(self.fd, termios.TCSANOW, new)
class RtLogLevel:
- def __init__(self, handler, logfilter, mlt):
+ def __init__(self, handler, logfilter, mlt, tf):
self.displaytail = False
self.handler = handler
self.logfilter = logfilter
self.defaultLevel = logfilter.getFiltLevel()
self.mlt = mlt
+ self.tf = tf
def displayLogs(self):
if self.displaytail:
self.mlt.displayLogs()
def setLevel(self, input, verbose):
- if input == "1":
+ if input == "1" or input == "0":
if verbose:
print "NOTE: Turning off real time log tail"
self.logfilter.setFiltLevel(self.handler, self.defaultLevel)
self.displaytail = False
+ if input == "0" and isinstance(self.tf, TerminalFilter):
+ self.tf.setNormalMode()
elif input == "2":
if verbose:
print "NOTE: Turning on real time log tail"
@@ -177,6 +286,23 @@ class RtLogLevel:
print "NOTE: Turning on DEBUG logging + real time log tail"
self.logfilter.setFiltLevel(self.handler, logging.DEBUG)
self.displaytail = True
+ elif input == "t":
+ if verbose:
+ print "NOTE: Activing task \"top\" mode"
+ if isinstance(self.tf, TerminalFilter):
+ self.tf.setTopMode()
+ elif input == "h":
+ print "============================================="
+ print "Interaction help commands:"
+ print " 0 - default with default logs"
+ print " 1 - turn off real time log tail"
+ print " 2 - turn on real time log tail"
+ print " 3 - turn on debug logging"
+ print " 4 - turn on debug logging and real time log tail"
+ print " t - Display tasks in \"top\" mode (formerly knotty2 mode)"
+ print " h - display commands"
+ return False
+ return True
def main(server, eventHandler, tf = TerminalFilter):
@@ -201,10 +327,6 @@ def main(server, eventHandler, tf = TerminalFilter):
console = logging.StreamHandler(sys.stdout)
format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
logfilter = bb.msg.addDefaultlogFilter(console)
- rtloglevel = RtLogLevel(console, logfilter, mlt)
- bb_rt_loglevel = server.runCommand(["getVariable", "BB_RT_LOGLEVEL"])
- if bb_rt_loglevel and bb_rt_loglevel != "":
- rtloglevel.setLevel(bb_rt_loglevel, False)
console.setFormatter(format)
logger.addHandler(console)
if consolelogfile:
@@ -241,14 +363,20 @@ def main(server, eventHandler, tf = TerminalFilter):
termfilter = tf(main, helper, console, format)
stdin_mgr = StdinMgr()
+ rtloglevel = RtLogLevel(console, logfilter, mlt, termfilter)
+ bb_rt_loglevel = server.runCommand(["getVariable", "BB_RT_LOGLEVEL"])
+ if bb_rt_loglevel and bb_rt_loglevel != "":
+ for inputkey in bb_rt_loglevel:
+ rtloglevel.setLevel(inputkey, False)
while True:
try:
termfilter.updateFooter()
event = eventHandler.waitEvent(0.25)
if stdin_mgr.poll():
keyinput = sys.stdin.read(1)
- rtloglevel.setLevel(keyinput, True)
- termfilter.updateFooterForce()
+ termfilter.clearFooter()
+ if (rtloglevel.setLevel(keyinput, True)):
+ termfilter.updateFooterForce()
sys.stdout.flush()
# Always try printing any accumulated log files first
--
1.7.10
More information about the bitbake-devel
mailing list