summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/toasterui.py
diff options
context:
space:
mode:
authorAlexandru DAMIAN <alexandru.damian@intel.com>2013-09-26 12:50:50 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-10-18 11:13:49 +0100
commit9a1dce10bdc9254bb38e0e54199f23ae55e209a4 (patch)
tree40bcb13c44718a4f2d61f515e7a28250b1ee165f /bitbake/lib/bb/ui/toasterui.py
parent4e21d092f9bc13e1bdade1e015c57d6ca569639b (diff)
downloadpoky-9a1dce10bdc9254bb38e0e54199f23ae55e209a4.tar.gz
bitbake: toaster: add Toaster UI interface
Adding a new bitbake UI interface named 'toasterui'. 'toasterui' listens for events and data coming from a bitbake server during a run, and records it in a data store using the Toaster object model. Adds a helper class named BuildInfoHelper that reconstructs the state of the bitbake server and saves relevant data to the data store. Code portions contributed by Calin Dragomir <calindragomir@gmail.com>. (Bitbake rev: 62200ff6694b21fbd5abf009a6f47ad93adf5309) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/bb/ui/toasterui.py')
-rw-r--r--bitbake/lib/bb/ui/toasterui.py273
1 files changed, 273 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/toasterui.py b/bitbake/lib/bb/ui/toasterui.py
new file mode 100644
index 0000000000..ab87092e63
--- /dev/null
+++ b/bitbake/lib/bb/ui/toasterui.py
@@ -0,0 +1,273 @@
1#
2# BitBake ToasterUI Implementation
3# based on (No)TTY UI Implementation by Richard Purdie
4#
5# Handling output to TTYs or files (no TTY)
6#
7# Copyright (C) 2006-2012 Richard Purdie
8# Copyright (C) 2013 Intel Corporation
9#
10# This program is free software; you can redistribute it and/or modify
11# it under the terms of the GNU General Public License version 2 as
12# published by the Free Software Foundation.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License along
20# with this program; if not, write to the Free Software Foundation, Inc.,
21# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23from __future__ import division
24try:
25 import bb
26except RuntimeError as exc:
27 sys.exit(str(exc))
28
29from bb.ui import uihelper
30from bb.ui.buildinfohelper import BuildInfoHelper
31
32import bb.msg
33import copy
34import fcntl
35import logging
36import os
37import progressbar
38import signal
39import struct
40import sys
41import time
42import xmlrpclib
43
44featureSet = [bb.cooker.CookerFeatures.HOB_EXTRA_CACHES, bb.cooker.CookerFeatures.SEND_DEPENDS_TREE]
45
46logger = logging.getLogger("BitBake")
47interactive = sys.stdout.isatty()
48
49
50
51def _log_settings_from_server(server):
52 # Get values of variables which control our output
53 includelogs, error = server.runCommand(["getVariable", "BBINCLUDELOGS"])
54 if error:
55 logger.error("Unable to get the value of BBINCLUDELOGS variable: %s" % error)
56 raise BaseException(error)
57 loglines, error = server.runCommand(["getVariable", "BBINCLUDELOGS_LINES"])
58 if error:
59 logger.error("Unable to get the value of BBINCLUDELOGS_LINES variable: %s" % error)
60 raise BaseException(error)
61 return includelogs, loglines
62
63def main(server, eventHandler, params ):
64
65 includelogs, loglines = _log_settings_from_server(server)
66
67 # verify and warn
68 build_history_enabled = True
69 inheritlist, error = server.runCommand(["getVariable", "INHERIT"])
70 if not "buildhistory" in inheritlist.split(" "):
71 logger.warn("buildhistory is not enabled. Please enable INHERIT += \"buildhistory\" to see image details.")
72 build_history_enabled = False
73
74 helper = uihelper.BBUIHelper()
75
76 console = logging.StreamHandler(sys.stdout)
77 format_str = "%(levelname)s: %(message)s"
78 format = bb.msg.BBLogFormatter(format_str)
79 bb.msg.addDefaultlogFilter(console)
80 console.setFormatter(format)
81 logger.addHandler(console)
82
83 if not params.observe_only:
84 logger.error("ToasterUI can only work in observer mode")
85 return
86
87
88 main.shutdown = 0
89 interrupted = False
90 return_value = 0
91 errors = 0
92 warnings = 0
93 taskfailures = []
94
95 buildinfohelper = BuildInfoHelper(server, build_history_enabled)
96 buildinfohelper.store_layer_info()
97
98
99 while True:
100 try:
101 event = eventHandler.waitEvent(0.25)
102
103 if event is None:
104 if main.shutdown > 0:
105 break
106 continue
107
108 helper.eventHandler(event)
109
110 if isinstance(event, bb.event.BuildStarted):
111 buildinfohelper.store_started_build(event)
112
113 if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)):
114 buildinfohelper.update_and_store_task(event)
115 continue
116
117 if isinstance(event, bb.event.LogExecTTY):
118 logger.warn(event.msg)
119 continue
120
121 if isinstance(event, logging.LogRecord):
122 buildinfohelper.store_log_event(event)
123 if event.levelno >= format.ERROR:
124 errors = errors + 1
125 return_value = 1
126 elif event.levelno == format.WARNING:
127 warnings = warnings + 1
128 # For "normal" logging conditions, don't show note logs from tasks
129 # but do show them if the user has changed the default log level to
130 # include verbose/debug messages
131 if event.taskpid != 0 and event.levelno <= format.NOTE:
132 continue
133
134 logger.handle(event)
135 continue
136
137 if isinstance(event, bb.build.TaskFailed):
138 buildinfohelper.update_and_store_task(event)
139 return_value = 1
140 logfile = event.logfile
141 if logfile and os.path.exists(logfile):
142 bb.error("Logfile of failure stored in: %s" % logfile)
143
144 # these events are unprocessed now, but may be used in the future to log
145 # timing and error informations from the parsing phase in Toaster
146 if isinstance(event, bb.event.ParseStarted):
147 continue
148 if isinstance(event, bb.event.ParseProgress):
149 continue
150 if isinstance(event, bb.event.ParseCompleted):
151 continue
152 if isinstance(event, bb.event.CacheLoadStarted):
153 continue
154 if isinstance(event, bb.event.CacheLoadProgress):
155 continue
156 if isinstance(event, bb.event.CacheLoadCompleted):
157 continue
158 if isinstance(event, bb.event.MultipleProviders):
159 continue
160 if isinstance(event, bb.event.NoProvider):
161 return_value = 1
162 errors = errors + 1
163 if event._runtime:
164 r = "R"
165 else:
166 r = ""
167
168 if event._dependees:
169 text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r)
170 else:
171 text = "Nothing %sPROVIDES '%s'" % (r, event._item)
172
173 logger.error(text)
174 if event._reasons:
175 for reason in event._reasons:
176 logger.error("%s", reason)
177 text += reason
178 buildinfohelper.store_log_error(text)
179 continue
180
181 if isinstance(event, bb.event.ConfigParsed):
182 continue
183 if isinstance(event, bb.event.RecipeParsed):
184 continue
185
186 # end of saved events
187
188 if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)):
189 buildinfohelper.store_started_task(event)
190 continue
191
192 if isinstance(event, bb.runqueue.runQueueTaskCompleted):
193 buildinfohelper.update_and_store_task(event)
194 continue
195
196 if isinstance(event, bb.runqueue.runQueueTaskFailed):
197 buildinfohelper.update_and_store_task(event)
198 taskfailures.append(event.taskstring)
199 logger.error("Task %s (%s) failed with exit code '%s'",
200 event.taskid, event.taskstring, event.exitcode)
201 continue
202
203 if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)):
204 buildinfohelper.update_and_store_task(event)
205 continue
206
207
208 if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)):
209 continue
210
211 if isinstance(event, (bb.event.BuildCompleted)):
212 buildinfohelper.read_target_package_dep_data(event)
213 buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
214 continue
215
216 if isinstance(event, (bb.command.CommandCompleted,
217 bb.command.CommandFailed,
218 bb.command.CommandExit)):
219
220 buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
221
222 # we start a new build info
223 errors = 0
224 warnings = 0
225 taskfailures = []
226 buildinfohelper = BuildInfoHelper(server, build_history_enabled)
227 buildinfohelper.store_layer_info()
228 continue
229
230 if isinstance(event, bb.event.MetadataEvent):
231 if event.type == "SinglePackageInfo":
232 buildinfohelper.store_build_package_information(event)
233 elif event.type == "PackageFileSize":
234 buildinfohelper.store_package_file_information(event)
235 continue
236
237 # ignore
238 if isinstance(event, (bb.event.BuildBase,
239 bb.event.StampUpdate,
240 bb.event.RecipePreFinalise,
241 bb.runqueue.runQueueEvent,
242 bb.runqueue.runQueueExitWait,
243 bb.event.OperationProgress,
244 bb.command.CommandFailed,
245 bb.command.CommandExit,
246 bb.command.CommandCompleted,
247 bb.cooker.CookerExit)):
248 continue
249
250 if isinstance(event, bb.event.DepTreeGenerated):
251 buildinfohelper.store_dependency_information(event)
252 continue
253
254 logger.error("Unknown event: %s", event)
255
256 except EnvironmentError as ioerror:
257 # ignore interrupted io
258 if ioerror.args[0] == 4:
259 pass
260 except KeyboardInterrupt:
261 main.shutdown = 1
262 pass
263 except Exception as e:
264 logger.error(e)
265 import traceback
266 traceback.print_exc()
267 pass
268
269 if interrupted:
270 if return_value == 0:
271 return_value = 1
272
273 return return_value