blob: dcc410426296ec6adf88c02d753405c4ffeb244f [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/usr/bin/env python
2#
3# BitBake Graphical GTK User Interface
4#
5# Copyright (C) 2011-2012 Intel Corporation
6#
7# Authored by Joshua Lock <josh@linux.intel.com>
8# Authored by Dongxiao Xu <dongxiao.xu@intel.com>
9# Authored by Shane Wang <shane.wang@intel.com>
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License version 2 as
13# published by the Free Software Foundation.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License along
21# with this program; if not, write to the Free Software Foundation, Inc.,
22# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24import glib
25import gtk, gobject
26import copy
27import os
28import subprocess
29import shlex
30import re
31import logging
32import sys
33import signal
34import time
35from bb.ui.crumbs.imageconfigurationpage import ImageConfigurationPage
36from bb.ui.crumbs.recipeselectionpage import RecipeSelectionPage
37from bb.ui.crumbs.packageselectionpage import PackageSelectionPage
38from bb.ui.crumbs.builddetailspage import BuildDetailsPage
39from bb.ui.crumbs.imagedetailspage import ImageDetailsPage
40from bb.ui.crumbs.sanitycheckpage import SanityCheckPage
41from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton
42from bb.ui.crumbs.persistenttooltip import PersistentTooltip
43import bb.ui.crumbs.utils
44from bb.ui.crumbs.hig.crumbsmessagedialog import CrumbsMessageDialog
45from bb.ui.crumbs.hig.simplesettingsdialog import SimpleSettingsDialog
46from bb.ui.crumbs.hig.advancedsettingsdialog import AdvancedSettingsDialog
47from bb.ui.crumbs.hig.deployimagedialog import DeployImageDialog
48from bb.ui.crumbs.hig.layerselectiondialog import LayerSelectionDialog
49from bb.ui.crumbs.hig.imageselectiondialog import ImageSelectionDialog
50from bb.ui.crumbs.hig.parsingwarningsdialog import ParsingWarningsDialog
51from bb.ui.crumbs.hig.propertydialog import PropertyDialog
52
53hobVer = 20120808
54
55class Configuration:
56 '''Represents the data structure of configuration.'''
57
58 @classmethod
59 def parse_proxy_string(cls, proxy):
60 pattern = "^\s*((http|https|ftp|socks|cvs)://)?((\S+):(\S+)@)?([^\s:]+)(:(\d+))?/?"
61 match = re.search(pattern, proxy)
62 if match:
63 return match.group(2), match.group(4), match.group(5), match.group(6), match.group(8)
64 else:
65 return None, None, None, "", ""
66
67 @classmethod
68 def make_host_string(cls, prot, user, passwd, host, default_prot=""):
69 if host == None or host == "":
70 return ""
71
72 passwd = passwd or ""
73
74 if user != None and user != "":
75 if prot == None or prot == "":
76 prot = default_prot
77 return prot + "://" + user + ":" + passwd + "@" + host
78 else:
79 if prot == None or prot == "":
80 return host
81 else:
82 return prot + "://" + host
83
84 @classmethod
85 def make_port_string(cls, port):
86 port = port or ""
87 return port
88
89 @classmethod
90 def make_proxy_string(cls, prot, user, passwd, host, port, default_prot=""):
91 if host == None or host == "":# or port == None or port == "":
92 return ""
93
94 return Configuration.make_host_string(prot, user, passwd, host, default_prot) + (":" + Configuration.make_port_string(port) if port else "")
95
96 def __init__(self):
97 self.curr_mach = ""
98 self.selected_image = None
99 # settings
100 self.curr_distro = ""
101 self.dldir = self.sstatedir = self.sstatemirror = ""
102 self.pmake = self.bbthread = 0
103 self.curr_package_format = ""
104 self.image_rootfs_size = self.image_extra_size = 0
105 self.image_overhead_factor = 1
106 self.incompat_license = ""
107 self.curr_sdk_machine = ""
108 self.conf_version = self.lconf_version = ""
109 self.extra_setting = {}
110 self.toolchain_build = False
111 self.image_fstypes = ""
112 self.image_size = None
113 self.image_packages = []
114 # bblayers.conf
115 self.layers = []
116 # image/recipes/packages
117 self.clear_selection()
118
119 self.user_selected_packages = []
120
121 self.default_task = "build"
122
123 # proxy settings
124 self.enable_proxy = None
125 self.same_proxy = False
126 self.proxies = {
127 "http" : [None, None, None, "", ""], # protocol : [prot, user, passwd, host, port]
128 "https" : [None, None, None, "", ""],
129 "ftp" : [None, None, None, "", ""],
130 "socks" : [None, None, None, "", ""],
131 "cvs" : [None, None, None, "", ""],
132 }
133
134 def clear_selection(self):
135 self.selected_recipes = []
136 self.selected_packages = []
137 self.initial_selected_image = None
138 self.initial_selected_packages = []
139 self.initial_user_selected_packages = []
140
141 def split_proxy(self, protocol, proxy):
142 entry = []
143 prot, user, passwd, host, port = Configuration.parse_proxy_string(proxy)
144 entry.append(prot)
145 entry.append(user)
146 entry.append(passwd)
147 entry.append(host)
148 entry.append(port)
149 self.proxies[protocol] = entry
150
151 def combine_proxy(self, protocol):
152 entry = self.proxies[protocol]
153 return Configuration.make_proxy_string(entry[0], entry[1], entry[2], entry[3], entry[4], protocol)
154
155 def combine_host_only(self, protocol):
156 entry = self.proxies[protocol]
157 return Configuration.make_host_string(entry[0], entry[1], entry[2], entry[3], protocol)
158
159 def combine_port_only(self, protocol):
160 entry = self.proxies[protocol]
161 return Configuration.make_port_string(entry[4])
162
163 def update(self, params):
164 # settings
165 self.curr_distro = params["distro"]
166 self.dldir = params["dldir"]
167 self.sstatedir = params["sstatedir"]
168 self.sstatemirror = params["sstatemirror"]
169 self.pmake = int(params["pmake"].split()[1])
170 self.bbthread = params["bbthread"]
171 self.curr_package_format = " ".join(params["pclass"].split("package_")).strip()
172 self.image_rootfs_size = params["image_rootfs_size"]
173 self.image_extra_size = params["image_extra_size"]
174 self.image_overhead_factor = params['image_overhead_factor']
175 self.incompat_license = params["incompat_license"]
176 self.curr_sdk_machine = params["sdk_machine"]
177 self.conf_version = params["conf_version"]
178 self.lconf_version = params["lconf_version"]
179 self.image_fstypes = params["image_fstypes"]
180 # self.extra_setting/self.toolchain_build
181 # bblayers.conf
182 self.layers = params["layer"].split()
183 self.layers_non_removable = params["layers_non_removable"].split()
184 self.default_task = params["default_task"]
185
186 # proxy settings
187 self.enable_proxy = params["http_proxy"] != "" or params["https_proxy"] != "" \
188 or params["ftp_proxy"] != "" or params["socks_proxy"] != "" \
189 or params["cvs_proxy_host"] != "" or params["cvs_proxy_port"] != ""
190 self.split_proxy("http", params["http_proxy"])
191 self.split_proxy("https", params["https_proxy"])
192 self.split_proxy("ftp", params["ftp_proxy"])
193 self.split_proxy("socks", params["socks_proxy"])
194 self.split_proxy("cvs", params["cvs_proxy_host"] + ":" + params["cvs_proxy_port"])
195
196 def save(self, handler, defaults=False):
197 # bblayers.conf
198 handler.set_var_in_file("BBLAYERS", self.layers, "bblayers.conf")
199 # local.conf
200 if not defaults:
201 handler.early_assign_var_in_file("MACHINE", self.curr_mach, "local.conf")
202 handler.set_var_in_file("DISTRO", self.curr_distro, "local.conf")
203 handler.set_var_in_file("DL_DIR", self.dldir, "local.conf")
204 handler.set_var_in_file("SSTATE_DIR", self.sstatedir, "local.conf")
205 sstate_mirror_list = self.sstatemirror.split("\\n ")
206 sstate_mirror_list_modified = []
207 for mirror in sstate_mirror_list:
208 if mirror != "":
209 mirror = mirror + "\\n"
210 sstate_mirror_list_modified.append(mirror)
211 handler.set_var_in_file("SSTATE_MIRRORS", sstate_mirror_list_modified, "local.conf")
212 handler.set_var_in_file("PARALLEL_MAKE", "-j %s" % self.pmake, "local.conf")
213 handler.set_var_in_file("BB_NUMBER_THREADS", self.bbthread, "local.conf")
214 handler.set_var_in_file("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()]), "local.conf")
215 handler.set_var_in_file("IMAGE_ROOTFS_SIZE", self.image_rootfs_size, "local.conf")
216 handler.set_var_in_file("IMAGE_EXTRA_SPACE", self.image_extra_size, "local.conf")
217 handler.set_var_in_file("INCOMPATIBLE_LICENSE", self.incompat_license, "local.conf")
218 handler.set_var_in_file("SDKMACHINE", self.curr_sdk_machine, "local.conf")
219 handler.set_var_in_file("CONF_VERSION", self.conf_version, "local.conf")
220 handler.set_var_in_file("LCONF_VERSION", self.lconf_version, "bblayers.conf")
221 handler.set_extra_config(self.extra_setting)
222 handler.set_var_in_file("TOOLCHAIN_BUILD", self.toolchain_build, "local.conf")
223 handler.set_var_in_file("IMAGE_FSTYPES", self.image_fstypes, "local.conf")
224 if not defaults:
225 # image/recipes/packages
226 handler.set_var_in_file("__SELECTED_IMAGE__", self.selected_image, "local.conf")
227 handler.set_var_in_file("DEPENDS", self.selected_recipes, "local.conf")
228 handler.set_var_in_file("IMAGE_INSTALL", self.user_selected_packages, "local.conf")
229 # proxy
230 if self.enable_proxy == True:
231 handler.set_var_in_file("http_proxy", self.combine_proxy("http"), "local.conf")
232 handler.set_var_in_file("https_proxy", self.combine_proxy("https"), "local.conf")
233 handler.set_var_in_file("ftp_proxy", self.combine_proxy("ftp"), "local.conf")
234 handler.set_var_in_file("all_proxy", self.combine_proxy("socks"), "local.conf")
235 handler.set_var_in_file("CVS_PROXY_HOST", self.combine_host_only("cvs"), "local.conf")
236 handler.set_var_in_file("CVS_PROXY_PORT", self.combine_port_only("cvs"), "local.conf")
237 else:
238 handler.set_var_in_file("http_proxy", "", "local.conf")
239 handler.set_var_in_file("https_proxy", "", "local.conf")
240 handler.set_var_in_file("ftp_proxy", "", "local.conf")
241 handler.set_var_in_file("all_proxy", "", "local.conf")
242 handler.set_var_in_file("CVS_PROXY_HOST", "", "local.conf")
243 handler.set_var_in_file("CVS_PROXY_PORT", "", "local.conf")
244
245 def __str__(self):
246 s = "VERSION: '%s', BBLAYERS: '%s', MACHINE: '%s', DISTRO: '%s', DL_DIR: '%s'," % \
247 (hobVer, " ".join(self.layers), self.curr_mach, self.curr_distro, self.dldir )
248 s += "SSTATE_DIR: '%s', SSTATE_MIRROR: '%s', PARALLEL_MAKE: '-j %s', BB_NUMBER_THREADS: '%s', PACKAGE_CLASSES: '%s', " % \
249 (self.sstatedir, self.sstatemirror, self.pmake, self.bbthread, " ".join(["package_" + i for i in self.curr_package_format.split()]))
250 s += "IMAGE_ROOTFS_SIZE: '%s', IMAGE_EXTRA_SPACE: '%s', INCOMPATIBLE_LICENSE: '%s', SDKMACHINE: '%s', CONF_VERSION: '%s', " % \
251 (self.image_rootfs_size, self.image_extra_size, self.incompat_license, self.curr_sdk_machine, self.conf_version)
252 s += "LCONF_VERSION: '%s', EXTRA_SETTING: '%s', TOOLCHAIN_BUILD: '%s', IMAGE_FSTYPES: '%s', __SELECTED_IMAGE__: '%s', " % \
253 (self.lconf_version, self.extra_setting, self.toolchain_build, self.image_fstypes, self.selected_image)
254 s += "DEPENDS: '%s', IMAGE_INSTALL: '%s', enable_proxy: '%s', use_same_proxy: '%s', http_proxy: '%s', " % \
255 (self.selected_recipes, self.user_selected_packages, self.enable_proxy, self.same_proxy, self.combine_proxy("http"))
256 s += "https_proxy: '%s', ftp_proxy: '%s', all_proxy: '%s', CVS_PROXY_HOST: '%s', CVS_PROXY_PORT: '%s'" % \
257 (self.combine_proxy("https"), self.combine_proxy("ftp"), self.combine_proxy("socks"),
258 self.combine_host_only("cvs"), self.combine_port_only("cvs"))
259 return s
260
261class Parameters:
262 '''Represents other variables like available machines, etc.'''
263
264 def __init__(self):
265 # Variables
266 self.max_threads = 65535
267 self.core_base = ""
268 self.image_addr = ""
269 self.image_types = []
270 self.runnable_image_types = []
271 self.runnable_machine_patterns = []
272 self.deployable_image_types = []
273 self.tmpdir = ""
274
275 self.all_machines = []
276 self.all_package_formats = []
277 self.all_distros = []
278 self.all_sdk_machines = []
279 self.all_layers = []
280 self.image_names = []
281 self.image_white_pattern = ""
282 self.image_black_pattern = ""
283
284 # for build log to show
285 self.bb_version = ""
286 self.target_arch = ""
287 self.target_os = ""
288 self.distro_version = ""
289 self.tune_pkgarch = ""
290
291 def update(self, params):
292 self.max_threads = params["max_threads"]
293 self.core_base = params["core_base"]
294 self.image_addr = params["image_addr"]
295 self.image_types = params["image_types"].split()
296 self.runnable_image_types = params["runnable_image_types"].split()
297 self.runnable_machine_patterns = params["runnable_machine_patterns"].split()
298 self.deployable_image_types = params["deployable_image_types"].split()
299 self.tmpdir = params["tmpdir"]
300 self.image_white_pattern = params["image_white_pattern"]
301 self.image_black_pattern = params["image_black_pattern"]
302 self.kernel_image_type = params["kernel_image_type"]
303 # for build log to show
304 self.bb_version = params["bb_version"]
305 self.target_arch = params["target_arch"]
306 self.target_os = params["target_os"]
307 self.distro_version = params["distro_version"]
308 self.tune_pkgarch = params["tune_pkgarch"]
309
310def hob_conf_filter(fn, data):
311 if fn.endswith("/local.conf"):
312 distro = data.getVar("DISTRO_HOB", False)
313 if distro:
314 if distro != "defaultsetup":
315 data.setVar("DISTRO", distro)
316 else:
317 data.delVar("DISTRO")
318
319 keys = ["MACHINE_HOB", "SDKMACHINE_HOB", "PACKAGE_CLASSES_HOB", \
320 "BB_NUMBER_THREADS_HOB", "PARALLEL_MAKE_HOB", "DL_DIR_HOB", \
321 "SSTATE_DIR_HOB", "SSTATE_MIRRORS_HOB", "INCOMPATIBLE_LICENSE_HOB"]
322 for key in keys:
323 var_hob = data.getVar(key, False)
324 if var_hob:
325 data.setVar(key.split("_HOB")[0], var_hob)
326 return
327
328 if fn.endswith("/bblayers.conf"):
329 layers = data.getVar("BBLAYERS_HOB", False)
330 if layers:
331 data.setVar("BBLAYERS", layers)
332 return
333
334class Builder(gtk.Window):
335
336 (INITIAL_CHECKS,
337 MACHINE_SELECTION,
338 RCPPKGINFO_POPULATING,
339 RCPPKGINFO_POPULATED,
340 BASEIMG_SELECTED,
341 RECIPE_SELECTION,
342 PACKAGE_GENERATING,
343 PACKAGE_GENERATED,
344 PACKAGE_SELECTION,
345 FAST_IMAGE_GENERATING,
346 IMAGE_GENERATING,
347 IMAGE_GENERATED,
348 MY_IMAGE_OPENED,
349 BACK,
350 END_NOOP) = range(15)
351
352 (SANITY_CHECK,
353 IMAGE_CONFIGURATION,
354 RECIPE_DETAILS,
355 BUILD_DETAILS,
356 PACKAGE_DETAILS,
357 IMAGE_DETAILS,
358 END_TAB) = range(7)
359
360 __step2page__ = {
361 INITIAL_CHECKS : SANITY_CHECK,
362 MACHINE_SELECTION : IMAGE_CONFIGURATION,
363 RCPPKGINFO_POPULATING : IMAGE_CONFIGURATION,
364 RCPPKGINFO_POPULATED : IMAGE_CONFIGURATION,
365 BASEIMG_SELECTED : IMAGE_CONFIGURATION,
366 RECIPE_SELECTION : RECIPE_DETAILS,
367 PACKAGE_GENERATING : BUILD_DETAILS,
368 PACKAGE_GENERATED : PACKAGE_DETAILS,
369 PACKAGE_SELECTION : PACKAGE_DETAILS,
370 FAST_IMAGE_GENERATING : BUILD_DETAILS,
371 IMAGE_GENERATING : BUILD_DETAILS,
372 IMAGE_GENERATED : IMAGE_DETAILS,
373 MY_IMAGE_OPENED : IMAGE_DETAILS,
374 END_NOOP : None,
375 }
376
377 SANITY_CHECK_MIN_DISPLAY_TIME = 5
378
379 def __init__(self, hobHandler, recipe_model, package_model):
380 super(Builder, self).__init__()
381
382 self.hob_image = "hob-image"
383
384 # handler
385 self.handler = hobHandler
386
387 # logger
388 self.logger = logging.getLogger("BitBake")
389 self.consolelog = None
390 self.current_logfile = None
391
392 # configuration and parameters
393 self.configuration = Configuration()
394 self.parameters = Parameters()
395
396 # build step
397 self.current_step = None
398 self.previous_step = None
399
400 self.stopping = False
401
402 # recipe model and package model
403 self.recipe_model = recipe_model
404 self.package_model = package_model
405
406 # Indicate whether user has customized the image
407 self.customized = False
408
409 # Indicate whether the UI is working
410 self.sensitive = True
411
412 # Indicate whether the sanity check ran
413 self.sanity_checked = False
414
415 # save parsing warnings
416 self.parsing_warnings = []
417
418 # create visual elements
419 self.create_visual_elements()
420
421 # connect the signals to functions
422 self.connect("delete-event", self.destroy_window_cb)
423 self.recipe_model.connect ("recipe-selection-changed", self.recipelist_changed_cb)
424 self.package_model.connect("package-selection-changed", self.packagelist_changed_cb)
425 self.handler.connect("config-updated", self.handler_config_updated_cb)
426 self.handler.connect("package-formats-updated", self.handler_package_formats_updated_cb)
427 self.handler.connect("parsing-started", self.handler_parsing_started_cb)
428 self.handler.connect("parsing", self.handler_parsing_cb)
429 self.handler.connect("parsing-completed", self.handler_parsing_completed_cb)
430 self.handler.build.connect("build-started", self.handler_build_started_cb)
431 self.handler.build.connect("build-succeeded", self.handler_build_succeeded_cb)
432 self.handler.build.connect("build-failed", self.handler_build_failed_cb)
433 self.handler.build.connect("build-aborted", self.handler_build_aborted_cb)
434 self.handler.build.connect("task-started", self.handler_task_started_cb)
435 self.handler.build.connect("disk-full", self.handler_disk_full_cb)
436 self.handler.build.connect("log-error", self.handler_build_failure_cb)
437 self.handler.build.connect("log-warning", self.handler_build_failure_cb)
438 self.handler.build.connect("log", self.handler_build_log_cb)
439 self.handler.build.connect("no-provider", self.handler_no_provider_cb)
440 self.handler.connect("generating-data", self.handler_generating_data_cb)
441 self.handler.connect("data-generated", self.handler_data_generated_cb)
442 self.handler.connect("command-succeeded", self.handler_command_succeeded_cb)
443 self.handler.connect("command-failed", self.handler_command_failed_cb)
444 self.handler.connect("parsing-warning", self.handler_parsing_warning_cb)
445 self.handler.connect("sanity-failed", self.handler_sanity_failed_cb)
446 self.handler.connect("recipe-populated", self.handler_recipe_populated_cb)
447 self.handler.connect("package-populated", self.handler_package_populated_cb)
448
449 self.handler.append_to_bbfiles("${TOPDIR}/recipes/images/custom/*.bb")
450 self.handler.append_to_bbfiles("${TOPDIR}/recipes/images/*.bb")
451 self.initiate_new_build_async()
452
453 signal.signal(signal.SIGINT, self.event_handle_SIGINT)
454
455 def create_visual_elements(self):
456 self.set_title("Hob")
457 self.set_icon_name("applications-development")
458 self.set_resizable(True)
459
460 try:
461 window_width = self.get_screen().get_width()
462 window_height = self.get_screen().get_height()
463 except AttributeError:
464 print "Please set DISPLAY variable before running Hob."
465 sys.exit(1)
466
467 if window_width >= hwc.MAIN_WIN_WIDTH:
468 window_width = hwc.MAIN_WIN_WIDTH
469 window_height = hwc.MAIN_WIN_HEIGHT
470 self.set_size_request(window_width, window_height)
471
472 self.vbox = gtk.VBox(False, 0)
473 self.vbox.set_border_width(0)
474 self.add(self.vbox)
475
476 # create pages
477 self.image_configuration_page = ImageConfigurationPage(self)
478 self.recipe_details_page = RecipeSelectionPage(self)
479 self.build_details_page = BuildDetailsPage(self)
480 self.package_details_page = PackageSelectionPage(self)
481 self.image_details_page = ImageDetailsPage(self)
482 self.sanity_check_page = SanityCheckPage(self)
483 self.display_sanity_check = False
484 self.sanity_check_post_func = False
485 self.had_network_error = False
486
487 self.nb = gtk.Notebook()
488 self.nb.set_show_tabs(False)
489 self.nb.insert_page(self.sanity_check_page, None, self.SANITY_CHECK)
490 self.nb.insert_page(self.image_configuration_page, None, self.IMAGE_CONFIGURATION)
491 self.nb.insert_page(self.recipe_details_page, None, self.RECIPE_DETAILS)
492 self.nb.insert_page(self.build_details_page, None, self.BUILD_DETAILS)
493 self.nb.insert_page(self.package_details_page, None, self.PACKAGE_DETAILS)
494 self.nb.insert_page(self.image_details_page, None, self.IMAGE_DETAILS)
495 self.vbox.pack_start(self.nb, expand=True, fill=True)
496
497 self.show_all()
498 self.nb.set_current_page(0)
499
500 def sanity_check_timeout(self):
501 # The minimum time for showing the 'sanity check' page has passe
502 # If someone set the 'sanity_check_post_step' meanwhile, execute it now
503 self.display_sanity_check = False
504 if self.sanity_check_post_func:
505 temp = self.sanity_check_post_func
506 self.sanity_check_post_func = None
507 temp()
508 return False
509
510 def show_sanity_check_page(self):
511 # This window must stay on screen for at least 5 seconds, according to the design document
512 self.nb.set_current_page(self.SANITY_CHECK)
513 self.sanity_check_post_step = None
514 self.display_sanity_check = True
515 self.sanity_check_page.start()
516 gobject.timeout_add(self.SANITY_CHECK_MIN_DISPLAY_TIME * 1000, self.sanity_check_timeout)
517
518 def execute_after_sanity_check(self, func):
519 if not self.display_sanity_check:
520 func()
521 else:
522 self.sanity_check_post_func = func
523
524 def generate_configuration(self):
525 if not self.sanity_checked:
526 self.show_sanity_check_page()
527 self.handler.generate_configuration()
528
529 def initiate_new_build_async(self):
530 self.configuration.selected_image = None
531 self.switch_page(self.MACHINE_SELECTION)
532 self.handler.init_cooker()
533 self.handler.set_extra_inherit("image_types")
534 self.generate_configuration()
535
536 def update_config_async(self):
537 self.set_user_config()
538 self.generate_configuration()
539 self.switch_page(self.MACHINE_SELECTION)
540
541 def sanity_check(self):
542 self.handler.trigger_sanity_check()
543
544 def populate_recipe_package_info_async(self):
545 self.switch_page(self.RCPPKGINFO_POPULATING)
546 # Parse recipes
547 self.set_user_config()
548 self.handler.generate_recipes()
549
550 def generate_packages_async(self, log = False):
551 self.switch_page(self.PACKAGE_GENERATING)
552 if log:
553 self.current_logfile = self.handler.get_logfile()
554 self.do_log(self.current_logfile)
555 # Build packages
556 _, all_recipes = self.recipe_model.get_selected_recipes()
557 self.set_user_config()
558 self.handler.reset_build()
559 self.handler.generate_packages(all_recipes, self.configuration.default_task)
560
561 def restore_initial_selected_packages(self):
562 self.package_model.set_selected_packages(self.configuration.initial_user_selected_packages, True)
563 self.package_model.set_selected_packages(self.configuration.initial_selected_packages)
564 for package in self.configuration.selected_packages:
565 if package not in self.configuration.initial_selected_packages:
566 self.package_model.exclude_item(self.package_model.find_path_for_item(package))
567
568 def fast_generate_image_async(self, log = False):
569 self.switch_page(self.FAST_IMAGE_GENERATING)
570 if log:
571 self.current_logfile = self.handler.get_logfile()
572 self.do_log(self.current_logfile)
573 # Build packages
574 _, all_recipes = self.recipe_model.get_selected_recipes()
575 self.set_user_config()
576 self.handler.reset_build()
577 self.handler.generate_packages(all_recipes, self.configuration.default_task)
578
579 def generate_image_async(self, cont = False):
580 self.switch_page(self.IMAGE_GENERATING)
581 self.handler.reset_build()
582 if not cont:
583 self.current_logfile = self.handler.get_logfile()
584 self.do_log(self.current_logfile)
585 # Build image
586 self.set_user_config()
587 toolchain_packages = []
588 base_image = None
589 if self.configuration.toolchain_build:
590 toolchain_packages = self.package_model.get_selected_packages_toolchain()
591 if self.configuration.selected_image == self.recipe_model.__custom_image__:
592 packages = self.package_model.get_selected_packages()
593 image = self.hob_image
594 base_image = self.configuration.initial_selected_image
595 else:
596 packages = []
597 image = self.configuration.selected_image
598 self.handler.generate_image(image,
599 base_image,
600 packages,
601 toolchain_packages,
602 self.configuration.default_task)
603
604 def generate_new_image(self, image, description):
605 base_image = self.configuration.initial_selected_image
606 if base_image == self.recipe_model.__custom_image__:
607 base_image = None
608 packages = self.package_model.get_selected_packages()
609 self.handler.generate_new_image(image, base_image, packages, description)
610
611 def ensure_dir(self, directory):
612 self.handler.ensure_dir(directory)
613
614 def get_parameters_sync(self):
615 return self.handler.get_parameters()
616
617 def request_package_info_async(self):
618 self.handler.request_package_info()
619
620 def cancel_build_sync(self, force=False):
621 self.handler.cancel_build(force)
622
623 def cancel_parse_sync(self):
624 self.handler.cancel_parse()
625
626 def switch_page(self, next_step):
627 # Main Workflow (Business Logic)
628 self.nb.set_current_page(self.__step2page__[next_step])
629
630 if next_step == self.MACHINE_SELECTION: # init step
631 self.image_configuration_page.show_machine()
632
633 elif next_step == self.RCPPKGINFO_POPULATING:
634 # MACHINE CHANGED action or SETTINGS CHANGED
635 # show the progress bar
636 self.image_configuration_page.show_info_populating()
637
638 elif next_step == self.RCPPKGINFO_POPULATED:
639 self.image_configuration_page.show_info_populated()
640
641 elif next_step == self.BASEIMG_SELECTED:
642 self.image_configuration_page.show_baseimg_selected()
643
644 elif next_step == self.RECIPE_SELECTION:
645 if self.recipe_model.get_selected_image() == self.recipe_model.__custom_image__:
646 self.recipe_details_page.set_recipe_curr_tab(self.recipe_details_page.ALL)
647 else:
648 self.recipe_details_page.set_recipe_curr_tab(self.recipe_details_page.INCLUDED)
649
650 elif next_step == self.PACKAGE_SELECTION:
651 self.configuration.initial_selected_packages = self.configuration.selected_packages
652 self.configuration.initial_user_selected_packages = self.configuration.user_selected_packages
653 self.package_details_page.set_title("Edit packages")
654 if self.recipe_model.get_selected_image() == self.recipe_model.__custom_image__:
655 self.package_details_page.set_packages_curr_tab(self.package_details_page.ALL)
656 else:
657 self.package_details_page.set_packages_curr_tab(self.package_details_page.INCLUDED)
658 self.package_details_page.show_page(self.current_logfile)
659
660
661 elif next_step == self.PACKAGE_GENERATING or next_step == self.FAST_IMAGE_GENERATING:
662 # both PACKAGE_GENERATING and FAST_IMAGE_GENERATING share the same page
663 self.build_details_page.show_page(next_step)
664
665 elif next_step == self.PACKAGE_GENERATED:
666 self.package_details_page.set_title("Step 2 of 2: Edit packages")
667 if self.recipe_model.get_selected_image() == self.recipe_model.__custom_image__:
668 self.package_details_page.set_packages_curr_tab(self.package_details_page.ALL)
669 else:
670 self.package_details_page.set_packages_curr_tab(self.package_details_page.INCLUDED)
671 self.package_details_page.show_page(self.current_logfile)
672
673 elif next_step == self.IMAGE_GENERATING:
674 # after packages are generated, selected_packages need to
675 # be updated in package_model per selected_image in recipe_model
676 self.build_details_page.show_page(next_step)
677
678 elif next_step == self.IMAGE_GENERATED:
679 self.image_details_page.show_page(next_step)
680
681 elif next_step == self.MY_IMAGE_OPENED:
682 self.image_details_page.show_page(next_step)
683
684 self.previous_step = self.current_step
685 self.current_step = next_step
686
687 def set_user_config_proxies(self):
688 if self.configuration.enable_proxy == True:
689 self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
690 self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
691 self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
692 self.handler.set_socks_proxy(self.configuration.combine_proxy("socks"))
693 self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
694 elif self.configuration.enable_proxy == False:
695 self.handler.set_http_proxy("")
696 self.handler.set_https_proxy("")
697 self.handler.set_ftp_proxy("")
698 self.handler.set_socks_proxy("")
699 self.handler.set_cvs_proxy("", "")
700
701 def set_user_config_extra(self):
702 self.handler.set_rootfs_size(self.configuration.image_rootfs_size)
703 self.handler.set_extra_size(self.configuration.image_extra_size)
704 self.handler.set_incompatible_license(self.configuration.incompat_license)
705 self.handler.set_sdk_machine(self.configuration.curr_sdk_machine)
706 self.handler.set_image_fstypes(self.configuration.image_fstypes)
707 self.handler.set_extra_config(self.configuration.extra_setting)
708 self.handler.set_extra_inherit("packageinfo image_types")
709 self.set_user_config_proxies()
710
711 def set_user_config(self):
712 # set bb layers
713 self.handler.set_bblayers(self.configuration.layers)
714 # set local configuration
715 self.handler.set_machine(self.configuration.curr_mach)
716 self.handler.set_package_format(self.configuration.curr_package_format)
717 self.handler.set_distro(self.configuration.curr_distro)
718 self.handler.set_dl_dir(self.configuration.dldir)
719 self.handler.set_sstate_dir(self.configuration.sstatedir)
720 self.handler.set_sstate_mirrors(self.configuration.sstatemirror)
721 self.handler.set_pmake(self.configuration.pmake)
722 self.handler.set_bbthreads(self.configuration.bbthread)
723 self.set_user_config_extra()
724
725 def update_recipe_model(self, selected_image, selected_recipes):
726 self.recipe_model.set_selected_image(selected_image)
727 self.recipe_model.set_selected_recipes(selected_recipes)
728
729 def update_package_model(self, selected_packages, user_selected_packages=None):
730 if user_selected_packages:
731 left = self.package_model.set_selected_packages(user_selected_packages, True)
732 self.configuration.user_selected_packages += left
733 left = self.package_model.set_selected_packages(selected_packages)
734 self.configuration.selected_packages += left
735
736 def update_configuration_parameters(self, params):
737 if params:
738 self.configuration.update(params)
739 self.parameters.update(params)
740
741 def set_base_image(self):
742 self.configuration.initial_selected_image = self.configuration.selected_image
743 if self.configuration.selected_image != self.recipe_model.__custom_image__:
744 self.hob_image = self.configuration.selected_image + "-edited"
745
746 def reset(self):
747 self.configuration.curr_mach = ""
748 self.configuration.clear_selection()
749 self.image_configuration_page.switch_machine_combo()
750 self.switch_page(self.MACHINE_SELECTION)
751
752 # Callback Functions
753 def handler_config_updated_cb(self, handler, which, values):
754 if which == "distro":
755 self.parameters.all_distros = values
756 elif which == "machine":
757 self.parameters.all_machines = values
758 self.image_configuration_page.update_machine_combo()
759 elif which == "machine-sdk":
760 self.parameters.all_sdk_machines = values
761
762 def handler_package_formats_updated_cb(self, handler, formats):
763 self.parameters.all_package_formats = formats
764
765 def switch_to_image_configuration_helper(self):
766 self.sanity_check_page.stop()
767 self.switch_page(self.IMAGE_CONFIGURATION)
768 self.image_configuration_page.switch_machine_combo()
769
770 def show_network_error_dialog_helper(self):
771 self.sanity_check_page.stop()
772 self.show_network_error_dialog()
773
774 def handler_command_succeeded_cb(self, handler, initcmd):
775 if initcmd == self.handler.GENERATE_CONFIGURATION:
776 if not self.configuration.curr_mach:
777 self.configuration.curr_mach = self.handler.runCommand(["getVariable", "HOB_MACHINE"]) or ""
778 self.update_configuration_parameters(self.get_parameters_sync())
779 if not self.sanity_checked:
780 self.sanity_check()
781 self.sanity_checked = True
782 elif initcmd == self.handler.SANITY_CHECK:
783 if self.had_network_error:
784 self.had_network_error = False
785 self.execute_after_sanity_check(self.show_network_error_dialog_helper)
786 else:
787 # Switch to the 'image configuration' page now, but we might need
788 # to wait for the minimum display time of the sanity check page
789 self.execute_after_sanity_check(self.switch_to_image_configuration_helper)
790 elif initcmd in [self.handler.GENERATE_RECIPES,
791 self.handler.GENERATE_PACKAGES,
792 self.handler.GENERATE_IMAGE]:
793 self.update_configuration_parameters(self.get_parameters_sync())
794 self.request_package_info_async()
795 elif initcmd == self.handler.POPULATE_PACKAGEINFO:
796 if self.current_step == self.RCPPKGINFO_POPULATING:
797 self.switch_page(self.RCPPKGINFO_POPULATED)
798 self.rcppkglist_populated()
799 return
800
801 self.rcppkglist_populated()
802 if self.current_step == self.FAST_IMAGE_GENERATING:
803 self.generate_image_async(True)
804
805 def show_error_dialog(self, msg):
806 lbl = "<b>Hob found an error</b>"
807 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg)
808 button = dialog.add_button("Close", gtk.RESPONSE_OK)
809 HobButton.style_button(button)
810 response = dialog.run()
811 dialog.destroy()
812
813 def show_warning_dialog(self):
814 dialog = ParsingWarningsDialog(title = "View warnings",
815 warnings = self.parsing_warnings,
816 parent = None,
817 flags = gtk.DIALOG_DESTROY_WITH_PARENT
818 | gtk.DIALOG_NO_SEPARATOR)
819 response = dialog.run()
820 dialog.destroy()
821
822 def show_network_error_dialog(self):
823 lbl = "<b>Hob cannot connect to the network</b>"
824 msg = msg + "Please check your network connection. If you are using a proxy server, please make sure it is configured correctly."
825 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg)
826 button = dialog.add_button("Close", gtk.RESPONSE_OK)
827 HobButton.style_button(button)
828 button = dialog.add_button("Proxy settings", gtk.RESPONSE_CANCEL)
829 HobButton.style_button(button)
830 res = dialog.run()
831 dialog.destroy()
832 if res == gtk.RESPONSE_CANCEL:
833 res, settings_changed = self.show_simple_settings_dialog(SimpleSettingsDialog.PROXIES_PAGE_ID)
834 if not res:
835 return
836 if settings_changed:
837 self.reparse_post_adv_settings()
838
839 def handler_command_failed_cb(self, handler, msg):
840 if msg:
841 self.show_error_dialog(msg)
842 self.reset()
843
844 def handler_parsing_warning_cb(self, handler, warn_msg):
845 self.parsing_warnings.append(warn_msg)
846
847 def handler_sanity_failed_cb(self, handler, msg, network_error):
848 self.reset()
849 if network_error:
850 # Mark this in an internal field. The "network error" dialog will be
851 # shown later, when a SanityCheckPassed event will be handled
852 # (as sent by sanity.bbclass)
853 self.had_network_error = True
854 else:
855 msg = msg.replace("your local.conf", "Settings")
856 self.show_error_dialog(msg)
857 self.reset()
858
859 def window_sensitive(self, sensitive):
860 self.image_configuration_page.machine_combo.set_sensitive(sensitive)
861 self.image_configuration_page.machine_combo.child.set_sensitive(sensitive)
862 self.image_configuration_page.image_combo.set_sensitive(sensitive)
863 self.image_configuration_page.image_combo.child.set_sensitive(sensitive)
864 self.image_configuration_page.layer_button.set_sensitive(sensitive)
865 self.image_configuration_page.layer_info_icon.set_sensitive(sensitive)
866 self.image_configuration_page.toolbar.set_sensitive(sensitive)
867 self.image_configuration_page.view_adv_configuration_button.set_sensitive(sensitive)
868 self.image_configuration_page.config_build_button.set_sensitive(sensitive)
869
870 self.recipe_details_page.set_sensitive(sensitive)
871 self.package_details_page.set_sensitive(sensitive)
872 self.build_details_page.set_sensitive(sensitive)
873 self.image_details_page.set_sensitive(sensitive)
874
875 if sensitive:
876 self.window.set_cursor(None)
877 else:
878 self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
879 self.sensitive = sensitive
880
881
882 def handler_generating_data_cb(self, handler):
883 self.window_sensitive(False)
884
885 def handler_data_generated_cb(self, handler):
886 self.window_sensitive(True)
887
888 def rcppkglist_populated(self):
889 selected_image = self.configuration.selected_image
890 selected_recipes = self.configuration.selected_recipes[:]
891 selected_packages = self.configuration.selected_packages[:]
892 user_selected_packages = self.configuration.user_selected_packages[:]
893
894 self.image_configuration_page.update_image_combo(self.recipe_model, selected_image)
895 self.image_configuration_page.update_image_desc()
896 self.update_recipe_model(selected_image, selected_recipes)
897 self.update_package_model(selected_packages, user_selected_packages)
898
899 def recipelist_changed_cb(self, recipe_model):
900 self.recipe_details_page.refresh_selection()
901
902 def packagelist_changed_cb(self, package_model):
903 self.package_details_page.refresh_selection()
904
905 def handler_recipe_populated_cb(self, handler):
906 self.image_configuration_page.update_progress_bar("Populating recipes", 0.99)
907
908 def handler_package_populated_cb(self, handler):
909 self.image_configuration_page.update_progress_bar("Populating packages", 1.0)
910
911 def handler_parsing_started_cb(self, handler, message):
912 if self.current_step != self.RCPPKGINFO_POPULATING:
913 return
914
915 fraction = 0
916 if message["eventname"] == "TreeDataPreparationStarted":
917 fraction = 0.6 + fraction
918 self.image_configuration_page.stop_button.set_sensitive(False)
919 self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction)
920 else:
921 self.image_configuration_page.stop_button.set_sensitive(True)
922 self.image_configuration_page.update_progress_bar(message["title"], fraction)
923
924 def handler_parsing_cb(self, handler, message):
925 if self.current_step != self.RCPPKGINFO_POPULATING:
926 return
927
928 fraction = message["current"] * 1.0/message["total"]
929 if message["eventname"] == "TreeDataPreparationProgress":
930 fraction = 0.6 + 0.38 * fraction
931 self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction)
932 else:
933 fraction = 0.6 * fraction
934 self.image_configuration_page.update_progress_bar(message["title"], fraction)
935
936 def handler_parsing_completed_cb(self, handler, message):
937 if self.current_step != self.RCPPKGINFO_POPULATING:
938 return
939
940 if message["eventname"] == "TreeDataPreparationCompleted":
941 fraction = 0.98
942 else:
943 fraction = 0.6
944 self.image_configuration_page.update_progress_bar("Generating dependency tree", fraction)
945
946 def handler_build_started_cb(self, running_build):
947 if self.current_step == self.FAST_IMAGE_GENERATING:
948 fraction = 0
949 elif self.current_step == self.IMAGE_GENERATING:
950 if self.previous_step == self.FAST_IMAGE_GENERATING:
951 fraction = 0.9
952 else:
953 fraction = 0
954 elif self.current_step == self.PACKAGE_GENERATING:
955 fraction = 0
956 self.build_details_page.update_progress_bar("Build Started: ", fraction)
957 self.build_details_page.show_configurations(self.configuration, self.parameters)
958
959 def build_succeeded(self):
960 if self.current_step == self.FAST_IMAGE_GENERATING:
961 fraction = 0.9
962 elif self.current_step == self.IMAGE_GENERATING:
963 fraction = 1.0
964 version = ""
965 self.parameters.image_names = []
966 selected_image = self.recipe_model.get_selected_image()
967 if selected_image == self.recipe_model.__custom_image__:
968 if self.configuration.initial_selected_image != selected_image:
969 version = self.recipe_model.get_custom_image_version()
970 linkname = self.hob_image + version + "-" + self.configuration.curr_mach
971 else:
972 linkname = selected_image + '-' + self.configuration.curr_mach
973 image_extension = self.get_image_extension()
974 for image_type in self.parameters.image_types:
975 if image_type in image_extension:
976 real_types = image_extension[image_type]
977 else:
978 real_types = [image_type]
979 for real_image_type in real_types:
980 linkpath = self.parameters.image_addr + '/' + linkname + '.' + real_image_type
981 if os.path.exists(linkpath):
982 self.parameters.image_names.append(os.readlink(linkpath))
983 elif self.current_step == self.PACKAGE_GENERATING:
984 fraction = 1.0
985 self.build_details_page.update_progress_bar("Build Completed: ", fraction)
986 self.handler.build_succeeded_async()
987 self.stopping = False
988
989 if self.current_step == self.PACKAGE_GENERATING:
990 self.switch_page(self.PACKAGE_GENERATED)
991 elif self.current_step == self.IMAGE_GENERATING:
992 self.switch_page(self.IMAGE_GENERATED)
993
994 def build_failed(self):
995 if self.stopping:
996 status = "stop"
997 message = "Build stopped: "
998 fraction = self.build_details_page.progress_bar.get_fraction()
999 stop_to_next_edit = ""
1000 if self.current_step == self.FAST_IMAGE_GENERATING:
1001 stop_to_next_edit = "image configuration"
1002 elif self.current_step == self.IMAGE_GENERATING:
1003 if self.previous_step == self.FAST_IMAGE_GENERATING:
1004 stop_to_next_edit = "image configuration"
1005 else:
1006 stop_to_next_edit = "packages"
1007 elif self.current_step == self.PACKAGE_GENERATING:
1008 stop_to_next_edit = "recipes"
1009 button = self.build_details_page.show_stop_page(stop_to_next_edit.split(' ')[0])
1010 self.set_default(button)
1011 else:
1012 fail_to_next_edit = ""
1013 if self.current_step == self.FAST_IMAGE_GENERATING:
1014 fail_to_next_edit = "image configuration"
1015 fraction = 0.9
1016 elif self.current_step == self.IMAGE_GENERATING:
1017 if self.previous_step == self.FAST_IMAGE_GENERATING:
1018 fail_to_next_edit = "image configuration"
1019 else:
1020 fail_to_next_edit = "packages"
1021 fraction = 1.0
1022 elif self.current_step == self.PACKAGE_GENERATING:
1023 fail_to_next_edit = "recipes"
1024 fraction = 1.0
1025 self.build_details_page.show_fail_page(fail_to_next_edit.split(' ')[0])
1026 status = "fail"
1027 message = "Build failed: "
1028 self.build_details_page.update_progress_bar(message, fraction, status)
1029 self.build_details_page.show_back_button()
1030 self.build_details_page.hide_stop_button()
1031 self.handler.build_failed_async()
1032 self.stopping = False
1033
1034 def handler_build_succeeded_cb(self, running_build):
1035 if not self.stopping:
1036 self.build_succeeded()
1037 else:
1038 self.build_failed()
1039
1040
1041 def handler_build_failed_cb(self, running_build):
1042 self.build_failed()
1043
1044 def handler_build_aborted_cb(self, running_build):
1045 self.build_failed()
1046
1047 def handler_no_provider_cb(self, running_build, msg):
1048 dialog = CrumbsMessageDialog(self, glib.markup_escape_text(msg), gtk.MESSAGE_INFO)
1049 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1050 HobButton.style_button(button)
1051 dialog.run()
1052 dialog.destroy()
1053 self.build_failed()
1054
1055 def handler_task_started_cb(self, running_build, message):
1056 fraction = message["current"] * 1.0/message["total"]
1057 title = "Build packages"
1058 if self.current_step == self.FAST_IMAGE_GENERATING:
1059 if message["eventname"] == "sceneQueueTaskStarted":
1060 fraction = 0.27 * fraction
1061 elif message["eventname"] == "runQueueTaskStarted":
1062 fraction = 0.27 + 0.63 * fraction
1063 elif self.current_step == self.IMAGE_GENERATING:
1064 title = "Build image"
1065 if self.previous_step == self.FAST_IMAGE_GENERATING:
1066 if message["eventname"] == "sceneQueueTaskStarted":
1067 fraction = 0.27 + 0.63 + 0.03 * fraction
1068 elif message["eventname"] == "runQueueTaskStarted":
1069 fraction = 0.27 + 0.63 + 0.03 + 0.07 * fraction
1070 else:
1071 if message["eventname"] == "sceneQueueTaskStarted":
1072 fraction = 0.2 * fraction
1073 elif message["eventname"] == "runQueueTaskStarted":
1074 fraction = 0.2 + 0.8 * fraction
1075 elif self.current_step == self.PACKAGE_GENERATING:
1076 if message["eventname"] == "sceneQueueTaskStarted":
1077 fraction = 0.2 * fraction
1078 elif message["eventname"] == "runQueueTaskStarted":
1079 fraction = 0.2 + 0.8 * fraction
1080 self.build_details_page.update_progress_bar(title + ": ", fraction)
1081 self.build_details_page.update_build_status(message["current"], message["total"], message["task"])
1082
1083 def handler_disk_full_cb(self, running_build):
1084 self.disk_full = True
1085
1086 def handler_build_failure_cb(self, running_build):
1087 self.build_details_page.show_issues()
1088
1089 def handler_build_log_cb(self, running_build, func, obj):
1090 if hasattr(self.logger, func):
1091 getattr(self.logger, func)(obj)
1092
1093 def destroy_window_cb(self, widget, event):
1094 if not self.sensitive:
1095 return True
1096 elif self.handler.building:
1097 self.stop_build()
1098 return True
1099 else:
1100 gtk.main_quit()
1101
1102 def event_handle_SIGINT(self, signal, frame):
1103 for w in gtk.window_list_toplevels():
1104 if w.get_modal():
1105 w.response(gtk.RESPONSE_DELETE_EVENT)
1106 sys.exit(0)
1107
1108 def build_packages(self):
1109 _, all_recipes = self.recipe_model.get_selected_recipes()
1110 if not all_recipes:
1111 lbl = "<b>No selections made</b>"
1112 msg = "You have not made any selections"
1113 msg = msg + " so there isn't anything to bake at this time."
1114 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
1115 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1116 HobButton.style_button(button)
1117 dialog.run()
1118 dialog.destroy()
1119 return
1120 self.generate_packages_async(True)
1121
1122 def build_image(self):
1123 selected_packages = self.package_model.get_selected_packages()
1124 if not selected_packages:
1125 lbl = "<b>No selections made</b>"
1126 msg = "You have not made any selections"
1127 msg = msg + " so there isn't anything to bake at this time."
1128 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
1129 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1130 HobButton.style_button(button)
1131 dialog.run()
1132 dialog.destroy()
1133 return
1134 self.generate_image_async(True)
1135
1136 def just_bake(self):
1137 selected_image = self.recipe_model.get_selected_image()
1138 selected_packages = self.package_model.get_selected_packages() or []
1139
1140 # If no base image and no selected packages don't build anything
1141 if not (selected_packages or selected_image != self.recipe_model.__custom_image__):
1142 lbl = "<b>No selections made</b>"
1143 msg = "You have not made any selections"
1144 msg = msg + " so there isn't anything to bake at this time."
1145 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
1146 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1147 HobButton.style_button(button)
1148 dialog.run()
1149 dialog.destroy()
1150 return
1151
1152 self.fast_generate_image_async(True)
1153
1154 def show_recipe_property_dialog(self, properties):
1155 information = {}
1156 dialog = PropertyDialog(title = properties["name"] +' '+ "properties",
1157 parent = self,
1158 information = properties,
1159 flags = gtk.DIALOG_DESTROY_WITH_PARENT
1160 | gtk.DIALOG_NO_SEPARATOR)
1161
1162 dialog.set_modal(False)
1163
1164 button = dialog.add_button("Close", gtk.RESPONSE_NO)
1165 HobAltButton.style_button(button)
1166 button.connect("clicked", lambda w: dialog.destroy())
1167
1168 dialog.run()
1169
1170 def show_packages_property_dialog(self, properties):
1171 information = {}
1172 dialog = PropertyDialog(title = properties["name"] +' '+ "properties",
1173 parent = self,
1174 information = properties,
1175 flags = gtk.DIALOG_DESTROY_WITH_PARENT
1176 | gtk.DIALOG_NO_SEPARATOR)
1177
1178 dialog.set_modal(False)
1179
1180 button = dialog.add_button("Close", gtk.RESPONSE_NO)
1181 HobAltButton.style_button(button)
1182 button.connect("clicked", lambda w: dialog.destroy())
1183
1184 dialog.run()
1185
1186 def show_layer_selection_dialog(self):
1187 dialog = LayerSelectionDialog(title = "Layers",
1188 layers = copy.deepcopy(self.configuration.layers),
1189 layers_non_removable = copy.deepcopy(self.configuration.layers_non_removable),
1190 all_layers = self.parameters.all_layers,
1191 parent = self,
1192 flags = gtk.DIALOG_MODAL
1193 | gtk.DIALOG_DESTROY_WITH_PARENT
1194 | gtk.DIALOG_NO_SEPARATOR)
1195 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1196 HobAltButton.style_button(button)
1197 button = dialog.add_button("OK", gtk.RESPONSE_YES)
1198 HobButton.style_button(button)
1199 response = dialog.run()
1200 if response == gtk.RESPONSE_YES:
1201 self.configuration.layers = dialog.layers
1202 # DO refresh layers
1203 if dialog.layers_changed:
1204 self.update_config_async()
1205 dialog.destroy()
1206
1207 def get_image_extension(self):
1208 image_extension = {}
1209 for type in self.parameters.image_types:
1210 ext = self.handler.runCommand(["getVariable", "IMAGE_EXTENSION_%s" % type])
1211 if ext:
1212 image_extension[type] = ext.split(' ')
1213
1214 return image_extension
1215
1216 def show_load_my_images_dialog(self):
1217 image_extension = self.get_image_extension()
1218 dialog = ImageSelectionDialog(self.parameters.image_addr, self.parameters.image_types,
1219 "Open My Images", self,
1220 gtk.FILE_CHOOSER_ACTION_SAVE, None,
1221 image_extension)
1222 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1223 HobAltButton.style_button(button)
1224 button = dialog.add_button("Open", gtk.RESPONSE_YES)
1225 HobButton.style_button(button)
1226 response = dialog.run()
1227 if response == gtk.RESPONSE_YES:
1228 if not dialog.image_names:
1229 lbl = "<b>No selections made</b>"
1230 msg = "You have not made any selections"
1231 crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO, msg)
1232 button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
1233 HobButton.style_button(button)
1234 crumbs_dialog.run()
1235 crumbs_dialog.destroy()
1236 dialog.destroy()
1237 return
1238
1239 self.parameters.image_addr = dialog.image_folder
1240 self.parameters.image_names = dialog.image_names[:]
1241 self.switch_page(self.MY_IMAGE_OPENED)
1242
1243 dialog.destroy()
1244
1245 def show_adv_settings_dialog(self, tab=None):
1246 dialog = AdvancedSettingsDialog(title = "Advanced configuration",
1247 configuration = copy.deepcopy(self.configuration),
1248 all_image_types = self.parameters.image_types,
1249 all_package_formats = self.parameters.all_package_formats,
1250 all_distros = self.parameters.all_distros,
1251 all_sdk_machines = self.parameters.all_sdk_machines,
1252 max_threads = self.parameters.max_threads,
1253 parent = self,
1254 flags = gtk.DIALOG_MODAL
1255 | gtk.DIALOG_DESTROY_WITH_PARENT
1256 | gtk.DIALOG_NO_SEPARATOR)
1257 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1258 HobAltButton.style_button(button)
1259 button = dialog.add_button("Save", gtk.RESPONSE_YES)
1260 HobButton.style_button(button)
1261 dialog.set_save_button(button)
1262 response = dialog.run()
1263 settings_changed = False
1264 if response == gtk.RESPONSE_YES:
1265 self.configuration = dialog.configuration
1266 self.configuration.save(self.handler, True) # remember settings
1267 settings_changed = dialog.settings_changed
1268 dialog.destroy()
1269 return response == gtk.RESPONSE_YES, settings_changed
1270
1271 def show_simple_settings_dialog(self, tab=None):
1272 dialog = SimpleSettingsDialog(title = "Settings",
1273 configuration = copy.deepcopy(self.configuration),
1274 all_image_types = self.parameters.image_types,
1275 all_package_formats = self.parameters.all_package_formats,
1276 all_distros = self.parameters.all_distros,
1277 all_sdk_machines = self.parameters.all_sdk_machines,
1278 max_threads = self.parameters.max_threads,
1279 parent = self,
1280 flags = gtk.DIALOG_MODAL
1281 | gtk.DIALOG_DESTROY_WITH_PARENT
1282 | gtk.DIALOG_NO_SEPARATOR,
1283 handler = self.handler)
1284 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1285 HobAltButton.style_button(button)
1286 button = dialog.add_button("Save", gtk.RESPONSE_YES)
1287 HobButton.style_button(button)
1288 if tab:
1289 dialog.switch_to_page(tab)
1290 response = dialog.run()
1291 settings_changed = False
1292 if response == gtk.RESPONSE_YES:
1293 self.configuration = dialog.configuration
1294 self.configuration.save(self.handler, True) # remember settings
1295 settings_changed = dialog.settings_changed
1296 if dialog.proxy_settings_changed:
1297 self.set_user_config_proxies()
1298 elif dialog.proxy_test_ran:
1299 # The user might have modified the proxies in the "Proxy"
1300 # tab, which in turn made the proxy settings modify in bb.
1301 # If "Cancel" was pressed, restore the previous proxy
1302 # settings inside bb.
1303 self.set_user_config_proxies()
1304 dialog.destroy()
1305 return response == gtk.RESPONSE_YES, settings_changed
1306
1307 def reparse_post_adv_settings(self):
1308 if not self.configuration.curr_mach:
1309 self.update_config_async()
1310 else:
1311 self.configuration.clear_selection()
1312 # DO reparse recipes
1313 self.populate_recipe_package_info_async()
1314
1315 def deploy_image(self, image_name):
1316 if not image_name:
1317 lbl = "<b>Please select an image to deploy.</b>"
1318 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO)
1319 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1320 HobButton.style_button(button)
1321 dialog.run()
1322 dialog.destroy()
1323 return
1324
1325 image_path = os.path.join(self.parameters.image_addr, image_name)
1326 dialog = DeployImageDialog(title = "Usb Image Maker",
1327 image_path = image_path,
1328 parent = self,
1329 flags = gtk.DIALOG_MODAL
1330 | gtk.DIALOG_DESTROY_WITH_PARENT
1331 | gtk.DIALOG_NO_SEPARATOR)
1332 button = dialog.add_button("Close", gtk.RESPONSE_NO)
1333 HobAltButton.style_button(button)
1334 button = dialog.add_button("Make usb image", gtk.RESPONSE_YES)
1335 HobButton.style_button(button)
1336 response = dialog.run()
1337 dialog.destroy()
1338
1339 def show_load_kernel_dialog(self):
1340 dialog = gtk.FileChooserDialog("Load Kernel Files", self,
1341 gtk.FILE_CHOOSER_ACTION_SAVE)
1342 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1343 HobAltButton.style_button(button)
1344 button = dialog.add_button("Open", gtk.RESPONSE_YES)
1345 HobButton.style_button(button)
1346 filter = gtk.FileFilter()
1347 filter.set_name("Kernel Files")
1348 filter.add_pattern("*.bin")
1349 dialog.add_filter(filter)
1350
1351 dialog.set_current_folder(self.parameters.image_addr)
1352
1353 response = dialog.run()
1354 kernel_path = ""
1355 if response == gtk.RESPONSE_YES:
1356 kernel_path = dialog.get_filename()
1357
1358 dialog.destroy()
1359
1360 return kernel_path
1361
1362 def runqemu_image(self, image_name, kernel_name):
1363 if not image_name or not kernel_name:
1364 lbl = "<b>Please select %s to launch in QEMU.</b>" % ("a kernel" if image_name else "an image")
1365 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_INFO)
1366 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1367 HobButton.style_button(button)
1368 dialog.run()
1369 dialog.destroy()
1370 return
1371
1372 kernel_path = os.path.join(self.parameters.image_addr, kernel_name)
1373 image_path = os.path.join(self.parameters.image_addr, image_name)
1374
1375 source_env_path = os.path.join(self.parameters.core_base, "oe-init-build-env")
1376 tmp_path = self.parameters.tmpdir
1377 cmdline = bb.ui.crumbs.utils.which_terminal()
1378 if os.path.exists(image_path) and os.path.exists(kernel_path) \
1379 and os.path.exists(source_env_path) and os.path.exists(tmp_path) \
1380 and cmdline:
1381 cmdline += "\' bash -c \"export OE_TMPDIR=" + tmp_path + "; "
1382 cmdline += "source " + source_env_path + " " + os.getcwd() + "; "
1383 cmdline += "runqemu " + kernel_path + " " + image_path + "\"\'"
1384 subprocess.Popen(shlex.split(cmdline))
1385 else:
1386 lbl = "<b>Path error</b>"
1387 msg = "One of your paths is wrong,"
1388 msg = msg + " please make sure the following paths exist:\n"
1389 msg = msg + "image path:" + image_path + "\n"
1390 msg = msg + "kernel path:" + kernel_path + "\n"
1391 msg = msg + "source environment path:" + source_env_path + "\n"
1392 msg = msg + "tmp path: " + tmp_path + "."
1393 msg = msg + "You may be missing either xterm or vte for terminal services."
1394 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_ERROR, msg)
1395 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1396 HobButton.style_button(button)
1397 dialog.run()
1398 dialog.destroy()
1399
1400 def show_packages(self):
1401 self.package_details_page.refresh_tables()
1402 self.switch_page(self.PACKAGE_SELECTION)
1403
1404 def show_recipes(self):
1405 self.switch_page(self.RECIPE_SELECTION)
1406
1407 def show_image_details(self):
1408 self.switch_page(self.IMAGE_GENERATED)
1409
1410 def show_configuration(self):
1411 self.switch_page(self.BASEIMG_SELECTED)
1412
1413 def stop_build(self):
1414 if self.stopping:
1415 lbl = "<b>Force Stop build?</b>"
1416 msg = "You've already selected Stop once,"
1417 msg = msg + " would you like to 'Force Stop' the build?\n\n"
1418 msg = msg + "This will stop the build as quickly as possible but may"
1419 msg = msg + " well leave your build directory in an unusable state"
1420 msg = msg + " that requires manual steps to fix."
1421 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg)
1422 button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
1423 HobAltButton.style_button(button)
1424 button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
1425 HobButton.style_button(button)
1426 else:
1427 lbl = "<b>Stop build?</b>"
1428 msg = "Are you sure you want to stop this"
1429 msg = msg + " build?\n\n'Stop' will stop the build as soon as all in"
1430 msg = msg + " progress build tasks are finished. However if a"
1431 msg = msg + " lengthy compilation phase is in progress this may take"
1432 msg = msg + " some time.\n\n"
1433 msg = msg + "'Force Stop' will stop the build as quickly as"
1434 msg = msg + " possible but may well leave your build directory in an"
1435 msg = msg + " unusable state that requires manual steps to fix."
1436 dialog = CrumbsMessageDialog(self, lbl, gtk.MESSAGE_WARNING, msg)
1437 button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
1438 HobAltButton.style_button(button)
1439 button = dialog.add_button("Force stop", gtk.RESPONSE_YES)
1440 HobAltButton.style_button(button)
1441 button = dialog.add_button("Stop", gtk.RESPONSE_OK)
1442 HobButton.style_button(button)
1443 response = dialog.run()
1444 dialog.destroy()
1445 if response != gtk.RESPONSE_CANCEL:
1446 self.stopping = True
1447 if response == gtk.RESPONSE_OK:
1448 self.build_details_page.progress_bar.set_stop_title("Stopping the build....")
1449 self.build_details_page.progress_bar.set_rcstyle("stop")
1450 self.cancel_build_sync()
1451 elif response == gtk.RESPONSE_YES:
1452 self.cancel_build_sync(True)
1453
1454 def do_log(self, consolelogfile = None):
1455 if consolelogfile:
1456 bb.utils.mkdirhier(os.path.dirname(consolelogfile))
1457 if self.consolelog:
1458 self.logger.removeHandler(self.consolelog)
1459 self.consolelog = None
1460 self.consolelog = logging.FileHandler(consolelogfile)
1461 bb.msg.addDefaultlogFilter(self.consolelog)
1462 format = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
1463 self.consolelog.setFormatter(format)
1464
1465 self.logger.addHandler(self.consolelog)
1466
1467 def get_topdir(self):
1468 return self.handler.get_topdir()
1469
1470 def wait(self, delay):
1471 time_start = time.time()
1472 time_end = time_start + delay
1473 while time_end > time.time():
1474 while gtk.events_pending():
1475 gtk.main_iteration()