summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/ui/crumbs/builddetailspage.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/builddetailspage.py')
-rwxr-xr-xbitbake/lib/bb/ui/crumbs/builddetailspage.py436
1 files changed, 436 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/builddetailspage.py b/bitbake/lib/bb/ui/crumbs/builddetailspage.py
new file mode 100755
index 0000000000..171a7a68ed
--- /dev/null
+++ b/bitbake/lib/bb/ui/crumbs/builddetailspage.py
@@ -0,0 +1,436 @@
1#!/usr/bin/env python
2#
3# BitBake Graphical GTK User Interface
4#
5# Copyright (C) 2012 Intel Corporation
6#
7# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
8# Authored by Shane Wang <shane.wang@intel.com>
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
23import gtk
24import pango
25import gobject
26import bb.process
27from bb.ui.crumbs.progressbar import HobProgressBar
28from bb.ui.crumbs.hobwidget import hic, HobNotebook, HobAltButton, HobWarpCellRendererText, HobButton, HobInfoButton
29from bb.ui.crumbs.runningbuild import RunningBuildTreeView
30from bb.ui.crumbs.runningbuild import BuildFailureTreeView
31from bb.ui.crumbs.hobpages import HobPage
32from bb.ui.crumbs.hobcolor import HobColors
33
34class BuildConfigurationTreeView(gtk.TreeView):
35 def __init__ (self):
36 gtk.TreeView.__init__(self)
37 self.set_rules_hint(False)
38 self.set_headers_visible(False)
39 self.set_property("hover-expand", True)
40 self.get_selection().set_mode(gtk.SELECTION_SINGLE)
41
42 # The icon that indicates whether we're building or failed.
43 renderer0 = gtk.CellRendererText()
44 renderer0.set_property('font-desc', pango.FontDescription('courier bold 12'))
45 col0 = gtk.TreeViewColumn ("Name", renderer0, text=0)
46 self.append_column (col0)
47
48 # The message of configuration.
49 renderer1 = HobWarpCellRendererText(col_number=1)
50 col1 = gtk.TreeViewColumn ("Values", renderer1, text=1)
51 self.append_column (col1)
52
53 def set_vars(self, key="", var=[""]):
54 d = {}
55 if type(var) == str:
56 d = {key: [var]}
57 elif type(var) == list and len(var) > 1:
58 #create the sub item line
59 l = []
60 text = ""
61 for item in var:
62 text = " - " + item
63 l.append(text)
64 d = {key: var}
65
66 return d
67
68 def set_config_model(self, show_vars):
69 listmodel = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING)
70 parent = None
71 for var in show_vars:
72 for subitem in var.items():
73 name = subitem[0]
74 is_parent = True
75 for value in subitem[1]:
76 if is_parent:
77 parent = listmodel.append(parent, (name, value))
78 is_parent = False
79 else:
80 listmodel.append(parent, (None, value))
81 name = " - "
82 parent = None
83 # renew the tree model after get the configuration messages
84 self.set_model(listmodel)
85
86 def show(self, src_config_info, src_params):
87 vars = []
88 vars.append(self.set_vars("BB version:", src_params.bb_version))
89 vars.append(self.set_vars("Target arch:", src_params.target_arch))
90 vars.append(self.set_vars("Target OS:", src_params.target_os))
91 vars.append(self.set_vars("Machine:", src_config_info.curr_mach))
92 vars.append(self.set_vars("Distro:", src_config_info.curr_distro))
93 vars.append(self.set_vars("Distro version:", src_params.distro_version))
94 vars.append(self.set_vars("SDK machine:", src_config_info.curr_sdk_machine))
95 vars.append(self.set_vars("Tune features:", src_params.tune_pkgarch))
96 vars.append(self.set_vars("Layers:", src_config_info.layers))
97
98 for path in src_config_info.layers:
99 import os, os.path
100 if os.path.exists(path):
101 branch = bb.process.run('cd %s; git branch | grep "^* " | tr -d "* "' % path)[0]
102 if branch.startswith("fatal:"):
103 branch = "(unknown)"
104 if branch:
105 branch = branch.strip('\n')
106 vars.append(self.set_vars("Branch:", branch))
107 break
108
109 self.set_config_model(vars)
110
111 def reset(self):
112 self.set_model(None)
113
114#
115# BuildDetailsPage
116#
117
118class BuildDetailsPage (HobPage):
119
120 def __init__(self, builder):
121 super(BuildDetailsPage, self).__init__(builder, "Building ...")
122
123 self.num_of_issues = 0
124 self.endpath = (0,)
125 # create visual elements
126 self.create_visual_elements()
127
128 def create_visual_elements(self):
129 # create visual elements
130 self.vbox = gtk.VBox(False, 12)
131
132 self.progress_box = gtk.VBox(False, 12)
133 self.task_status = gtk.Label("\n") # to ensure layout is correct
134 self.task_status.set_alignment(0.0, 0.5)
135 self.progress_box.pack_start(self.task_status, expand=False, fill=False)
136 self.progress_hbox = gtk.HBox(False, 6)
137 self.progress_box.pack_end(self.progress_hbox, expand=True, fill=True)
138 self.progress_bar = HobProgressBar()
139 self.progress_hbox.pack_start(self.progress_bar, expand=True, fill=True)
140 self.stop_button = HobAltButton("Stop")
141 self.stop_button.connect("clicked", self.stop_button_clicked_cb)
142 self.stop_button.set_sensitive(False)
143 self.progress_hbox.pack_end(self.stop_button, expand=False, fill=False)
144
145 self.notebook = HobNotebook()
146 self.config_tv = BuildConfigurationTreeView()
147 self.scrolled_view_config = gtk.ScrolledWindow ()
148 self.scrolled_view_config.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
149 self.scrolled_view_config.add(self.config_tv)
150 self.notebook.append_page(self.scrolled_view_config, "Build configuration")
151
152 self.failure_tv = BuildFailureTreeView()
153 self.failure_model = self.builder.handler.build.model.failure_model()
154 self.failure_tv.set_model(self.failure_model)
155 self.scrolled_view_failure = gtk.ScrolledWindow ()
156 self.scrolled_view_failure.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
157 self.scrolled_view_failure.add(self.failure_tv)
158 self.notebook.append_page(self.scrolled_view_failure, "Issues")
159
160 self.build_tv = RunningBuildTreeView(readonly=True, hob=True)
161 self.build_tv.set_model(self.builder.handler.build.model)
162 self.scrolled_view_build = gtk.ScrolledWindow ()
163 self.scrolled_view_build.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
164 self.scrolled_view_build.add(self.build_tv)
165 self.notebook.append_page(self.scrolled_view_build, "Log")
166
167 self.builder.handler.build.model.connect_after("row-changed", self.scroll_to_present_row, self.scrolled_view_build.get_vadjustment(), self.build_tv)
168
169 self.button_box = gtk.HBox(False, 6)
170 self.back_button = HobAltButton('&lt;&lt; Back')
171 self.back_button.connect("clicked", self.back_button_clicked_cb)
172 self.button_box.pack_start(self.back_button, expand=False, fill=False)
173
174 def update_build_status(self, current, total, task):
175 recipe_path, recipe_task = task.split(", ")
176 recipe = os.path.basename(recipe_path).rstrip(".bb")
177 tsk_msg = "<b>Running task %s of %s:</b> %s\n<b>Recipe:</b> %s" % (current, total, recipe_task, recipe)
178 self.task_status.set_markup(tsk_msg)
179 self.stop_button.set_sensitive(True)
180
181 def reset_build_status(self):
182 self.task_status.set_markup("\n") # to ensure layout is correct
183 self.endpath = (0,)
184
185 def show_issues(self):
186 self.num_of_issues += 1
187 self.notebook.show_indicator_icon("Issues", self.num_of_issues)
188
189 def reset_issues(self):
190 self.num_of_issues = 0
191 self.notebook.hide_indicator_icon("Issues")
192
193 def _remove_all_widget(self):
194 children = self.vbox.get_children() or []
195 for child in children:
196 self.vbox.remove(child)
197 children = self.box_group_area.get_children() or []
198 for child in children:
199 self.box_group_area.remove(child)
200 children = self.get_children() or []
201 for child in children:
202 self.remove(child)
203
204 def add_build_fail_top_bar(self, actions, log_file=None):
205 primary_action = "Edit %s" % actions
206
207 color = HobColors.ERROR
208 build_fail_top = gtk.EventBox()
209 #build_fail_top.set_size_request(-1, 200)
210 build_fail_top.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
211
212 build_fail_tab = gtk.Table(14, 46, True)
213 build_fail_top.add(build_fail_tab)
214
215 icon = gtk.Image()
216 icon_pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_INDI_ERROR_FILE)
217 icon.set_from_pixbuf(icon_pix_buffer)
218 build_fail_tab.attach(icon, 1, 4, 0, 6)
219
220 label = gtk.Label()
221 label.set_alignment(0.0, 0.5)
222 label.set_markup("<span size='x-large'><b>%s</b></span>" % self.title)
223 build_fail_tab.attach(label, 4, 26, 0, 6)
224
225 label = gtk.Label()
226 label.set_alignment(0.0, 0.5)
227 # Ensure variable disk_full is defined
228 if not hasattr(self.builder, 'disk_full'):
229 self.builder.disk_full = False
230
231 if self.builder.disk_full:
232 markup = "<span size='medium'>There is no disk space left, so Hob cannot finish building your image. Free up some disk space\n"
233 markup += "and restart the build. Check the \"Issues\" tab for more details</span>"
234 label.set_markup(markup)
235 else:
236 label.set_markup("<span size='medium'>Check the \"Issues\" information for more details</span>")
237 build_fail_tab.attach(label, 4, 40, 4, 9)
238
239 # create button 'Edit packages'
240 action_button = HobButton(primary_action)
241 #action_button.set_size_request(-1, 40)
242 action_button.set_tooltip_text("Edit the %s parameters" % actions)
243 action_button.connect('clicked', self.failure_primary_action_button_clicked_cb, primary_action)
244
245 if log_file:
246 open_log_button = HobAltButton("Open log")
247 open_log_button.set_relief(gtk.RELIEF_HALF)
248 open_log_button.set_tooltip_text("Open the build's log file")
249 open_log_button.connect('clicked', self.open_log_button_clicked_cb, log_file)
250
251 attach_pos = (24 if log_file else 14)
252 file_bug_button = HobAltButton('File a bug')
253 file_bug_button.set_relief(gtk.RELIEF_HALF)
254 file_bug_button.set_tooltip_text("Open the Yocto Project bug tracking website")
255 file_bug_button.connect('clicked', self.failure_activate_file_bug_link_cb)
256
257 if not self.builder.disk_full:
258 build_fail_tab.attach(action_button, 4, 13, 9, 12)
259 if log_file:
260 build_fail_tab.attach(open_log_button, 14, 23, 9, 12)
261 build_fail_tab.attach(file_bug_button, attach_pos, attach_pos + 9, 9, 12)
262
263 else:
264 restart_build = HobButton("Restart the build")
265 restart_build.set_tooltip_text("Restart the build")
266 restart_build.connect('clicked', self.restart_build_button_clicked_cb)
267
268 build_fail_tab.attach(restart_build, 4, 13, 9, 12)
269 build_fail_tab.attach(action_button, 14, 23, 9, 12)
270 if log_file:
271 build_fail_tab.attach(open_log_button, attach_pos, attach_pos + 9, 9, 12)
272
273 self.builder.disk_full = False
274 return build_fail_top
275
276 def show_fail_page(self, title):
277 self._remove_all_widget()
278 self.title = "Hob cannot build your %s" % title
279
280 self.build_fail_bar = self.add_build_fail_top_bar(title, self.builder.current_logfile)
281
282 self.pack_start(self.group_align, expand=True, fill=True)
283 self.box_group_area.pack_start(self.build_fail_bar, expand=False, fill=False)
284 self.box_group_area.pack_start(self.vbox, expand=True, fill=True)
285
286 self.vbox.pack_start(self.notebook, expand=True, fill=True)
287 self.show_all()
288 self.notebook.set_page("Issues")
289 self.back_button.hide()
290
291 def add_build_stop_top_bar(self, action, log_file=None):
292 color = HobColors.LIGHT_GRAY
293 build_stop_top = gtk.EventBox()
294 #build_stop_top.set_size_request(-1, 200)
295 build_stop_top.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(color))
296 build_stop_top.set_flags(gtk.CAN_DEFAULT)
297 build_stop_top.grab_default()
298
299 build_stop_tab = gtk.Table(11, 46, True)
300 build_stop_top.add(build_stop_tab)
301
302 icon = gtk.Image()
303 icon_pix_buffer = gtk.gdk.pixbuf_new_from_file(hic.ICON_INFO_HOVER_FILE)
304 icon.set_from_pixbuf(icon_pix_buffer)
305 build_stop_tab.attach(icon, 1, 4, 0, 6)
306
307 label = gtk.Label()
308 label.set_alignment(0.0, 0.5)
309 label.set_markup("<span size='x-large'><b>%s</b></span>" % self.title)
310 build_stop_tab.attach(label, 4, 26, 0, 6)
311
312 action_button = HobButton("Edit %s" % action)
313 action_button.set_size_request(-1, 40)
314 if action == "image":
315 action_button.set_tooltip_text("Edit the image parameters")
316 elif action == "recipes":
317 action_button.set_tooltip_text("Edit the included recipes")
318 elif action == "packages":
319 action_button.set_tooltip_text("Edit the included packages")
320 action_button.connect('clicked', self.stop_primary_action_button_clicked_cb, action)
321 build_stop_tab.attach(action_button, 4, 13, 6, 9)
322
323 if log_file:
324 open_log_button = HobAltButton("Open log")
325 open_log_button.set_relief(gtk.RELIEF_HALF)
326 open_log_button.set_tooltip_text("Open the build's log file")
327 open_log_button.connect('clicked', self.open_log_button_clicked_cb, log_file)
328 build_stop_tab.attach(open_log_button, 14, 23, 6, 9)
329
330 attach_pos = (24 if log_file else 14)
331 build_button = HobAltButton("Build new image")
332 #build_button.set_size_request(-1, 40)
333 build_button.set_tooltip_text("Create a new image from scratch")
334 build_button.connect('clicked', self.new_image_button_clicked_cb)
335 build_stop_tab.attach(build_button, attach_pos, attach_pos + 9, 6, 9)
336
337 return build_stop_top, action_button
338
339 def show_stop_page(self, action):
340 self._remove_all_widget()
341 self.title = "Build stopped"
342 self.build_stop_bar, action_button = self.add_build_stop_top_bar(action, self.builder.current_logfile)
343
344 self.pack_start(self.group_align, expand=True, fill=True)
345 self.box_group_area.pack_start(self.build_stop_bar, expand=False, fill=False)
346 self.box_group_area.pack_start(self.vbox, expand=True, fill=True)
347
348 self.vbox.pack_start(self.notebook, expand=True, fill=True)
349 self.show_all()
350 self.back_button.hide()
351 return action_button
352
353 def show_page(self, step):
354 self._remove_all_widget()
355 if step == self.builder.PACKAGE_GENERATING or step == self.builder.FAST_IMAGE_GENERATING:
356 self.title = "Building packages ..."
357 else:
358 self.title = "Building image ..."
359 self.build_details_top = self.add_onto_top_bar(None)
360 self.pack_start(self.build_details_top, expand=False, fill=False)
361 self.pack_start(self.group_align, expand=True, fill=True)
362
363 self.box_group_area.pack_start(self.vbox, expand=True, fill=True)
364
365 self.progress_bar.reset()
366 self.config_tv.reset()
367 self.vbox.pack_start(self.progress_box, expand=False, fill=False)
368
369 self.vbox.pack_start(self.notebook, expand=True, fill=True)
370
371 self.box_group_area.pack_end(self.button_box, expand=False, fill=False)
372 self.show_all()
373 self.notebook.set_page("Log")
374 self.back_button.hide()
375
376 self.reset_build_status()
377 self.reset_issues()
378
379 def update_progress_bar(self, title, fraction, status=None):
380 self.progress_bar.update(fraction)
381 self.progress_bar.set_title(title)
382 self.progress_bar.set_rcstyle(status)
383
384 def back_button_clicked_cb(self, button):
385 self.builder.show_configuration()
386
387 def new_image_button_clicked_cb(self, button):
388 self.builder.reset()
389
390 def show_back_button(self):
391 self.back_button.show()
392
393 def stop_button_clicked_cb(self, button):
394 self.builder.stop_build()
395
396 def hide_stop_button(self):
397 self.stop_button.set_sensitive(False)
398 self.stop_button.hide()
399
400 def scroll_to_present_row(self, model, path, iter, v_adj, treeview):
401 if treeview and v_adj:
402 if path[0] > self.endpath[0]: # check the event is a new row append or not
403 self.endpath = path
404 # check the gtk.adjustment position is at end boundary or not
405 if (v_adj.upper <= v_adj.page_size) or (v_adj.value == v_adj.upper - v_adj.page_size):
406 treeview.scroll_to_cell(path)
407
408 def show_configurations(self, configurations, params):
409 self.config_tv.show(configurations, params)
410
411 def failure_primary_action_button_clicked_cb(self, button, action):
412 if "Edit recipes" in action:
413 self.builder.show_recipes()
414 elif "Edit packages" in action:
415 self.builder.show_packages()
416 elif "Edit image" in action:
417 self.builder.show_configuration()
418
419 def restart_build_button_clicked_cb(self, button):
420 self.builder.just_bake()
421
422 def stop_primary_action_button_clicked_cb(self, button, action):
423 if "recipes" in action:
424 self.builder.show_recipes()
425 elif "packages" in action:
426 self.builder.show_packages(ask=False)
427 elif "image" in action:
428 self.builder.show_configuration()
429
430 def open_log_button_clicked_cb(self, button, log_file):
431 if log_file:
432 log_file = "file:///" + log_file
433 gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0)
434
435 def failure_activate_file_bug_link_cb(self, button):
436 button.child.emit('activate-link', "http://bugzilla.yoctoproject.org")