summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbitbake/bin/bitbake2
-rw-r--r--bitbake/lib/bb/ui/knotty.py70
-rw-r--r--bitbake/lib/bb/ui/knotty2.py109
3 files changed, 162 insertions, 19 deletions
diff --git a/bitbake/bin/bitbake b/bitbake/bin/bitbake
index c06d4e8176..a90f6c6fd1 100755
--- a/bitbake/bin/bitbake
+++ b/bitbake/bin/bitbake
@@ -69,7 +69,7 @@ def get_ui(config):
69 return getattr(module, interface).main 69 return getattr(module, interface).main
70 except AttributeError: 70 except AttributeError:
71 sys.exit("FATAL: Invalid user interface '%s' specified.\n" 71 sys.exit("FATAL: Invalid user interface '%s' specified.\n"
72 "Valid interfaces: depexp, goggle, ncurses, knotty [default]." % interface) 72 "Valid interfaces: depexp, goggle, ncurses, hob, knotty [default], knotty2." % interface)
73 73
74 74
75# Display bitbake/OE warnings via the BitBake.Warnings logger, ignoring others""" 75# Display bitbake/OE warnings via the BitBake.Warnings logger, ignoring others"""
diff --git a/bitbake/lib/bb/ui/knotty.py b/bitbake/lib/bb/ui/knotty.py
index 14989d47d9..f8af4dc5fb 100644
--- a/bitbake/lib/bb/ui/knotty.py
+++ b/bitbake/lib/bb/ui/knotty.py
@@ -3,7 +3,7 @@
3# 3#
4# Handling output to TTYs or files (no TTY) 4# Handling output to TTYs or files (no TTY)
5# 5#
6# Copyright (C) 2006-2007 Richard Purdie 6# Copyright (C) 2006-2012 Richard Purdie
7# 7#
8# This program is free software; you can redistribute it and/or modify 8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as 9# it under the terms of the GNU General Public License version 2 as
@@ -70,7 +70,39 @@ def pluralise(singular, plural, qty):
70 else: 70 else:
71 return plural % qty 71 return plural % qty
72 72
73def main(server, eventHandler): 73class TerminalFilter(object):
74 def __init__(self, main, helper, console, format):
75 self.main = main
76 self.helper = helper
77
78 def clearFooter(self):
79 return
80
81 def updateFooter(self):
82 if not main.shutdown or not self.helper.needUpdate:
83 return
84
85 activetasks = self.helper.running_tasks
86 runningpids = self.helper.running_pids
87
88 if len(runningpids) == 0:
89 return
90
91 tasks = []
92 for t in runningpids:
93 tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
94
95 if main.shutdown:
96 print("Waiting for %s running tasks to finish:" % len(activetasks))
97 else:
98 print("Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total))
99 for tasknum, task in enumerate(tasks):
100 print("%s: %s" % (tasknum, task))
101
102 def finish(self):
103 return
104
105def main(server, eventHandler, tf = TerminalFilter):
74 106
75 # Get values of variables which control our output 107 # Get values of variables which control our output
76 includelogs = server.runCommand(["getVariable", "BBINCLUDELOGS"]) 108 includelogs = server.runCommand(["getVariable", "BBINCLUDELOGS"])
@@ -106,32 +138,29 @@ def main(server, eventHandler):
106 print("XMLRPC Fault getting commandline:\n %s" % x) 138 print("XMLRPC Fault getting commandline:\n %s" % x)
107 return 1 139 return 1
108 140
109
110 parseprogress = None 141 parseprogress = None
111 cacheprogress = None 142 cacheprogress = None
112 shutdown = 0 143 main.shutdown = 0
113 interrupted = False 144 interrupted = False
114 return_value = 0 145 return_value = 0
115 errors = 0 146 errors = 0
116 warnings = 0 147 warnings = 0
117 taskfailures = [] 148 taskfailures = []
149
150 termfilter = tf(main, helper, console, format)
151
118 while True: 152 while True:
119 try: 153 try:
154 termfilter.updateFooter()
120 event = eventHandler.waitEvent(0.25) 155 event = eventHandler.waitEvent(0.25)
121 if event is None: 156 if event is None:
122 if shutdown > 1: 157 if main.shutdown > 1:
123 break 158 break
124 continue 159 continue
125 helper.eventHandler(event) 160 helper.eventHandler(event)
126 if isinstance(event, bb.runqueue.runQueueExitWait): 161 if isinstance(event, bb.runqueue.runQueueExitWait):
127 if not shutdown: 162 if not main.shutdown:
128 shutdown = 1 163 main.shutdown = 1
129 if shutdown and helper.needUpdate:
130 activetasks, failedtasks = helper.getTasks()
131 if activetasks:
132 print("Waiting for %s active tasks to finish:" % len(activetasks))
133 for tasknum, task in enumerate(activetasks):
134 print("%s: %s (pid %s)" % (tasknum, activetasks[task]["title"], task))
135 164
136 if isinstance(event, logging.LogRecord): 165 if isinstance(event, logging.LogRecord):
137 if event.levelno >= format.ERROR: 166 if event.levelno >= format.ERROR:
@@ -151,6 +180,7 @@ def main(server, eventHandler):
151 return_value = 1 180 return_value = 1
152 logfile = event.logfile 181 logfile = event.logfile
153 if logfile and os.path.exists(logfile): 182 if logfile and os.path.exists(logfile):
183 termfilter.clearFooter()
154 print("ERROR: Logfile of failure stored in: %s" % logfile) 184 print("ERROR: Logfile of failure stored in: %s" % logfile)
155 if includelogs and not event.errprinted: 185 if includelogs and not event.errprinted:
156 print("Log data follows:") 186 print("Log data follows:")
@@ -206,14 +236,14 @@ def main(server, eventHandler):
206 return_value = event.exitcode 236 return_value = event.exitcode
207 errors = errors + 1 237 errors = errors + 1
208 logger.error("Command execution failed: %s", event.error) 238 logger.error("Command execution failed: %s", event.error)
209 shutdown = 2 239 main.shutdown = 2
210 continue 240 continue
211 if isinstance(event, bb.command.CommandExit): 241 if isinstance(event, bb.command.CommandExit):
212 if not return_value: 242 if not return_value:
213 return_value = event.exitcode 243 return_value = event.exitcode
214 continue 244 continue
215 if isinstance(event, (bb.command.CommandCompleted, bb.cooker.CookerExit)): 245 if isinstance(event, (bb.command.CommandCompleted, bb.cooker.CookerExit)):
216 shutdown = 2 246 main.shutdown = 2
217 continue 247 continue
218 if isinstance(event, bb.event.MultipleProviders): 248 if isinstance(event, bb.event.MultipleProviders):
219 logger.info("multiple providers are available for %s%s (%s)", event._is_runtime and "runtime " or "", 249 logger.info("multiple providers are available for %s%s (%s)", event._is_runtime and "runtime " or "",
@@ -281,18 +311,20 @@ def main(server, eventHandler):
281 logger.error("Unknown event: %s", event) 311 logger.error("Unknown event: %s", event)
282 312
283 except EnvironmentError as ioerror: 313 except EnvironmentError as ioerror:
314 termfilter.clearFooter()
284 # ignore interrupted io 315 # ignore interrupted io
285 if ioerror.args[0] == 4: 316 if ioerror.args[0] == 4:
286 pass 317 pass
287 except KeyboardInterrupt: 318 except KeyboardInterrupt:
288 if shutdown == 1: 319 termfilter.clearFooter()
320 if main.shutdown == 1:
289 print("\nSecond Keyboard Interrupt, stopping...\n") 321 print("\nSecond Keyboard Interrupt, stopping...\n")
290 server.runCommand(["stateStop"]) 322 server.runCommand(["stateStop"])
291 if shutdown == 0: 323 if main.shutdown == 0:
292 interrupted = True 324 interrupted = True
293 print("\nKeyboard Interrupt, closing down...\n") 325 print("\nKeyboard Interrupt, closing down...\n")
294 server.runCommand(["stateShutdown"]) 326 server.runCommand(["stateShutdown"])
295 shutdown = shutdown + 1 327 main.shutdown = main.shutdown + 1
296 pass 328 pass
297 329
298 summary = "" 330 summary = ""
@@ -315,4 +347,6 @@ def main(server, eventHandler):
315 if return_value == 0: 347 if return_value == 0:
316 return_value = 1 348 return_value = 1
317 349
350 termfilter.finish()
351
318 return return_value 352 return return_value
diff --git a/bitbake/lib/bb/ui/knotty2.py b/bitbake/lib/bb/ui/knotty2.py
new file mode 100644
index 0000000000..aa6a4080e2
--- /dev/null
+++ b/bitbake/lib/bb/ui/knotty2.py
@@ -0,0 +1,109 @@
1#
2# BitBake (No)TTY UI Implementation (v2)
3#
4# Handling output to TTYs or files (no TTY)
5#
6# Copyright (C) 2012 Richard Purdie
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21from bb.ui import knotty
22import logging
23import sys
24logger = logging.getLogger("BitBake")
25
26class InteractConsoleLogFilter(logging.Filter):
27 def __init__(self, tf, format):
28 self.tf = tf
29 self.format = format
30
31 def filter(self, record):
32 if record.levelno == self.format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("package ")):
33 return False
34 self.tf.clearFooter()
35 return True
36
37class TerminalFilter2(object):
38 def __init__(self, main, helper, console, format):
39 self.main = main
40 self.helper = helper
41 self.cuu = None
42 self.stdinbackup = None
43 self.interactive = sys.stdout.isatty()
44 self.footer_present = False
45 self.lastpids = []
46
47 if not self.interactive:
48 return
49
50 import curses
51 import termios
52 import copy
53 self.curses = curses
54 self.termios = termios
55 try:
56 fd = sys.stdin.fileno()
57 self.stdinbackup = termios.tcgetattr(fd)
58 new = copy.deepcopy(self.stdinbackup)
59 new[3] = new[3] & ~termios.ECHO
60 termios.tcsetattr(fd, termios.TCSADRAIN, new)
61 curses.setupterm()
62 self.ed = curses.tigetstr("ed")
63 if self.ed:
64 self.cuu = curses.tigetstr("cuu")
65 except:
66 self.cuu = None
67 console.addFilter(InteractConsoleLogFilter(self, format))
68
69 def clearFooter(self):
70 if self.footer_present:
71 lines = self.footer_present
72 sys.stdout.write(self.curses.tparm(self.cuu, lines))
73 sys.stdout.write(self.curses.tparm(self.ed))
74 self.footer_present = False
75
76 def updateFooter(self):
77 if not self.cuu:
78 return
79 activetasks = self.helper.running_tasks
80 failedtasks = self.helper.failed_tasks
81 runningpids = self.helper.running_pids
82 if self.footer_present and (self.lastpids == runningpids):
83 return
84 if self.footer_present:
85 self.clearFooter()
86 if not activetasks:
87 return
88 lines = 1
89 tasks = []
90 for t in runningpids:
91 tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
92
93 if self.main.shutdown:
94 print("Waiting for %s running tasks to finish:" % len(activetasks))
95 else:
96 print("Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total))
97 for tasknum, task in enumerate(tasks):
98 print("%s: %s" % (tasknum, task))
99 lines = lines + 1
100 self.footer_present = lines
101 self.lastpids = runningpids[:]
102
103 def finish(self):
104 if self.stdinbackup:
105 fd = sys.stdin.fileno()
106 self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
107
108def main(server, eventHandler):
109 bb.ui.knotty.main(server, eventHandler, TerminalFilter2)