summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/toasterui.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/ui/toasterui.py')
-rw-r--r--bitbake/lib/bb/ui/toasterui.py312
1 files changed, 312 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..1626aa6c34
--- /dev/null
+++ b/bitbake/lib/bb/ui/toasterui.py
@@ -0,0 +1,312 @@
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, bb.cooker.CookerFeatures.BASEDATASTORE_TRACKING]
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 first = True
95
96 buildinfohelper = BuildInfoHelper(server, build_history_enabled)
97
98 while True:
99 try:
100 event = eventHandler.waitEvent(0.25)
101 if first:
102 first = False
103 logger.info("ToasterUI waiting for events")
104
105 if event is None:
106 if main.shutdown > 0:
107 break
108 continue
109
110 helper.eventHandler(event)
111
112 if isinstance(event, bb.event.BuildStarted):
113 buildinfohelper.store_started_build(event)
114
115 if isinstance(event, (bb.build.TaskStarted, bb.build.TaskSucceeded, bb.build.TaskFailedSilent)):
116 buildinfohelper.update_and_store_task(event)
117 continue
118
119 if isinstance(event, bb.event.LogExecTTY):
120 logger.warn(event.msg)
121 continue
122
123 if isinstance(event, logging.LogRecord):
124 buildinfohelper.store_log_event(event)
125 if event.levelno >= format.ERROR:
126 errors = errors + 1
127 return_value = 1
128 elif event.levelno == format.WARNING:
129 warnings = warnings + 1
130 # For "normal" logging conditions, don't show note logs from tasks
131 # but do show them if the user has changed the default log level to
132 # include verbose/debug messages
133 if event.taskpid != 0 and event.levelno <= format.NOTE:
134 continue
135
136 logger.handle(event)
137 continue
138
139 if isinstance(event, bb.build.TaskFailed):
140 buildinfohelper.update_and_store_task(event)
141 return_value = 1
142 logfile = event.logfile
143 if logfile and os.path.exists(logfile):
144 bb.error("Logfile of failure stored in: %s" % logfile)
145 continue
146
147 # these events are unprocessed now, but may be used in the future to log
148 # timing and error informations from the parsing phase in Toaster
149 if isinstance(event, (bb.event.SanityCheckPassed, bb.event.SanityCheck)):
150 continue
151 if isinstance(event, bb.event.ParseStarted):
152 continue
153 if isinstance(event, bb.event.ParseProgress):
154 continue
155 if isinstance(event, bb.event.ParseCompleted):
156 continue
157 if isinstance(event, bb.event.CacheLoadStarted):
158 continue
159 if isinstance(event, bb.event.CacheLoadProgress):
160 continue
161 if isinstance(event, bb.event.CacheLoadCompleted):
162 continue
163 if isinstance(event, bb.event.MultipleProviders):
164 continue
165 if isinstance(event, bb.event.NoProvider):
166 return_value = 1
167 errors = errors + 1
168 if event._runtime:
169 r = "R"
170 else:
171 r = ""
172
173 if event._dependees:
174 text = "Nothing %sPROVIDES '%s' (but %s %sDEPENDS on or otherwise requires it)" % (r, event._item, ", ".join(event._dependees), r)
175 else:
176 text = "Nothing %sPROVIDES '%s'" % (r, event._item)
177
178 logger.error(text)
179 if event._reasons:
180 for reason in event._reasons:
181 logger.error("%s", reason)
182 text += reason
183 buildinfohelper.store_log_error(text)
184 continue
185
186 if isinstance(event, bb.event.ConfigParsed):
187 continue
188 if isinstance(event, bb.event.RecipeParsed):
189 continue
190
191 # end of saved events
192
193 if isinstance(event, (bb.runqueue.sceneQueueTaskStarted, bb.runqueue.runQueueTaskStarted, bb.runqueue.runQueueTaskSkipped)):
194 buildinfohelper.store_started_task(event)
195 continue
196
197 if isinstance(event, bb.runqueue.runQueueTaskCompleted):
198 buildinfohelper.update_and_store_task(event)
199 continue
200
201 if isinstance(event, bb.runqueue.runQueueTaskFailed):
202 buildinfohelper.update_and_store_task(event)
203 taskfailures.append(event.taskstring)
204 logger.error("Task %s (%s) failed with exit code '%s'",
205 event.taskid, event.taskstring, event.exitcode)
206 continue
207
208 if isinstance(event, (bb.runqueue.sceneQueueTaskCompleted, bb.runqueue.sceneQueueTaskFailed)):
209 buildinfohelper.update_and_store_task(event)
210 continue
211
212
213 if isinstance(event, (bb.event.TreeDataPreparationStarted, bb.event.TreeDataPreparationCompleted)):
214 continue
215
216 if isinstance(event, (bb.event.BuildCompleted)):
217 continue
218
219 if isinstance(event, (bb.command.CommandCompleted,
220 bb.command.CommandFailed,
221 bb.command.CommandExit)):
222 if (isinstance(event, bb.command.CommandFailed)):
223 event.levelno = format.ERROR
224 event.msg = "Command Failed " + event.error
225 event.pathname = ""
226 event.lineno = 0
227 buildinfohelper.store_log_event(event)
228 errors += 1
229
230 buildinfohelper.update_build_information(event, errors, warnings, taskfailures)
231 buildinfohelper.close()
232
233
234 # we start a new build info
235 if buildinfohelper.brbe is not None:
236
237 print "we are under BuildEnvironment management - after the build, we exit"
238 server.terminateServer()
239 else:
240 print "prepared for new build"
241 errors = 0
242 warnings = 0
243 taskfailures = []
244 buildinfohelper = BuildInfoHelper(server, build_history_enabled)
245
246 continue
247
248 if isinstance(event, bb.event.MetadataEvent):
249 if event.type == "SinglePackageInfo":
250 buildinfohelper.store_build_package_information(event)
251 elif event.type == "LayerInfo":
252 buildinfohelper.store_layer_info(event)
253 elif event.type == "BuildStatsList":
254 buildinfohelper.store_tasks_stats(event)
255 elif event.type == "ImagePkgList":
256 buildinfohelper.store_target_package_data(event)
257 elif event.type == "MissedSstate":
258 buildinfohelper.store_missed_state_tasks(event)
259 elif event.type == "ImageFileSize":
260 buildinfohelper.update_target_image_file(event)
261 elif event.type == "LicenseManifestPath":
262 buildinfohelper.store_license_manifest_path(event)
263 continue
264
265 if isinstance(event, bb.cooker.CookerExit):
266 # exit when the server exits
267 break
268
269 # ignore
270 if isinstance(event, (bb.event.BuildBase,
271 bb.event.StampUpdate,
272 bb.event.RecipePreFinalise,
273 bb.runqueue.runQueueEvent,
274 bb.runqueue.runQueueExitWait,
275 bb.event.OperationProgress,
276 bb.command.CommandFailed,
277 bb.command.CommandExit,
278 bb.command.CommandCompleted)):
279 continue
280
281 if isinstance(event, bb.event.DepTreeGenerated):
282 buildinfohelper.store_dependency_information(event)
283 continue
284
285 logger.error("Unknown event: %s", event)
286
287 except EnvironmentError as ioerror:
288 # ignore interrupted io
289 if ioerror.args[0] == 4:
290 pass
291 except KeyboardInterrupt:
292 main.shutdown = 1
293 pass
294 except Exception as e:
295 # print errors to log
296 import traceback
297 exception_data = traceback.format_exc()
298 logger.error("%s\n%s" % (e, exception_data))
299
300 # save them to database, if possible; if it fails, we already logged to console.
301 try:
302 buildinfohelper.store_log_exception("%s\n%s" % (str(e), exception_data))
303 except Exception as ce:
304 logger.error("CRITICAL - Failed to to save toaster exception to the database: %s" % str(ce))
305
306 pass
307
308 if interrupted:
309 if return_value == 0:
310 return_value = 1
311
312 return return_value