summaryrefslogtreecommitdiffstats
path: root/bitbake/lib
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib')
-rw-r--r--bitbake/lib/bb/ui/knotty.py114
-rw-r--r--bitbake/lib/bb/ui/knotty2.py149
2 files changed, 101 insertions, 162 deletions
diff --git a/bitbake/lib/bb/ui/knotty.py b/bitbake/lib/bb/ui/knotty.py
index 34b5969e6b..304ba293d1 100644
--- a/bitbake/lib/bb/ui/knotty.py
+++ b/bitbake/lib/bb/ui/knotty.py
@@ -27,6 +27,9 @@ import logging
27import progressbar 27import progressbar
28import signal 28import signal
29import bb.msg 29import bb.msg
30import fcntl
31import struct
32import copy
30from bb.ui import uihelper 33from bb.ui import uihelper
31 34
32logger = logging.getLogger("BitBake") 35logger = logging.getLogger("BitBake")
@@ -84,39 +87,124 @@ def pluralise(singular, plural, qty):
84 else: 87 else:
85 return plural % qty 88 return plural % qty
86 89
90
91class InteractConsoleLogFilter(logging.Filter):
92 def __init__(self, tf, format):
93 self.tf = tf
94 self.format = format
95
96 def filter(self, record):
97 if record.levelno == self.format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("package ")):
98 return False
99 self.tf.clearFooter()
100 return True
101
87class TerminalFilter(object): 102class TerminalFilter(object):
103 columns = 80
104
105 def sigwinch_handle(self, signum, frame):
106 self.columns = self.getTerminalColumns()
107 if self._sigwinch_default:
108 self._sigwinch_default(signum, frame)
109
110 def getTerminalColumns(self):
111 def ioctl_GWINSZ(fd):
112 try:
113 cr = struct.unpack('hh', fcntl.ioctl(fd, self.termios.TIOCGWINSZ, '1234'))
114 except:
115 return None
116 return cr
117 cr = ioctl_GWINSZ(sys.stdout.fileno())
118 if not cr:
119 try:
120 fd = os.open(os.ctermid(), os.O_RDONLY)
121 cr = ioctl_GWINSZ(fd)
122 os.close(fd)
123 except:
124 pass
125 if not cr:
126 try:
127 cr = (env['LINES'], env['COLUMNS'])
128 except:
129 cr = (25, 80)
130 return cr[1]
131
88 def __init__(self, main, helper, console, format): 132 def __init__(self, main, helper, console, format):
89 self.main = main 133 self.main = main
90 self.helper = helper 134 self.helper = helper
135 self.cuu = None
136 self.stdinbackup = None
137 self.interactive = sys.stdout.isatty()
138 self.footer_present = False
139 self.lastpids = []
140
141 if not self.interactive:
142 return
143
144 import curses
145 import termios
146 self.curses = curses
147 self.termios = termios
148 try:
149 fd = sys.stdin.fileno()
150 self.stdinbackup = termios.tcgetattr(fd)
151 new = copy.deepcopy(self.stdinbackup)
152 new[3] = new[3] & ~termios.ECHO
153 termios.tcsetattr(fd, termios.TCSADRAIN, new)
154 curses.setupterm()
155 self.ed = curses.tigetstr("ed")
156 if self.ed:
157 self.cuu = curses.tigetstr("cuu")
158 try:
159 self._sigwinch_default = signal.getsignal(signal.SIGWINCH)
160 signal.signal(signal.SIGWINCH, self.sigwinch_handle)
161 except:
162 pass
163 self.columns = self.getTerminalColumns()
164 except:
165 self.cuu = None
166 console.addFilter(InteractConsoleLogFilter(self, format))
91 167
92 def clearFooter(self): 168 def clearFooter(self):
93 return 169 if self.footer_present:
170 lines = self.footer_present
171 sys.stdout.write(self.curses.tparm(self.cuu, lines))
172 sys.stdout.write(self.curses.tparm(self.ed))
173 self.footer_present = False
94 174
95 def updateFooter(self): 175 def updateFooter(self):
96 if not main.shutdown or not self.helper.needUpdate: 176 if not self.cuu:
97 return 177 return
98
99 activetasks = self.helper.running_tasks 178 activetasks = self.helper.running_tasks
179 failedtasks = self.helper.failed_tasks
100 runningpids = self.helper.running_pids 180 runningpids = self.helper.running_pids
101 181 if self.footer_present and (self.lastpids == runningpids):
102 if len(runningpids) == 0: 182 return
183 if self.footer_present:
184 self.clearFooter()
185 if not activetasks:
103 return 186 return
104
105 self.helper.getTasks()
106
107 tasks = [] 187 tasks = []
108 for t in runningpids: 188 for t in runningpids:
109 tasks.append("%s (pid %s)" % (activetasks[t]["title"], t)) 189 tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
110 190
111 if main.shutdown: 191 if self.main.shutdown:
112 print("Waiting for %s running tasks to finish:" % len(activetasks)) 192 content = "Waiting for %s running tasks to finish:" % len(activetasks)
113 else: 193 else:
114 print("Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)) 194 content = "Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)
195 print content
196 lines = 1 + int(len(content) / (self.columns + 1))
115 for tasknum, task in enumerate(tasks): 197 for tasknum, task in enumerate(tasks):
116 print("%s: %s" % (tasknum, task)) 198 content = "%s: %s" % (tasknum, task)
199 print content
200 lines = lines + 1 + int(len(content) / (self.columns + 1))
201 self.footer_present = lines
202 self.lastpids = runningpids[:]
117 203
118 def finish(self): 204 def finish(self):
119 return 205 if self.stdinbackup:
206 fd = sys.stdin.fileno()
207 self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
120 208
121def main(server, eventHandler, tf = TerminalFilter): 209def main(server, eventHandler, tf = TerminalFilter):
122 210
diff --git a/bitbake/lib/bb/ui/knotty2.py b/bitbake/lib/bb/ui/knotty2.py
index 57ad67f5b4..e69de29bb2 100644
--- a/bitbake/lib/bb/ui/knotty2.py
+++ b/bitbake/lib/bb/ui/knotty2.py
@@ -1,149 +0,0 @@
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
24import os
25import fcntl
26import struct
27import copy
28logger = logging.getLogger("BitBake")
29
30class InteractConsoleLogFilter(logging.Filter):
31 def __init__(self, tf, format):
32 self.tf = tf
33 self.format = format
34
35 def filter(self, record):
36 if record.levelno == self.format.NOTE and (record.msg.startswith("Running") or record.msg.startswith("package ")):
37 return False
38 self.tf.clearFooter()
39 return True
40
41class TerminalFilter2(object):
42 columns = 80
43
44 def sigwinch_handle(self, signum, frame):
45 self.columns = self.getTerminalColumns()
46 if self._sigwinch_default:
47 self._sigwinch_default(signum, frame)
48
49 def getTerminalColumns(self):
50 def ioctl_GWINSZ(fd):
51 try:
52 cr = struct.unpack('hh', fcntl.ioctl(fd, self.termios.TIOCGWINSZ, '1234'))
53 except:
54 return None
55 return cr
56 cr = ioctl_GWINSZ(sys.stdout.fileno())
57 if not cr:
58 try:
59 fd = os.open(os.ctermid(), os.O_RDONLY)
60 cr = ioctl_GWINSZ(fd)
61 os.close(fd)
62 except:
63 pass
64 if not cr:
65 try:
66 cr = (env['LINES'], env['COLUMNS'])
67 except:
68 cr = (25, 80)
69 return cr[1]
70
71 def __init__(self, main, helper, console, format):
72 self.main = main
73 self.helper = helper
74 self.cuu = None
75 self.stdinbackup = None
76 self.interactive = sys.stdout.isatty()
77 self.footer_present = False
78 self.lastpids = []
79
80 if not self.interactive:
81 return
82
83 import curses
84 import termios
85 self.curses = curses
86 self.termios = termios
87 try:
88 fd = sys.stdin.fileno()
89 self.stdinbackup = termios.tcgetattr(fd)
90 new = copy.deepcopy(self.stdinbackup)
91 new[3] = new[3] & ~termios.ECHO
92 termios.tcsetattr(fd, termios.TCSADRAIN, new)
93 curses.setupterm()
94 self.ed = curses.tigetstr("ed")
95 if self.ed:
96 self.cuu = curses.tigetstr("cuu")
97 try:
98 self._sigwinch_default = signal.getsignal(signal.SIGWINCH)
99 signal.signal(signal.SIGWINCH, self.sigwinch_handle)
100 except:
101 pass
102 self.columns = self.getTerminalColumns()
103 except:
104 self.cuu = None
105 console.addFilter(InteractConsoleLogFilter(self, format))
106
107 def clearFooter(self):
108 if self.footer_present:
109 lines = self.footer_present
110 sys.stdout.write(self.curses.tparm(self.cuu, lines))
111 sys.stdout.write(self.curses.tparm(self.ed))
112 self.footer_present = False
113
114 def updateFooter(self):
115 if not self.cuu:
116 return
117 activetasks = self.helper.running_tasks
118 failedtasks = self.helper.failed_tasks
119 runningpids = self.helper.running_pids
120 if self.footer_present and (self.lastpids == runningpids):
121 return
122 if self.footer_present:
123 self.clearFooter()
124 if not activetasks:
125 return
126 tasks = []
127 for t in runningpids:
128 tasks.append("%s (pid %s)" % (activetasks[t]["title"], t))
129
130 if self.main.shutdown:
131 content = "Waiting for %s running tasks to finish:" % len(activetasks)
132 else:
133 content = "Currently %s running tasks (%s of %s):" % (len(activetasks), self.helper.tasknumber_current, self.helper.tasknumber_total)
134 print content
135 lines = 1 + int(len(content) / (self.columns + 1))
136 for tasknum, task in enumerate(tasks):
137 content = "%s: %s" % (tasknum, task)
138 print content
139 lines = lines + 1 + int(len(content) / (self.columns + 1))
140 self.footer_present = lines
141 self.lastpids = runningpids[:]
142
143 def finish(self):
144 if self.stdinbackup:
145 fd = sys.stdin.fileno()
146 self.termios.tcsetattr(fd, self.termios.TCSADRAIN, self.stdinbackup)
147
148def main(server, eventHandler):
149 return bb.ui.knotty.main(server, eventHandler, TerminalFilter2)