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