2011-11-28 06:32:40 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
#
|
|
|
|
# BitBake Graphical GTK User Interface
|
|
|
|
#
|
|
|
|
# Copyright (C) 2012 Intel Corporation
|
|
|
|
#
|
|
|
|
# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
|
|
|
|
# Authored by Shane Wang <shane.wang@intel.com>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
|
|
# published by the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along
|
|
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
|
|
|
import gobject
|
|
|
|
import gtk
|
|
|
|
from bb.ui.crumbs.hobcolor import HobColors
|
2012-03-22 23:06:42 +00:00
|
|
|
from bb.ui.crumbs.hobwidget import hic, HobViewTable, HobAltButton, HobButton
|
2011-11-28 06:32:40 +00:00
|
|
|
from bb.ui.crumbs.hobpages import HobPage
|
2012-05-20 12:36:05 +00:00
|
|
|
import subprocess
|
2013-01-10 11:08:02 +00:00
|
|
|
from bb.ui.crumbs.hig.crumbsdialog import CrumbsDialog
|
2013-07-25 07:25:38 +00:00
|
|
|
from bb.ui.crumbs.hig.saveimagedialog import SaveImageDialog
|
2012-10-25 10:36:23 +00:00
|
|
|
|
2011-11-28 06:32:40 +00:00
|
|
|
#
|
|
|
|
# ImageDetailsPage
|
|
|
|
#
|
|
|
|
class ImageDetailsPage (HobPage):
|
|
|
|
|
|
|
|
class DetailBox (gtk.EventBox):
|
2012-08-02 11:06:01 +00:00
|
|
|
def __init__(self, widget = None, varlist = None, vallist = None, icon = None, button = None, button2=None, color = HobColors.LIGHT_GRAY):
|
2011-11-28 06:32:40 +00:00
|
|
|
gtk.EventBox.__init__(self)
|
|
|
|
|
|
|
|
# set color
|
|
|
|
style = self.get_style().copy()
|
|
|
|
style.bg[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(color, False, False)
|
|
|
|
self.set_style(style)
|
|
|
|
|
2012-09-26 12:13:42 +00:00
|
|
|
self.row = gtk.Table(1, 2, False)
|
|
|
|
self.row.set_border_width(10)
|
|
|
|
self.add(self.row)
|
|
|
|
|
2012-05-08 11:48:08 +00:00
|
|
|
total_rows = 0
|
2012-03-16 07:17:37 +00:00
|
|
|
if widget:
|
2012-05-08 11:48:08 +00:00
|
|
|
total_rows = 10
|
|
|
|
if varlist and vallist:
|
2012-02-29 14:14:58 +00:00
|
|
|
# pack the icon and the text on the left
|
2012-05-08 11:48:08 +00:00
|
|
|
total_rows += len(varlist)
|
|
|
|
self.table = gtk.Table(total_rows, 20, True)
|
|
|
|
self.table.set_row_spacings(6)
|
2011-11-28 06:32:40 +00:00
|
|
|
self.table.set_size_request(100, -1)
|
2012-09-26 12:13:42 +00:00
|
|
|
self.row.attach(self.table, 0, 1, 0, 1, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL)
|
|
|
|
|
2011-11-28 06:32:40 +00:00
|
|
|
colid = 0
|
2012-05-08 11:48:08 +00:00
|
|
|
rowid = 0
|
2012-02-29 14:15:23 +00:00
|
|
|
self.line_widgets = {}
|
2012-03-16 07:17:37 +00:00
|
|
|
if icon:
|
2011-11-28 06:32:40 +00:00
|
|
|
self.table.attach(icon, colid, colid + 2, 0, 1)
|
|
|
|
colid = colid + 2
|
2012-03-16 07:17:37 +00:00
|
|
|
if widget:
|
2012-05-08 11:48:08 +00:00
|
|
|
self.table.attach(widget, colid, 20, 0, 10)
|
|
|
|
rowid = 10
|
|
|
|
if varlist and vallist:
|
|
|
|
for row in range(rowid, total_rows):
|
|
|
|
index = row - rowid
|
|
|
|
self.line_widgets[varlist[index]] = self.text2label(varlist[index], vallist[index])
|
|
|
|
self.table.attach(self.line_widgets[varlist[index]], colid, 20, row, row + 1)
|
2011-11-28 06:32:40 +00:00
|
|
|
# pack the button on the right
|
2012-03-16 07:17:37 +00:00
|
|
|
if button:
|
2012-08-02 11:06:01 +00:00
|
|
|
self.bbox = gtk.VBox()
|
2012-09-26 12:13:42 +00:00
|
|
|
self.bbox.pack_start(button, expand=True, fill=False)
|
2012-08-02 11:06:01 +00:00
|
|
|
if button2:
|
2012-09-26 12:13:42 +00:00
|
|
|
self.bbox.pack_start(button2, expand=True, fill=False)
|
|
|
|
self.bbox.set_size_request(150,-1)
|
|
|
|
self.row.attach(self.bbox, 1, 2, 0, 1, xoptions=gtk.FILL, yoptions=gtk.EXPAND)
|
|
|
|
|
|
|
|
def update_line_widgets(self, variable, value):
|
|
|
|
if len(self.line_widgets) == 0:
|
|
|
|
return
|
|
|
|
if not isinstance(self.line_widgets[variable], gtk.Label):
|
|
|
|
return
|
|
|
|
self.line_widgets[variable].set_markup(self.format_line(variable, value))
|
|
|
|
|
|
|
|
def wrap_line(self, inputs):
|
|
|
|
# wrap the long text of inputs
|
|
|
|
wrap_width_chars = 75
|
|
|
|
outputs = ""
|
|
|
|
tmps = inputs
|
|
|
|
less_chars = len(inputs)
|
|
|
|
while (less_chars - wrap_width_chars) > 0:
|
|
|
|
less_chars -= wrap_width_chars
|
|
|
|
outputs += tmps[:wrap_width_chars] + "\n "
|
|
|
|
tmps = inputs[less_chars:]
|
|
|
|
outputs += tmps
|
|
|
|
return outputs
|
|
|
|
|
|
|
|
def format_line(self, variable, value):
|
|
|
|
wraped_value = self.wrap_line(value)
|
|
|
|
markup = "<span weight=\'bold\'>%s</span>" % variable
|
|
|
|
markup += "<span weight=\'normal\' foreground=\'#1c1c1c\' font_desc=\'14px\'>%s</span>" % wraped_value
|
|
|
|
return markup
|
|
|
|
|
|
|
|
def text2label(self, variable, value):
|
|
|
|
# append the name:value to the left box
|
|
|
|
# such as "Name: hob-core-minimal-variant-2011-12-15-beagleboard"
|
|
|
|
label = gtk.Label()
|
|
|
|
label.set_alignment(0.0, 0.5)
|
|
|
|
label.set_markup(self.format_line(variable, value))
|
|
|
|
return label
|
|
|
|
|
|
|
|
class BuildDetailBox (gtk.EventBox):
|
|
|
|
def __init__(self, varlist = None, vallist = None, icon = None, color = HobColors.LIGHT_GRAY):
|
|
|
|
gtk.EventBox.__init__(self)
|
|
|
|
|
|
|
|
# set color
|
|
|
|
style = self.get_style().copy()
|
|
|
|
style.bg[gtk.STATE_NORMAL] = self.get_colormap().alloc_color(color, False, False)
|
|
|
|
self.set_style(style)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-09-26 12:13:42 +00:00
|
|
|
self.hbox = gtk.HBox()
|
|
|
|
self.hbox.set_border_width(10)
|
|
|
|
self.add(self.hbox)
|
|
|
|
|
|
|
|
total_rows = 0
|
|
|
|
if varlist and vallist:
|
|
|
|
# pack the icon and the text on the left
|
|
|
|
total_rows += len(varlist)
|
|
|
|
self.table = gtk.Table(total_rows, 20, True)
|
|
|
|
self.table.set_row_spacings(6)
|
|
|
|
self.table.set_size_request(100, -1)
|
|
|
|
self.hbox.pack_start(self.table, expand=True, fill=True, padding=15)
|
|
|
|
|
|
|
|
colid = 0
|
|
|
|
rowid = 0
|
|
|
|
self.line_widgets = {}
|
|
|
|
if icon:
|
|
|
|
self.table.attach(icon, colid, colid + 2, 0, 1)
|
|
|
|
colid = colid + 2
|
|
|
|
if varlist and vallist:
|
|
|
|
for row in range(rowid, total_rows):
|
|
|
|
index = row - rowid
|
|
|
|
self.line_widgets[varlist[index]] = self.text2label(varlist[index], vallist[index])
|
|
|
|
self.table.attach(self.line_widgets[varlist[index]], colid, 20, row, row + 1)
|
|
|
|
|
2012-02-29 14:15:23 +00:00
|
|
|
def update_line_widgets(self, variable, value):
|
|
|
|
if len(self.line_widgets) == 0:
|
|
|
|
return
|
|
|
|
if not isinstance(self.line_widgets[variable], gtk.Label):
|
|
|
|
return
|
|
|
|
self.line_widgets[variable].set_markup(self.format_line(variable, value))
|
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
def wrap_line(self, inputs):
|
|
|
|
# wrap the long text of inputs
|
|
|
|
wrap_width_chars = 75
|
|
|
|
outputs = ""
|
|
|
|
tmps = inputs
|
|
|
|
less_chars = len(inputs)
|
|
|
|
while (less_chars - wrap_width_chars) > 0:
|
|
|
|
less_chars -= wrap_width_chars
|
|
|
|
outputs += tmps[:wrap_width_chars] + "\n "
|
|
|
|
tmps = inputs[less_chars:]
|
|
|
|
outputs += tmps
|
|
|
|
return outputs
|
|
|
|
|
2012-02-29 14:15:23 +00:00
|
|
|
def format_line(self, variable, value):
|
2012-06-04 10:52:13 +00:00
|
|
|
wraped_value = self.wrap_line(value)
|
2012-02-29 14:15:23 +00:00
|
|
|
markup = "<span weight=\'bold\'>%s</span>" % variable
|
2012-06-04 10:52:13 +00:00
|
|
|
markup += "<span weight=\'normal\' foreground=\'#1c1c1c\' font_desc=\'14px\'>%s</span>" % wraped_value
|
2012-02-29 14:15:23 +00:00
|
|
|
return markup
|
|
|
|
|
2011-11-28 06:32:40 +00:00
|
|
|
def text2label(self, variable, value):
|
|
|
|
# append the name:value to the left box
|
|
|
|
# such as "Name: hob-core-minimal-variant-2011-12-15-beagleboard"
|
|
|
|
label = gtk.Label()
|
|
|
|
label.set_alignment(0.0, 0.5)
|
2012-02-29 14:15:23 +00:00
|
|
|
label.set_markup(self.format_line(variable, value))
|
2011-11-28 06:32:40 +00:00
|
|
|
return label
|
|
|
|
|
|
|
|
def __init__(self, builder):
|
|
|
|
super(ImageDetailsPage, self).__init__(builder, "Image details")
|
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
self.image_store = []
|
2012-04-09 14:13:50 +00:00
|
|
|
self.button_ids = {}
|
|
|
|
self.details_bottom_buttons = gtk.HBox(False, 6)
|
2013-07-25 07:37:34 +00:00
|
|
|
self.image_saved = False
|
2011-11-28 06:32:40 +00:00
|
|
|
self.create_visual_elements()
|
2013-07-25 07:40:49 +00:00
|
|
|
self.name_field_template = ""
|
|
|
|
self.description_field_template = ""
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
def create_visual_elements(self):
|
|
|
|
# create visual elements
|
|
|
|
# create the toolbar
|
|
|
|
self.toolbar = gtk.Toolbar()
|
|
|
|
self.toolbar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
|
|
|
|
self.toolbar.set_style(gtk.TOOLBAR_BOTH)
|
|
|
|
|
2012-03-13 20:09:18 +00:00
|
|
|
my_images_button = self.append_toolbar_button(self.toolbar,
|
2012-04-09 14:13:48 +00:00
|
|
|
"Images",
|
2011-11-28 06:32:40 +00:00
|
|
|
hic.ICON_IMAGES_DISPLAY_FILE,
|
|
|
|
hic.ICON_IMAGES_HOVER_FILE,
|
2012-04-09 14:13:48 +00:00
|
|
|
"Open previously built images",
|
2011-11-28 06:32:40 +00:00
|
|
|
self.my_images_button_clicked_cb)
|
2012-03-28 16:10:30 +00:00
|
|
|
settings_button = self.append_toolbar_button(self.toolbar,
|
|
|
|
"Settings",
|
|
|
|
hic.ICON_SETTINGS_DISPLAY_FILE,
|
|
|
|
hic.ICON_SETTINGS_HOVER_FILE,
|
2012-04-09 14:13:48 +00:00
|
|
|
"View additional build settings",
|
2012-03-28 16:10:30 +00:00
|
|
|
self.settings_button_clicked_cb)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
self.details_top_buttons = self.add_onto_top_bar(self.toolbar)
|
|
|
|
|
|
|
|
def _remove_all_widget(self):
|
|
|
|
children = self.get_children() or []
|
|
|
|
for child in children:
|
|
|
|
self.remove(child)
|
|
|
|
children = self.box_group_area.get_children() or []
|
|
|
|
for child in children:
|
|
|
|
self.box_group_area.remove(child)
|
2012-04-09 14:13:50 +00:00
|
|
|
children = self.details_bottom_buttons.get_children() or []
|
|
|
|
for child in children:
|
|
|
|
self.details_bottom_buttons.remove(child)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
def show_page(self, step):
|
2012-06-04 10:52:13 +00:00
|
|
|
self.build_succeeded = (step == self.builder.IMAGE_GENERATED)
|
2011-11-28 06:32:40 +00:00
|
|
|
image_addr = self.builder.parameters.image_addr
|
|
|
|
image_names = self.builder.parameters.image_names
|
2012-06-04 10:52:13 +00:00
|
|
|
if self.build_succeeded:
|
2011-11-28 06:32:40 +00:00
|
|
|
machine = self.builder.configuration.curr_mach
|
|
|
|
base_image = self.builder.recipe_model.get_selected_image()
|
|
|
|
layers = self.builder.configuration.layers
|
|
|
|
pkg_num = "%s" % len(self.builder.package_model.get_selected_packages())
|
2012-08-02 11:06:01 +00:00
|
|
|
log_file = self.builder.current_logfile
|
2011-11-28 06:32:40 +00:00
|
|
|
else:
|
|
|
|
pkg_num = "N/A"
|
2012-08-02 11:06:01 +00:00
|
|
|
log_file = None
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-04-09 14:13:50 +00:00
|
|
|
# remove
|
|
|
|
for button_id, button in self.button_ids.items():
|
|
|
|
button.disconnect(button_id)
|
2011-11-28 06:32:40 +00:00
|
|
|
self._remove_all_widget()
|
2012-05-08 11:48:08 +00:00
|
|
|
|
2012-04-09 14:13:50 +00:00
|
|
|
# repack
|
2011-11-28 06:32:40 +00:00
|
|
|
self.pack_start(self.details_top_buttons, expand=False, fill=False)
|
|
|
|
self.pack_start(self.group_align, expand=True, fill=True)
|
|
|
|
|
2012-04-09 14:13:50 +00:00
|
|
|
self.build_result = None
|
2013-07-25 07:37:34 +00:00
|
|
|
if self.image_saved or (self.build_succeeded and self.builder.current_step == self.builder.IMAGE_GENERATING):
|
2011-11-28 06:32:40 +00:00
|
|
|
# building is the previous step
|
|
|
|
icon = gtk.Image()
|
|
|
|
pixmap_path = hic.ICON_INDI_CONFIRM_FILE
|
|
|
|
color = HobColors.RUNNING
|
|
|
|
pix_buffer = gtk.gdk.pixbuf_new_from_file(pixmap_path)
|
|
|
|
icon.set_from_pixbuf(pix_buffer)
|
|
|
|
varlist = [""]
|
2013-07-25 07:37:34 +00:00
|
|
|
if self.image_saved:
|
|
|
|
vallist = ["Your image recipe has been saved"]
|
|
|
|
else:
|
|
|
|
vallist = ["Your image is ready"]
|
2012-09-26 12:13:42 +00:00
|
|
|
self.build_result = self.BuildDetailBox(varlist=varlist, vallist=vallist, icon=icon, color=color)
|
2012-04-09 14:13:50 +00:00
|
|
|
self.box_group_area.pack_start(self.build_result, expand=False, fill=False)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2013-07-25 07:25:38 +00:00
|
|
|
self.buttonlist = ["Build new image", "Save image recipe", "Run image", "Deploy image"]
|
2012-03-26 11:29:15 +00:00
|
|
|
|
2011-11-28 06:32:40 +00:00
|
|
|
# Name
|
2012-06-28 11:55:31 +00:00
|
|
|
self.image_store = []
|
2012-06-04 10:52:13 +00:00
|
|
|
self.toggled_image = ""
|
2012-03-26 11:29:15 +00:00
|
|
|
default_image_size = 0
|
2012-06-04 10:52:13 +00:00
|
|
|
self.num_toggled = 0
|
2012-04-09 14:13:50 +00:00
|
|
|
i = 0
|
2011-11-28 06:32:40 +00:00
|
|
|
for image_name in image_names:
|
2012-04-02 08:29:17 +00:00
|
|
|
image_size = HobPage._size_to_string(os.stat(os.path.join(image_addr, image_name)).st_size)
|
2012-05-21 14:41:22 +00:00
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
image_attr = ("run" if (self.test_type_runnable(image_name) and self.test_mach_runnable(image_name)) else \
|
2012-06-04 10:52:13 +00:00
|
|
|
("deploy" if self.test_deployable(image_name) else ""))
|
|
|
|
is_toggled = (image_attr != "")
|
|
|
|
|
|
|
|
if not self.toggled_image:
|
2012-04-09 14:13:50 +00:00
|
|
|
if i == (len(image_names) - 1):
|
2012-05-21 14:41:24 +00:00
|
|
|
is_toggled = True
|
|
|
|
if is_toggled:
|
2012-03-26 11:29:15 +00:00
|
|
|
default_image_size = image_size
|
2012-06-04 10:52:13 +00:00
|
|
|
self.toggled_image = image_name
|
2012-05-21 14:41:24 +00:00
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
split_stuff = image_name.split('.')
|
|
|
|
if "rootfs" in split_stuff:
|
|
|
|
image_type = image_name[(len(split_stuff[0]) + len(".rootfs") + 1):]
|
2012-03-26 11:29:15 +00:00
|
|
|
else:
|
2012-06-28 11:55:31 +00:00
|
|
|
image_type = image_name[(len(split_stuff[0]) + 1):]
|
|
|
|
|
|
|
|
self.image_store.append({'name': image_name,
|
|
|
|
'type': image_type,
|
|
|
|
'size': image_size,
|
|
|
|
'is_toggled': is_toggled,
|
|
|
|
'action_attr': image_attr,})
|
|
|
|
|
2012-04-09 14:13:50 +00:00
|
|
|
i = i + 1
|
2012-06-04 10:52:13 +00:00
|
|
|
self.num_toggled += is_toggled
|
2012-05-08 11:48:08 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
is_runnable = self.create_bottom_buttons(self.buttonlist, self.toggled_image)
|
2012-05-21 14:41:24 +00:00
|
|
|
|
2012-07-03 11:15:55 +00:00
|
|
|
# Generated image files info
|
2012-09-11 07:40:06 +00:00
|
|
|
varlist = ["Name: ", "Files created: ", "Directory: "]
|
2012-06-28 11:55:31 +00:00
|
|
|
vallist = []
|
|
|
|
|
|
|
|
vallist.append(image_name.split('.')[0])
|
|
|
|
vallist.append(', '.join(fileitem['type'] for fileitem in self.image_store))
|
|
|
|
vallist.append(image_addr)
|
2012-05-08 11:48:08 +00:00
|
|
|
|
2012-03-27 03:17:17 +00:00
|
|
|
view_files_button = HobAltButton("View files")
|
|
|
|
view_files_button.connect("clicked", self.view_files_clicked_cb, image_addr)
|
2012-04-09 14:13:48 +00:00
|
|
|
view_files_button.set_tooltip_text("Open the directory containing the image files")
|
2012-09-14 09:58:53 +00:00
|
|
|
open_log_button = None
|
2012-08-02 11:06:01 +00:00
|
|
|
if log_file:
|
2012-09-14 09:58:53 +00:00
|
|
|
open_log_button = HobAltButton("Open log")
|
|
|
|
open_log_button.connect("clicked", self.open_log_clicked_cb, log_file)
|
|
|
|
open_log_button.set_tooltip_text("Open the build's log file")
|
|
|
|
self.image_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=view_files_button, button2=open_log_button)
|
2012-06-28 11:55:31 +00:00
|
|
|
self.box_group_area.pack_start(self.image_detail, expand=False, fill=True)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
# The default kernel box for the qemu images
|
|
|
|
self.sel_kernel = ""
|
2012-08-02 11:06:01 +00:00
|
|
|
self.kernel_detail = None
|
2012-10-03 11:13:18 +00:00
|
|
|
if 'qemu' in image_name:
|
|
|
|
self.sel_kernel = self.get_kernel_file_name()
|
2012-09-28 16:06:57 +00:00
|
|
|
|
|
|
|
# varlist = ["Kernel: "]
|
|
|
|
# vallist = []
|
|
|
|
# vallist.append(self.sel_kernel)
|
|
|
|
|
|
|
|
# change_kernel_button = HobAltButton("Change")
|
|
|
|
# change_kernel_button.connect("clicked", self.change_kernel_cb)
|
|
|
|
# change_kernel_button.set_tooltip_text("Change qemu kernel file")
|
|
|
|
# self.kernel_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=change_kernel_button)
|
|
|
|
# self.box_group_area.pack_start(self.kernel_detail, expand=True, fill=True)
|
2012-06-04 10:52:13 +00:00
|
|
|
|
2013-07-25 07:21:06 +00:00
|
|
|
# Machine, Image recipe and Layers
|
2011-11-28 06:32:40 +00:00
|
|
|
layer_num_limit = 15
|
2013-07-25 07:21:06 +00:00
|
|
|
varlist = ["Machine: ", "Image recipe: ", "Layers: "]
|
2011-11-28 06:32:40 +00:00
|
|
|
vallist = []
|
2012-04-09 14:13:50 +00:00
|
|
|
self.setting_detail = None
|
2012-06-04 10:52:13 +00:00
|
|
|
if self.build_succeeded:
|
2011-11-28 06:32:40 +00:00
|
|
|
vallist.append(machine)
|
2013-07-25 07:25:38 +00:00
|
|
|
if self.builder.recipe_model.is_custom_image():
|
2013-07-25 07:21:06 +00:00
|
|
|
if self.builder.configuration.initial_selected_image == self.builder.recipe_model.__custom_image__:
|
|
|
|
base_image ="New image recipe"
|
|
|
|
else:
|
|
|
|
base_image = self.builder.configuration.initial_selected_image + " (edited)"
|
2011-11-28 06:32:40 +00:00
|
|
|
vallist.append(base_image)
|
|
|
|
i = 0
|
|
|
|
for layer in layers:
|
|
|
|
varlist.append(" - ")
|
|
|
|
if i > layer_num_limit:
|
|
|
|
break
|
|
|
|
i += 1
|
|
|
|
vallist.append("")
|
|
|
|
i = 0
|
|
|
|
for layer in layers:
|
|
|
|
if i > layer_num_limit:
|
|
|
|
break
|
|
|
|
elif i == layer_num_limit:
|
|
|
|
vallist.append("and more...")
|
|
|
|
else:
|
|
|
|
vallist.append(layer)
|
|
|
|
i += 1
|
|
|
|
|
2012-03-22 01:42:35 +00:00
|
|
|
edit_config_button = HobAltButton("Edit configuration")
|
2013-07-25 07:21:06 +00:00
|
|
|
edit_config_button.set_tooltip_text("Edit machine and image recipe")
|
2011-11-28 06:32:40 +00:00
|
|
|
edit_config_button.connect("clicked", self.edit_config_button_clicked_cb)
|
2012-04-09 14:13:50 +00:00
|
|
|
self.setting_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=edit_config_button)
|
2012-05-08 11:48:08 +00:00
|
|
|
self.box_group_area.pack_start(self.setting_detail, expand=True, fill=True)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
# Packages included, and Total image size
|
|
|
|
varlist = ["Packages included: ", "Total image size: "]
|
|
|
|
vallist = []
|
|
|
|
vallist.append(pkg_num)
|
2012-03-26 11:29:15 +00:00
|
|
|
vallist.append(default_image_size)
|
2013-05-07 08:07:56 +00:00
|
|
|
self.builder.configuration.image_size = default_image_size
|
|
|
|
self.builder.configuration.image_packages = self.builder.configuration.selected_packages
|
2012-06-04 10:52:13 +00:00
|
|
|
if self.build_succeeded:
|
2012-03-22 01:42:35 +00:00
|
|
|
edit_packages_button = HobAltButton("Edit packages")
|
2012-04-09 14:13:48 +00:00
|
|
|
edit_packages_button.set_tooltip_text("Edit the packages included in your image")
|
2011-11-28 06:32:40 +00:00
|
|
|
edit_packages_button.connect("clicked", self.edit_packages_button_clicked_cb)
|
|
|
|
else: # get to this page from "My images"
|
|
|
|
edit_packages_button = None
|
2012-02-29 14:15:23 +00:00
|
|
|
self.package_detail = self.DetailBox(varlist=varlist, vallist=vallist, button=edit_packages_button)
|
2012-09-26 12:13:42 +00:00
|
|
|
self.box_group_area.pack_start(self.package_detail, expand=True, fill=True)
|
2012-02-29 14:15:23 +00:00
|
|
|
|
2012-03-26 11:29:15 +00:00
|
|
|
# pack the buttons at the bottom, at this time they are already created.
|
2012-06-28 11:55:31 +00:00
|
|
|
if self.build_succeeded:
|
|
|
|
self.box_group_area.pack_end(self.details_bottom_buttons, expand=False, fill=False)
|
|
|
|
else: # for "My images" page
|
|
|
|
self.details_separator = gtk.HSeparator()
|
|
|
|
self.box_group_area.pack_start(self.details_separator, expand=False, fill=False)
|
|
|
|
self.box_group_area.pack_start(self.details_bottom_buttons, expand=False, fill=False)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
self.show_all()
|
2012-08-02 11:06:01 +00:00
|
|
|
if self.kernel_detail and (not is_runnable):
|
2012-06-04 10:52:13 +00:00
|
|
|
self.kernel_detail.hide()
|
2013-07-25 07:37:34 +00:00
|
|
|
self.image_saved = False
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-03-27 03:17:17 +00:00
|
|
|
def view_files_clicked_cb(self, button, image_addr):
|
2012-05-20 12:36:05 +00:00
|
|
|
subprocess.call("xdg-open /%s" % image_addr, shell=True)
|
2012-03-27 03:17:17 +00:00
|
|
|
|
2012-09-14 09:58:53 +00:00
|
|
|
def open_log_clicked_cb(self, button, log_file):
|
2012-08-02 11:06:01 +00:00
|
|
|
if log_file:
|
2013-01-21 14:50:40 +00:00
|
|
|
log_file = "file:///" + log_file
|
|
|
|
gtk.show_uri(screen=button.get_screen(), uri=log_file, timestamp=0)
|
2012-08-02 11:06:01 +00:00
|
|
|
|
2012-02-29 14:15:23 +00:00
|
|
|
def refresh_package_detail_box(self, image_size):
|
|
|
|
self.package_detail.update_line_widgets("Total image size: ", image_size)
|
|
|
|
|
2012-03-26 11:29:15 +00:00
|
|
|
def test_type_runnable(self, image_name):
|
2012-03-23 17:12:09 +00:00
|
|
|
type_runnable = False
|
|
|
|
for t in self.builder.parameters.runnable_image_types:
|
|
|
|
if image_name.endswith(t):
|
|
|
|
type_runnable = True
|
|
|
|
break
|
2012-03-26 11:29:15 +00:00
|
|
|
return type_runnable
|
2012-03-23 17:12:09 +00:00
|
|
|
|
2012-03-26 11:29:15 +00:00
|
|
|
def test_mach_runnable(self, image_name):
|
|
|
|
mach_runnable = False
|
2012-03-23 17:12:09 +00:00
|
|
|
for t in self.builder.parameters.runnable_machine_patterns:
|
2012-04-09 08:41:59 +00:00
|
|
|
if t in image_name:
|
2012-03-23 17:12:09 +00:00
|
|
|
mach_runnable = True
|
|
|
|
break
|
2012-03-26 11:29:15 +00:00
|
|
|
return mach_runnable
|
2012-03-23 17:12:09 +00:00
|
|
|
|
2012-03-26 11:29:15 +00:00
|
|
|
def test_deployable(self, image_name):
|
2012-10-03 09:04:17 +00:00
|
|
|
if self.builder.configuration.curr_mach.startswith("qemu"):
|
|
|
|
return False
|
2012-03-23 17:12:09 +00:00
|
|
|
deployable = False
|
|
|
|
for t in self.builder.parameters.deployable_image_types:
|
|
|
|
if image_name.endswith(t):
|
|
|
|
deployable = True
|
|
|
|
break
|
2012-03-26 11:29:15 +00:00
|
|
|
return deployable
|
2012-03-23 17:12:09 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
def get_kernel_file_name(self, kernel_addr=""):
|
|
|
|
kernel_name = ""
|
2012-05-21 14:41:22 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
if not kernel_addr:
|
|
|
|
kernel_addr = self.builder.parameters.image_addr
|
2012-05-21 14:41:22 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
files = [f for f in os.listdir(kernel_addr) if f[0] <> '.']
|
|
|
|
for check_file in files:
|
|
|
|
if check_file.endswith(".bin"):
|
|
|
|
name_splits = check_file.split(".")[0]
|
|
|
|
if self.builder.parameters.kernel_image_type in name_splits.split("-"):
|
|
|
|
kernel_name = check_file
|
|
|
|
break
|
2012-05-21 14:41:22 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
return kernel_name
|
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
def show_builded_images_dialog(self, widget, primary_action=""):
|
|
|
|
title = primary_action if primary_action else "Your builded images"
|
|
|
|
dialog = CrumbsDialog(title, self.builder,
|
2012-06-04 10:52:13 +00:00
|
|
|
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
|
2012-06-28 11:55:31 +00:00
|
|
|
dialog.set_border_width(12)
|
2012-06-04 10:52:13 +00:00
|
|
|
|
|
|
|
label = gtk.Label()
|
|
|
|
label.set_use_markup(True)
|
|
|
|
label.set_alignment(0.0, 0.5)
|
2012-09-05 07:50:33 +00:00
|
|
|
label.set_padding(12,0)
|
|
|
|
if primary_action == "Run image":
|
|
|
|
label.set_markup("<span font_desc='12'>Select the image file you want to run:</span>")
|
|
|
|
elif primary_action == "Deploy image":
|
|
|
|
label.set_markup("<span font_desc='12'>Select the image file you want to deploy:</span>")
|
|
|
|
else:
|
|
|
|
label.set_markup("<span font_desc='12'>Select the image file you want to %s</span>" % primary_action)
|
2012-06-04 10:52:13 +00:00
|
|
|
dialog.vbox.pack_start(label, expand=False, fill=False)
|
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
# filter created images as action attribution (deploy or run)
|
|
|
|
action_attr = ""
|
|
|
|
action_images = []
|
|
|
|
for fileitem in self.image_store:
|
|
|
|
action_attr = fileitem['action_attr']
|
|
|
|
if (action_attr == 'run' and primary_action == "Run image") \
|
|
|
|
or (action_attr == 'deploy' and primary_action == "Deploy image"):
|
|
|
|
action_images.append(fileitem)
|
|
|
|
|
|
|
|
# pack the corresponding 'runnable' or 'deploy' radio_buttons, if there has no more than one file.
|
|
|
|
# assume that there does not both have 'deploy' and 'runnable' files in the same building result
|
|
|
|
# in possible as design.
|
|
|
|
curr_row = 0
|
|
|
|
rows = (len(action_images)) if len(action_images) < 10 else 10
|
|
|
|
table = gtk.Table(rows, 10, True)
|
|
|
|
table.set_row_spacings(6)
|
|
|
|
table.set_col_spacing(0, 12)
|
|
|
|
table.set_col_spacing(5, 12)
|
|
|
|
|
|
|
|
sel_parent_btn = None
|
|
|
|
for fileitem in action_images:
|
|
|
|
sel_btn = gtk.RadioButton(sel_parent_btn, fileitem['type'])
|
|
|
|
sel_parent_btn = sel_btn if not sel_parent_btn else sel_parent_btn
|
|
|
|
sel_btn.set_active(fileitem['is_toggled'])
|
|
|
|
sel_btn.connect('toggled', self.table_selected_cb, fileitem)
|
|
|
|
if curr_row < 10:
|
2012-09-05 07:50:33 +00:00
|
|
|
table.attach(sel_btn, 0, 4, curr_row, curr_row + 1, xpadding=24)
|
2012-06-28 11:55:31 +00:00
|
|
|
else:
|
2012-09-05 07:50:33 +00:00
|
|
|
table.attach(sel_btn, 5, 9, curr_row - 10, curr_row - 9, xpadding=24)
|
2012-06-28 11:55:31 +00:00
|
|
|
curr_row += 1
|
|
|
|
|
2012-09-05 07:50:33 +00:00
|
|
|
dialog.vbox.pack_start(table, expand=False, fill=False, padding=6)
|
2012-06-04 10:52:13 +00:00
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
|
|
|
|
HobAltButton.style_button(button)
|
|
|
|
|
|
|
|
if primary_action:
|
|
|
|
button = dialog.add_button(primary_action, gtk.RESPONSE_YES)
|
|
|
|
HobButton.style_button(button)
|
2012-05-21 14:41:22 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
dialog.show_all()
|
|
|
|
|
|
|
|
response = dialog.run()
|
|
|
|
dialog.destroy()
|
|
|
|
|
|
|
|
if response != gtk.RESPONSE_YES:
|
|
|
|
return
|
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
for fileitem in self.image_store:
|
|
|
|
if fileitem['is_toggled']:
|
|
|
|
if fileitem['action_attr'] == 'run':
|
|
|
|
self.builder.runqemu_image(fileitem['name'], self.sel_kernel)
|
2012-07-03 11:15:55 +00:00
|
|
|
elif fileitem['action_attr'] == 'deploy':
|
2012-06-28 11:55:31 +00:00
|
|
|
self.builder.deploy_image(fileitem['name'])
|
2012-06-04 10:52:13 +00:00
|
|
|
|
2012-06-28 11:55:31 +00:00
|
|
|
def table_selected_cb(self, tbutton, image):
|
|
|
|
image['is_toggled'] = tbutton.get_active()
|
|
|
|
if image['is_toggled']:
|
|
|
|
self.toggled_image = image['name']
|
2012-06-04 10:52:13 +00:00
|
|
|
|
|
|
|
def change_kernel_cb(self, widget):
|
|
|
|
kernel_path = self.builder.show_load_kernel_dialog()
|
|
|
|
if kernel_path and self.kernel_detail:
|
|
|
|
import os.path
|
|
|
|
self.sel_kernel = os.path.basename(kernel_path)
|
|
|
|
markup = self.kernel_detail.format_line("Kernel: ", self.sel_kernel)
|
|
|
|
label = ((self.kernel_detail.get_children()[0]).get_children()[0]).get_children()[0]
|
|
|
|
label.set_markup(markup)
|
2012-05-21 14:41:22 +00:00
|
|
|
|
2012-04-09 14:13:50 +00:00
|
|
|
def create_bottom_buttons(self, buttonlist, image_name):
|
2011-11-28 06:32:40 +00:00
|
|
|
# Create the buttons at the bottom
|
|
|
|
created = False
|
2012-04-09 14:13:50 +00:00
|
|
|
packed = False
|
|
|
|
self.button_ids = {}
|
2012-06-04 10:52:13 +00:00
|
|
|
is_runnable = False
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
# create button "Deploy image"
|
|
|
|
name = "Deploy image"
|
2012-04-09 14:13:50 +00:00
|
|
|
if name in buttonlist and self.test_deployable(image_name):
|
|
|
|
deploy_button = HobButton('Deploy image')
|
2012-09-26 12:13:42 +00:00
|
|
|
#deploy_button.set_size_request(205, 49)
|
2012-04-09 14:13:50 +00:00
|
|
|
deploy_button.set_tooltip_text("Burn a live image to a USB drive or flash memory")
|
|
|
|
deploy_button.set_flags(gtk.CAN_DEFAULT)
|
2012-06-04 10:52:13 +00:00
|
|
|
button_id = deploy_button.connect("clicked", self.deploy_button_clicked_cb)
|
2012-04-09 14:13:50 +00:00
|
|
|
self.button_ids[button_id] = deploy_button
|
|
|
|
self.details_bottom_buttons.pack_end(deploy_button, expand=False, fill=False)
|
2011-11-28 06:32:40 +00:00
|
|
|
created = True
|
2012-04-09 14:13:50 +00:00
|
|
|
packed = True
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
name = "Run image"
|
2012-04-09 14:13:50 +00:00
|
|
|
if name in buttonlist and self.test_type_runnable(image_name) and self.test_mach_runnable(image_name):
|
2011-11-28 06:32:40 +00:00
|
|
|
if created == True:
|
|
|
|
# separator
|
2012-09-03 09:51:06 +00:00
|
|
|
#label = gtk.Label(" or ")
|
|
|
|
#self.details_bottom_buttons.pack_end(label, expand=False, fill=False)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-04-09 14:13:50 +00:00
|
|
|
# create button "Run image"
|
|
|
|
run_button = HobAltButton("Run image")
|
|
|
|
else:
|
|
|
|
# create button "Run image" as the primary button
|
|
|
|
run_button = HobButton("Run image")
|
2012-09-26 12:13:42 +00:00
|
|
|
#run_button.set_size_request(205, 49)
|
2012-04-09 14:13:50 +00:00
|
|
|
run_button.set_flags(gtk.CAN_DEFAULT)
|
|
|
|
packed = True
|
|
|
|
run_button.set_tooltip_text("Start up an image with qemu emulator")
|
2012-06-04 10:52:13 +00:00
|
|
|
button_id = run_button.connect("clicked", self.run_button_clicked_cb)
|
2012-04-09 14:13:50 +00:00
|
|
|
self.button_ids[button_id] = run_button
|
|
|
|
self.details_bottom_buttons.pack_end(run_button, expand=False, fill=False)
|
2011-11-28 06:32:40 +00:00
|
|
|
created = True
|
2012-06-04 10:52:13 +00:00
|
|
|
is_runnable = True
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2013-07-25 07:25:38 +00:00
|
|
|
name = "Save image recipe"
|
|
|
|
if name in buttonlist and self.builder.recipe_model.is_custom_image():
|
|
|
|
save_button = HobAltButton("Save image recipe")
|
2013-07-25 07:37:34 +00:00
|
|
|
save_button.set_sensitive(not self.image_saved)
|
2013-07-25 07:25:38 +00:00
|
|
|
button_id = save_button.connect("clicked", self.save_button_clicked_cb)
|
|
|
|
self.button_ids[button_id] = save_button
|
|
|
|
self.details_bottom_buttons.pack_end(save_button, expand=False, fill=False)
|
|
|
|
|
2011-11-28 06:32:40 +00:00
|
|
|
name = "Build new image"
|
|
|
|
if name in buttonlist:
|
|
|
|
# create button "Build new image"
|
2012-05-30 12:01:11 +00:00
|
|
|
if packed:
|
|
|
|
build_new_button = HobAltButton("Build new image")
|
|
|
|
else:
|
|
|
|
build_new_button = HobButton("Build new image")
|
|
|
|
build_new_button.set_flags(gtk.CAN_DEFAULT)
|
2012-09-26 12:13:42 +00:00
|
|
|
#build_new_button.set_size_request(205, 49)
|
2012-06-28 11:55:31 +00:00
|
|
|
self.details_bottom_buttons.pack_end(build_new_button, expand=False, fill=False)
|
2012-04-09 14:13:48 +00:00
|
|
|
build_new_button.set_tooltip_text("Create a new image from scratch")
|
2012-04-09 14:13:50 +00:00
|
|
|
button_id = build_new_button.connect("clicked", self.build_new_button_clicked_cb)
|
|
|
|
self.button_ids[button_id] = build_new_button
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
return is_runnable
|
|
|
|
|
|
|
|
def deploy_button_clicked_cb(self, button):
|
2012-06-28 11:55:31 +00:00
|
|
|
if self.toggled_image:
|
2012-07-03 11:15:55 +00:00
|
|
|
if self.num_toggled > 1:
|
2012-06-28 11:55:31 +00:00
|
|
|
self.set_sensitive(False)
|
|
|
|
self.show_builded_images_dialog(None, "Deploy image")
|
|
|
|
self.set_sensitive(True)
|
|
|
|
else:
|
|
|
|
self.builder.deploy_image(self.toggled_image)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2012-06-04 10:52:13 +00:00
|
|
|
def run_button_clicked_cb(self, button):
|
2012-06-28 11:55:31 +00:00
|
|
|
if self.toggled_image:
|
|
|
|
if self.num_toggled > 1:
|
|
|
|
self.set_sensitive(False)
|
|
|
|
self.show_builded_images_dialog(None, "Run image")
|
|
|
|
self.set_sensitive(True)
|
|
|
|
else:
|
|
|
|
self.builder.runqemu_image(self.toggled_image, self.sel_kernel)
|
2011-11-28 06:32:40 +00:00
|
|
|
|
2013-07-25 07:25:38 +00:00
|
|
|
def save_button_clicked_cb(self, button):
|
|
|
|
topdir = self.builder.get_topdir()
|
|
|
|
images_dir = topdir + "/recipes/images/"
|
2013-07-29 09:55:06 +00:00
|
|
|
self.builder.ensure_dir(images_dir)
|
|
|
|
|
2013-07-25 07:40:49 +00:00
|
|
|
dialog = SaveImageDialog(images_dir, self.name_field_template, self.description_field_template,
|
|
|
|
"Save image recipe", self.builder, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
|
2013-07-25 07:25:38 +00:00
|
|
|
response = dialog.run()
|
|
|
|
dialog.destroy()
|
|
|
|
|
2011-11-28 06:32:40 +00:00
|
|
|
def build_new_button_clicked_cb(self, button):
|
2012-04-09 14:13:36 +00:00
|
|
|
self.builder.initiate_new_build_async()
|
2011-11-28 06:32:40 +00:00
|
|
|
|
|
|
|
def edit_config_button_clicked_cb(self, button):
|
|
|
|
self.builder.show_configuration()
|
|
|
|
|
|
|
|
def edit_packages_button_clicked_cb(self, button):
|
|
|
|
self.builder.show_packages(ask=False)
|
|
|
|
|
|
|
|
def my_images_button_clicked_cb(self, button):
|
|
|
|
self.builder.show_load_my_images_dialog()
|
2012-03-28 16:10:30 +00:00
|
|
|
|
|
|
|
def settings_button_clicked_cb(self, button):
|
|
|
|
# Create an advanced settings dialog
|
2012-09-14 14:17:13 +00:00
|
|
|
response, settings_changed = self.builder.show_simple_settings_dialog()
|
2012-03-28 16:10:30 +00:00
|
|
|
if not response:
|
|
|
|
return
|
|
|
|
if settings_changed:
|
|
|
|
self.builder.reparse_post_adv_settings()
|