3 # BitBake Graphical GTK User Interface
5 # Copyright (C) 2011-2012 Intel Corporation
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>
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.
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.
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.
29 from bb.ui.crumbs.template import TemplateMgr
30 from bb.ui.crumbs.imageconfigurationpage import ImageConfigurationPage
31 from bb.ui.crumbs.recipeselectionpage import RecipeSelectionPage
32 from bb.ui.crumbs.packageselectionpage import PackageSelectionPage
33 from bb.ui.crumbs.builddetailspage import BuildDetailsPage
34 from bb.ui.crumbs.imagedetailspage import ImageDetailsPage
35 from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton
36 from bb.ui.crumbs.hig import CrumbsMessageDialog, ImageSelectionDialog, \
37 AdvancedSettingDialog, LayerSelectionDialog, \
39 from bb.ui.crumbs.persistenttooltip import PersistentTooltip
42 '''Represents the data structure of configuration.'''
44 def __init__(self, params):
47 self.curr_distro = params["distro"]
48 self.dldir = params["dldir"]
49 self.sstatedir = params["sstatedir"]
50 self.sstatemirror = params["sstatemirror"]
51 self.pmake = params["pmake"]
52 self.bbthread = params["bbthread"]
53 self.curr_package_format = " ".join(params["pclass"].split("package_")).strip()
54 self.image_rootfs_size = params["image_rootfs_size"]
55 self.image_extra_size = params["image_extra_size"]
56 self.image_overhead_factor = params['image_overhead_factor']
57 self.incompat_license = params["incompat_license"]
58 self.curr_sdk_machine = params["sdk_machine"]
59 self.conf_version = params["conf_version"]
60 self.lconf_version = params["lconf_version"]
61 self.extra_setting = {}
62 self.toolchain_build = False
63 self.image_fstypes = params["image_fstypes"].split()
65 self.layers = params["layer"].split()
66 # image/recipes/packages
67 self.selected_image = None
68 self.selected_recipes = []
69 self.selected_packages = []
71 def load(self, template):
72 self.curr_mach = template.getVar("MACHINE")
73 self.curr_package_format = " ".join(template.getVar("PACKAGE_CLASSES").split("package_")).strip()
74 self.curr_distro = template.getVar("DISTRO")
75 self.dldir = template.getVar("DL_DIR")
76 self.sstatedir = template.getVar("SSTATE_DIR")
77 self.sstatemirror = template.getVar("SSTATE_MIRROR")
78 self.pmake = int(template.getVar("PARALLEL_MAKE").split()[1])
79 self.bbthread = int(template.getVar("BB_NUMBER_THREADS"))
80 self.image_rootfs_size = int(template.getVar("IMAGE_ROOTFS_SIZE"))
81 self.image_extra_size = int(template.getVar("IMAGE_EXTRA_SPACE"))
82 # image_overhead_factor is read-only.
83 self.incompat_license = template.getVar("INCOMPATIBLE_LICENSE")
84 self.curr_sdk_machine = template.getVar("SDKMACHINE")
85 self.conf_version = template.getVar("CONF_VERSION")
86 self.lconf_version = template.getVar("LCONF_VERSION")
87 self.extra_setting = eval(template.getVar("EXTRA_SETTING"))
88 self.toolchain_build = eval(template.getVar("TOOLCHAIN_BUILD"))
89 self.image_fstypes = template.getVar("IMAGE_FSTYPES").split()
91 self.layers = template.getVar("BBLAYERS").split()
92 # image/recipes/packages
93 self.selected_image = template.getVar("__SELECTED_IMAGE__")
94 self.selected_recipes = template.getVar("DEPENDS").split()
95 self.selected_packages = template.getVar("IMAGE_INSTALL").split()
97 def save(self, template, filename):
99 template.setVar("BBLAYERS", " ".join(self.layers))
101 template.setVar("MACHINE", self.curr_mach)
102 template.setVar("DISTRO", self.curr_distro)
103 template.setVar("DL_DIR", self.dldir)
104 template.setVar("SSTATE_DIR", self.sstatedir)
105 template.setVar("SSTATE_MIRROR", self.sstatemirror)
106 template.setVar("PARALLEL_MAKE", "-j %s" % self.pmake)
107 template.setVar("BB_NUMBER_THREADS", self.bbthread)
108 template.setVar("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()]))
109 template.setVar("IMAGE_ROOTFS_SIZE", self.image_rootfs_size)
110 template.setVar("IMAGE_EXTRA_SPACE", self.image_extra_size)
111 template.setVar("INCOMPATIBLE_LICENSE", self.incompat_license)
112 template.setVar("SDKMACHINE", self.curr_sdk_machine)
113 template.setVar("CONF_VERSION", self.conf_version)
114 template.setVar("LCONF_VERSION", self.lconf_version)
115 template.setVar("EXTRA_SETTING", self.extra_setting)
116 template.setVar("TOOLCHAIN_BUILD", self.toolchain_build)
117 template.setVar("IMAGE_FSTYPES", " ".join(self.image_fstypes).lstrip(" "))
118 # image/recipes/packages
119 self.selected_image = filename
120 template.setVar("__SELECTED_IMAGE__", self.selected_image)
121 template.setVar("DEPENDS", self.selected_recipes)
122 template.setVar("IMAGE_INSTALL", self.selected_packages)
125 '''Represents other variables like available machines, etc.'''
127 def __init__(self, params):
129 self.all_machines = []
130 self.all_package_formats = []
131 self.all_distros = []
132 self.all_sdk_machines = []
133 self.max_threads = params["max_threads"]
135 self.core_base = params["core_base"]
136 self.image_names = []
137 self.image_addr = params["image_addr"]
138 self.image_types = params["image_types"].split()
139 self.runnable_image_types = params["runnable_image_types"].split()
140 self.runnable_machine_patterns = params["runnable_machine_patterns"].split()
141 self.deployable_image_types = params["deployable_image_types"].split()
142 self.tmpdir = params["tmpdir"]
144 class Builder(gtk.Window):
148 RCPPKGINFO_POPULATING,
149 RCPPKGINFO_POPULATED,
155 FAST_IMAGE_GENERATING,
160 END_NOOP) = range(15)
162 (IMAGE_CONFIGURATION,
170 MACHINE_SELECTION : IMAGE_CONFIGURATION,
171 LAYER_CHANGED : IMAGE_CONFIGURATION,
172 RCPPKGINFO_POPULATING : IMAGE_CONFIGURATION,
173 RCPPKGINFO_POPULATED : IMAGE_CONFIGURATION,
174 BASEIMG_SELECTED : IMAGE_CONFIGURATION,
175 RECIPE_SELECTION : RECIPE_DETAILS,
176 PACKAGE_GENERATING : BUILD_DETAILS,
177 PACKAGE_GENERATED : PACKAGE_DETAILS,
178 PACKAGE_SELECTION : PACKAGE_DETAILS,
179 FAST_IMAGE_GENERATING : BUILD_DETAILS,
180 IMAGE_GENERATING : BUILD_DETAILS,
181 IMAGE_GENERATED : IMAGE_DETAILS,
182 MY_IMAGE_OPENED : IMAGE_DETAILS,
186 def __init__(self, hobHandler, recipe_model, package_model):
187 super(Builder, self).__init__()
190 self.handler = hobHandler
195 self.current_step = None
196 self.previous_step = None
198 self.stopping = False
200 # recipe model and package model
201 self.recipe_model = recipe_model
202 self.package_model = package_model
204 # create visual elements
205 self.create_visual_elements()
207 # connect the signals to functions
208 self.connect("delete-event", self.destroy_window_cb)
209 self.recipe_model.connect ("recipe-selection-changed", self.recipelist_changed_cb)
210 self.package_model.connect("package-selection-changed", self.packagelist_changed_cb)
211 self.handler.connect("config-updated", self.handler_config_updated_cb)
212 self.handler.connect("package-formats-updated", self.handler_package_formats_updated_cb)
213 self.handler.connect("layers-updated", self.handler_layers_updated_cb)
214 self.handler.connect("parsing-started", self.handler_parsing_started_cb)
215 self.handler.connect("parsing", self.handler_parsing_cb)
216 self.handler.connect("parsing-completed", self.handler_parsing_completed_cb)
217 self.handler.build.connect("build-started", self.handler_build_started_cb)
218 self.handler.build.connect("build-succeeded", self.handler_build_succeeded_cb)
219 self.handler.build.connect("build-failed", self.handler_build_failed_cb)
220 self.handler.build.connect("task-started", self.handler_task_started_cb)
221 self.handler.build.connect("log-error", self.handler_build_failure_cb)
222 self.handler.connect("generating-data", self.handler_generating_data_cb)
223 self.handler.connect("data-generated", self.handler_data_generated_cb)
224 self.handler.connect("command-succeeded", self.handler_command_succeeded_cb)
225 self.handler.connect("command-failed", self.handler_command_failed_cb)
227 self.handler.init_cooker()
228 self.handler.set_extra_inherit("image_types")
229 self.handler.parse_config()
231 self.switch_page(self.MACHINE_SELECTION)
233 def create_visual_elements(self):
234 self.set_title("Hob")
235 self.set_icon_name("applications-development")
236 self.set_resizable(True)
237 window_width = self.get_screen().get_width()
238 window_height = self.get_screen().get_height()
239 if window_width >= hwc.MAIN_WIN_WIDTH:
240 window_width = hwc.MAIN_WIN_WIDTH
241 window_height = hwc.MAIN_WIN_HEIGHT
242 self.set_size_request(window_width, window_height)
244 self.vbox = gtk.VBox(False, 0)
245 self.vbox.set_border_width(0)
249 self.image_configuration_page = ImageConfigurationPage(self)
250 self.recipe_details_page = RecipeSelectionPage(self)
251 self.build_details_page = BuildDetailsPage(self)
252 self.package_details_page = PackageSelectionPage(self)
253 self.image_details_page = ImageDetailsPage(self)
255 self.nb = gtk.Notebook()
256 self.nb.set_show_tabs(False)
257 self.nb.insert_page(self.image_configuration_page, None, self.IMAGE_CONFIGURATION)
258 self.nb.insert_page(self.recipe_details_page, None, self.RECIPE_DETAILS)
259 self.nb.insert_page(self.build_details_page, None, self.BUILD_DETAILS)
260 self.nb.insert_page(self.package_details_page, None, self.PACKAGE_DETAILS)
261 self.nb.insert_page(self.image_details_page, None, self.IMAGE_DETAILS)
262 self.vbox.pack_start(self.nb, expand=True, fill=True)
265 self.nb.set_current_page(0)
267 def load_template(self, path):
268 self.template = TemplateMgr()
269 self.template.load(path)
270 self.configuration.load(self.template)
272 for layer in self.configuration.layers:
273 if not os.path.exists(layer+'/conf/layer.conf'):
276 self.switch_page(self.LAYER_CHANGED)
278 self.template.destroy()
281 def save_template(self, path):
282 if path.rfind("/") == -1:
286 filename = path[path.rfind("/") + 1:len(path)]
287 path = path[0:path.rfind("/")]
289 self.template = TemplateMgr()
290 self.template.open(filename, path)
291 self.configuration.save(self.template, filename)
294 self.template.destroy()
297 def switch_page(self, next_step):
298 # Main Workflow (Business Logic)
299 self.nb.set_current_page(self.__step2page__[next_step])
301 if next_step == self.MACHINE_SELECTION: # init step
302 self.image_configuration_page.show_machine()
304 elif next_step == self.LAYER_CHANGED:
305 # after layers is changd by users
306 self.image_configuration_page.show_machine()
307 self.handler.refresh_layers(self.configuration.layers)
309 elif next_step == self.RCPPKGINFO_POPULATING:
310 # MACHINE CHANGED action or SETTINGS CHANGED
311 # show the progress bar
312 self.image_configuration_page.show_info_populating()
313 self.generate_recipes()
315 elif next_step == self.RCPPKGINFO_POPULATED:
316 self.image_configuration_page.show_info_populated()
318 elif next_step == self.BASEIMG_SELECTED:
319 self.image_configuration_page.show_baseimg_selected()
321 elif next_step == self.RECIPE_SELECTION:
324 elif next_step == self.PACKAGE_SELECTION:
327 elif next_step == self.PACKAGE_GENERATING or next_step == self.FAST_IMAGE_GENERATING:
328 # both PACKAGE_GENEATING and FAST_IMAGE_GENERATING share the same page
329 self.build_details_page.show_page(next_step)
330 self.generate_packages()
332 elif next_step == self.PACKAGE_GENERATED:
335 elif next_step == self.IMAGE_GENERATING:
336 # after packages are generated, selected_packages need to
337 # be updated in package_model per selected_image in recipe_model
338 self.build_details_page.show_page(next_step)
339 self.generate_image()
341 elif next_step == self.IMAGE_GENERATED:
342 self.image_details_page.show_page(next_step)
344 elif next_step == self.MY_IMAGE_OPENED:
345 self.image_details_page.show_page(next_step)
347 self.previous_step = self.current_step
348 self.current_step = next_step
350 def set_user_config(self):
351 self.handler.init_cooker()
353 self.handler.set_bblayers(self.configuration.layers)
354 # set local configuration
355 self.handler.set_machine(self.configuration.curr_mach)
356 self.handler.set_package_format(self.configuration.curr_package_format)
357 self.handler.set_distro(self.configuration.curr_distro)
358 self.handler.set_dl_dir(self.configuration.dldir)
359 self.handler.set_sstate_dir(self.configuration.sstatedir)
360 self.handler.set_sstate_mirror(self.configuration.sstatemirror)
361 self.handler.set_pmake(self.configuration.pmake)
362 self.handler.set_bbthreads(self.configuration.bbthread)
363 self.handler.set_rootfs_size(self.configuration.image_rootfs_size)
364 self.handler.set_extra_size(self.configuration.image_extra_size)
365 self.handler.set_incompatible_license(self.configuration.incompat_license)
366 self.handler.set_sdk_machine(self.configuration.curr_sdk_machine)
367 self.handler.set_image_fstypes(self.configuration.image_fstypes)
368 self.handler.set_extra_config(self.configuration.extra_setting)
369 self.handler.set_extra_inherit("packageinfo")
371 def update_recipe_model(self, selected_image, selected_recipes):
372 self.recipe_model.set_selected_image(selected_image)
373 self.recipe_model.set_selected_recipes(selected_recipes)
375 def update_package_model(self, selected_packages):
376 left = self.package_model.set_selected_packages(selected_packages)
377 self.configuration.selected_packages += left
379 def generate_packages(self):
381 _, all_recipes = self.recipe_model.get_selected_recipes()
382 self.set_user_config()
383 self.handler.reset_build()
384 self.handler.generate_packages(all_recipes)
386 def generate_recipes(self):
388 self.set_user_config()
389 self.handler.generate_recipes()
391 def generate_image(self):
393 self.set_user_config()
394 all_packages = self.package_model.get_selected_packages()
395 self.handler.reset_build()
396 self.handler.generate_image(all_packages, self.configuration.toolchain_build)
400 def handler_config_updated_cb(self, handler, which, values):
401 if which == "distro":
402 self.parameters.all_distros = values
403 elif which == "machine":
404 self.parameters.all_machines = values
405 self.image_configuration_page.update_machine_combo()
406 elif which == "machine-sdk":
407 self.parameters.all_sdk_machines = values
409 def handler_package_formats_updated_cb(self, handler, formats):
410 self.parameters.all_package_formats = formats
412 def handler_layers_updated_cb(self, handler, layers):
413 self.parameters.all_layers = layers
415 def handler_command_succeeded_cb(self, handler, initcmd):
416 if initcmd == self.handler.PARSE_CONFIG:
418 params = self.handler.get_parameters()
419 self.configuration = Configuration(params)
420 self.parameters = Parameters(params)
421 self.handler.generate_configuration()
422 elif initcmd == self.handler.GENERATE_CONFIGURATION:
423 self.image_configuration_page.switch_machine_combo()
424 elif initcmd in [self.handler.GENERATE_RECIPES,
425 self.handler.GENERATE_PACKAGES,
426 self.handler.GENERATE_IMAGE]:
427 self.handler.request_package_info_async()
428 elif initcmd == self.handler.POPULATE_PACKAGEINFO:
429 if self.current_step == self.RCPPKGINFO_POPULATING:
430 self.switch_page(self.RCPPKGINFO_POPULATED)
431 self.rcppkglist_populated()
434 self.rcppkglist_populated()
435 if self.current_step == self.FAST_IMAGE_GENERATING:
436 self.switch_page(self.IMAGE_GENERATING)
437 elif self.current_step == self.PACKAGE_GENERATING:
438 self.switch_page(self.PACKAGE_GENERATED)
439 elif self.current_step == self.IMAGE_GENERATING:
440 self.switch_page(self.IMAGE_GENERATED)
442 def handler_command_failed_cb(self, handler, msg):
444 lbl = "<b>Error</b>\n"
445 lbl = lbl + "%s\n\n" % msg
446 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
447 button = dialog.add_button("Close", gtk.RESPONSE_OK)
448 HobButton.style_button(button)
449 response = dialog.run()
451 self.handler.clear_busy()
452 self.configuration.curr_mach = None
453 self.image_configuration_page.switch_machine_combo()
454 self.switch_page(self.MACHINE_SELECTION)
456 def window_sensitive(self, sensitive):
457 self.image_configuration_page.machine_combo.set_sensitive(sensitive)
458 self.image_configuration_page.image_combo.set_sensitive(sensitive)
459 self.image_configuration_page.layer_button.set_sensitive(sensitive)
460 self.image_configuration_page.layer_info_icon.set_sensitive(sensitive)
461 self.image_configuration_page.toolbar.set_sensitive(sensitive)
462 self.image_configuration_page.view_recipes_button.set_sensitive(sensitive)
463 self.image_configuration_page.view_packages_button.set_sensitive(sensitive)
464 self.image_configuration_page.config_build_button.set_sensitive(sensitive)
466 self.recipe_details_page.set_sensitive(sensitive)
467 self.package_details_page.set_sensitive(sensitive)
468 self.build_details_page.set_sensitive(sensitive)
469 self.image_details_page.set_sensitive(sensitive)
472 self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
474 self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
477 def handler_generating_data_cb(self, handler):
478 self.window_sensitive(False)
480 def handler_data_generated_cb(self, handler):
481 self.window_sensitive(True)
483 def rcppkglist_populated(self):
484 selected_image = self.configuration.selected_image
485 selected_recipes = self.configuration.selected_recipes[:]
486 selected_packages = self.configuration.selected_packages[:]
488 self.recipe_model.image_list_append(selected_image,
489 " ".join(selected_recipes),
490 " ".join(selected_packages))
492 self.image_configuration_page.update_image_combo(self.recipe_model, selected_image)
493 self.update_recipe_model(selected_image, selected_recipes)
494 self.update_package_model(selected_packages)
496 def recipelist_changed_cb(self, recipe_model):
497 self.recipe_details_page.refresh_selection()
499 def packagelist_changed_cb(self, package_model):
500 self.package_details_page.refresh_selection()
502 def handler_parsing_started_cb(self, handler, message):
503 if self.current_step != self.RCPPKGINFO_POPULATING:
507 if message["eventname"] == "TreeDataPreparationStarted":
508 fraction = 0.6 + fraction
509 self.image_configuration_page.stop_button.set_sensitive(False)
511 self.image_configuration_page.stop_button.set_sensitive(True)
513 self.image_configuration_page.update_progress_bar(message["title"], fraction)
515 def handler_parsing_cb(self, handler, message):
516 if self.current_step != self.RCPPKGINFO_POPULATING:
519 fraction = message["current"] * 1.0/message["total"]
520 if message["eventname"] == "TreeDataPreparationProgress":
521 fraction = 0.6 + 0.4 * fraction
523 fraction = 0.6 * fraction
524 self.image_configuration_page.update_progress_bar(message["title"], fraction)
526 def handler_parsing_completed_cb(self, handler, message):
527 if self.current_step != self.RCPPKGINFO_POPULATING:
530 if message["eventname"] == "TreeDataPreparationCompleted":
534 self.image_configuration_page.update_progress_bar(message["title"], fraction)
536 def handler_build_started_cb(self, running_build):
537 if self.current_step == self.FAST_IMAGE_GENERATING:
539 elif self.current_step == self.IMAGE_GENERATING:
540 if self.previous_step == self.FAST_IMAGE_GENERATING:
544 elif self.current_step == self.PACKAGE_GENERATING:
546 self.build_details_page.update_progress_bar("Build Started: ", fraction)
547 self.build_details_page.reset_build_status()
548 self.build_details_page.reset_issues()
550 def build_succeeded(self):
551 if self.current_step == self.FAST_IMAGE_GENERATING:
553 elif self.current_step == self.IMAGE_GENERATING:
555 self.parameters.image_names = []
556 linkname = 'hob-image-' + self.configuration.curr_mach
557 for image_type in self.parameters.image_types:
558 linkpath = self.parameters.image_addr + '/' + linkname + '.' + image_type
559 if os.path.exists(linkpath):
560 self.parameters.image_names.append(os.readlink(linkpath))
561 elif self.current_step == self.PACKAGE_GENERATING:
563 self.build_details_page.update_progress_bar("Build Completed: ", fraction)
564 self.stopping = False
566 def build_failed(self):
567 if self.current_step == self.FAST_IMAGE_GENERATING:
569 elif self.current_step == self.IMAGE_GENERATING:
571 elif self.current_step == self.PACKAGE_GENERATING:
573 self.build_details_page.update_progress_bar("Build Failed: ", fraction, False)
574 self.build_details_page.show_back_button()
575 self.build_details_page.hide_stop_button()
576 self.handler.build_failed_async()
577 self.stopping = False
579 def handler_build_succeeded_cb(self, running_build):
580 if not self.stopping:
581 self.build_succeeded()
586 def handler_build_failed_cb(self, running_build):
589 def handler_task_started_cb(self, running_build, message):
590 fraction = message["current"] * 1.0/message["total"]
591 title = "Build packages"
592 if self.current_step == self.FAST_IMAGE_GENERATING:
593 if message["eventname"] == "sceneQueueTaskStarted":
594 fraction = 0.27 * fraction
595 elif message["eventname"] == "runQueueTaskStarted":
596 fraction = 0.27 + 0.63 * fraction
597 elif self.current_step == self.IMAGE_GENERATING:
598 title = "Build image"
599 if self.previous_step == self.FAST_IMAGE_GENERATING:
600 if message["eventname"] == "sceneQueueTaskStarted":
601 fraction = 0.27 + 0.63 + 0.03 * fraction
602 elif message["eventname"] == "runQueueTaskStarted":
603 fraction = 0.27 + 0.63 + 0.03 + 0.07 * fraction
605 if message["eventname"] == "sceneQueueTaskStarted":
606 fraction = 0.2 * fraction
607 elif message["eventname"] == "runQueueTaskStarted":
608 fraction = 0.2 + 0.8 * fraction
609 elif self.current_step == self.PACKAGE_GENERATING:
610 if message["eventname"] == "sceneQueueTaskStarted":
611 fraction = 0.2 * fraction
612 elif message["eventname"] == "runQueueTaskStarted":
613 fraction = 0.2 + 0.8 * fraction
614 self.build_details_page.update_progress_bar(title + ": ", fraction)
615 self.build_details_page.update_build_status(message["current"], message["total"], message["task"])
617 def handler_build_failure_cb(self, running_build):
618 self.build_details_page.show_issues()
620 def destroy_window_cb(self, widget, event):
621 lbl = "<b>Do you really want to exit the Hob image creator?</b>"
622 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
623 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
624 HobAltButton.style_button(button)
625 button = dialog.add_button("Exit Hob", gtk.RESPONSE_YES)
626 HobButton.style_button(button)
627 dialog.set_default_response(gtk.RESPONSE_YES)
628 response = dialog.run()
630 if response == gtk.RESPONSE_YES:
636 def build_packages(self):
637 _, all_recipes = self.recipe_model.get_selected_recipes()
639 lbl = "<b>No selections made</b>\nYou have not made any selections"
640 lbl = lbl + " so there isn't anything to bake at this time."
641 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
642 button = dialog.add_button("Close", gtk.RESPONSE_OK)
643 HobButton.style_button(button)
647 self.switch_page(self.PACKAGE_GENERATING)
649 def build_image(self):
650 selected_packages = self.package_model.get_selected_packages()
651 if not selected_packages:
652 lbl = "<b>No selections made</b>\nYou have not made any selections"
653 lbl = lbl + " so there isn't anything to bake at this time."
654 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
655 button = dialog.add_button("Close", gtk.RESPONSE_OK)
656 HobButton.style_button(button)
660 self.switch_page(self.IMAGE_GENERATING)
663 selected_image = self.recipe_model.get_selected_image()
664 selected_packages = self.package_model.get_selected_packages() or []
666 # If no base image and no selected packages don't build anything
667 if not (selected_packages or selected_image != self.recipe_model.__dummy_image__):
668 lbl = "<b>No selections made</b>\nYou have not made any selections"
669 lbl = lbl + " so there isn't anything to bake at this time."
670 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
671 button = dialog.add_button("Close", gtk.RESPONSE_OK)
672 HobButton.style_button(button)
677 self.switch_page(self.FAST_IMAGE_GENERATING)
679 def show_binb_dialog(self, binb):
680 markup = "<b>Brought in by:</b>\n%s" % binb
681 ptip = PersistentTooltip(markup)
685 def show_layer_selection_dialog(self):
686 dialog = LayerSelectionDialog(title = "Layers",
687 layers = copy.deepcopy(self.configuration.layers),
688 all_layers = self.parameters.all_layers,
690 flags = gtk.DIALOG_MODAL
691 | gtk.DIALOG_DESTROY_WITH_PARENT
692 | gtk.DIALOG_NO_SEPARATOR)
693 button = dialog.add_button("Close", gtk.RESPONSE_YES)
694 HobButton.style_button(button)
695 response = dialog.run()
696 if response == gtk.RESPONSE_YES:
697 self.configuration.layers = dialog.layers
699 if dialog.layers_changed:
700 self.switch_page(self.LAYER_CHANGED)
703 def show_load_template_dialog(self):
704 dialog = gtk.FileChooserDialog("Load Template Files", self,
705 gtk.FILE_CHOOSER_ACTION_OPEN)
706 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
707 HobAltButton.style_button(button)
708 button = dialog.add_button("Open", gtk.RESPONSE_YES)
709 HobButton.style_button(button)
710 filter = gtk.FileFilter()
711 filter.set_name("Hob Files")
712 filter.add_pattern("*.hob")
713 dialog.add_filter(filter)
715 response = dialog.run()
716 if response == gtk.RESPONSE_YES:
717 path = dialog.get_filename()
718 self.load_template(path)
721 def show_save_template_dialog(self):
722 dialog = gtk.FileChooserDialog("Save Template Files", self,
723 gtk.FILE_CHOOSER_ACTION_SAVE)
724 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
725 HobAltButton.style_button(button)
726 button = dialog.add_button("Save", gtk.RESPONSE_YES)
727 HobButton.style_button(button)
728 dialog.set_current_name("hob")
729 response = dialog.run()
730 if response == gtk.RESPONSE_YES:
731 path = dialog.get_filename()
732 self.save_template(path)
735 def show_load_my_images_dialog(self):
736 dialog = ImageSelectionDialog(self.parameters.image_addr, self.parameters.image_types,
737 "Open My Images", self,
738 gtk.FILE_CHOOSER_ACTION_SAVE)
739 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
740 HobAltButton.style_button(button)
741 button = dialog.add_button("Open", gtk.RESPONSE_YES)
742 HobButton.style_button(button)
743 response = dialog.run()
744 if response == gtk.RESPONSE_YES:
745 if not dialog.image_names:
746 lbl = "<b>No selections made</b>\nYou have not made any selections"
747 crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
748 button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
749 HobButton.style_button(button)
751 crumbs_dialog.destroy()
755 self.parameters.image_addr = dialog.image_folder
756 self.parameters.image_names = dialog.image_names[:]
757 self.switch_page(self.MY_IMAGE_OPENED)
761 def show_adv_settings_dialog(self):
762 dialog = AdvancedSettingDialog(title = "Settings",
763 configuration = copy.deepcopy(self.configuration),
764 all_image_types = self.parameters.image_types,
765 all_package_formats = self.parameters.all_package_formats,
766 all_distros = self.parameters.all_distros,
767 all_sdk_machines = self.parameters.all_sdk_machines,
768 max_threads = self.parameters.max_threads,
770 flags = gtk.DIALOG_MODAL
771 | gtk.DIALOG_DESTROY_WITH_PARENT
772 | gtk.DIALOG_NO_SEPARATOR)
773 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
774 HobAltButton.style_button(button)
775 button = dialog.add_button("Save", gtk.RESPONSE_YES)
776 HobButton.style_button(button)
777 response = dialog.run()
778 if response == gtk.RESPONSE_YES:
779 self.configuration = dialog.configuration
781 if dialog.settings_changed:
782 if self.configuration.curr_mach == "":
783 self.switch_page(self.MACHINE_SELECTION)
785 self.switch_page(self.RCPPKGINFO_POPULATING)
788 def deploy_image(self, image_name):
790 lbl = "<b>Please select an image to deploy.</b>"
791 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
792 button = dialog.add_button("Close", gtk.RESPONSE_OK)
793 HobButton.style_button(button)
798 image_path = os.path.join(self.parameters.image_addr, image_name)
799 dialog = DeployImageDialog(title = "Usb Image Maker",
800 image_path = image_path,
802 flags = gtk.DIALOG_MODAL
803 | gtk.DIALOG_DESTROY_WITH_PARENT
804 | gtk.DIALOG_NO_SEPARATOR)
805 button = dialog.add_button("Close", gtk.RESPONSE_NO)
806 HobAltButton.style_button(button)
807 button = dialog.add_button("Make usb image", gtk.RESPONSE_YES)
808 HobButton.style_button(button)
809 response = dialog.run()
812 def runqemu_image(self, image_name):
814 lbl = "<b>Please select an image to launch in QEMU.</b>"
815 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
816 button = dialog.add_button("Close", gtk.RESPONSE_OK)
817 HobButton.style_button(button)
822 dialog = gtk.FileChooserDialog("Load Kernel Files", self,
823 gtk.FILE_CHOOSER_ACTION_SAVE)
824 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
825 HobAltButton.style_button(button)
826 button = dialog.add_button("Open", gtk.RESPONSE_YES)
827 HobButton.style_button(button)
828 filter = gtk.FileFilter()
829 filter.set_name("Kernel Files")
830 filter.add_pattern("*.bin")
831 dialog.add_filter(filter)
833 dialog.set_current_folder(self.parameters.image_addr)
835 response = dialog.run()
836 if response == gtk.RESPONSE_YES:
837 kernel_path = dialog.get_filename()
838 image_path = os.path.join(self.parameters.image_addr, image_name)
841 if response == gtk.RESPONSE_YES:
842 source_env_path = os.path.join(self.parameters.core_base, "oe-init-build-env")
843 tmp_path = self.parameters.tmpdir
844 if os.path.exists(image_path) and os.path.exists(kernel_path) \
845 and os.path.exists(source_env_path) and os.path.exists(tmp_path):
846 cmdline = "/usr/bin/xterm -e "
847 cmdline += "\" export OE_TMPDIR=" + tmp_path + "; "
848 cmdline += "source " + source_env_path + " " + os.getcwd() + "; "
849 cmdline += "runqemu " + kernel_path + " " + image_path + "; bash\""
850 subprocess.Popen(shlex.split(cmdline))
852 lbl = "<b>Path error</b>\nOne of your paths is wrong,"
853 lbl = lbl + " please make sure the following paths exist:\n"
854 lbl = lbl + "image path:" + image_path + "\n"
855 lbl = lbl + "kernel path:" + kernel_path + "\n"
856 lbl = lbl + "source environment path:" + source_env_path + "\n"
857 lbl = lbl + "tmp path: " + tmp_path + "."
858 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
859 button = dialog.add_button("Close", gtk.RESPONSE_OK)
860 HobButton.style_button(button)
864 def show_packages(self, ask=True):
865 _, selected_recipes = self.recipe_model.get_selected_recipes()
866 if selected_recipes and ask:
867 lbl = "<b>Package list may be incomplete!</b>\nDo you want to build selected recipes"
868 lbl = lbl + " to get a full list or just view the existing packages?"
869 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
870 button = dialog.add_button("View packages", gtk.RESPONSE_NO)
871 HobAltButton.style_button(button)
872 button = dialog.add_button("Build packages", gtk.RESPONSE_YES)
873 HobButton.style_button(button)
874 dialog.set_default_response(gtk.RESPONSE_YES)
875 response = dialog.run()
877 if response == gtk.RESPONSE_YES:
878 self.switch_page(self.PACKAGE_GENERATING)
880 self.switch_page(self.PACKAGE_SELECTION)
882 self.switch_page(self.PACKAGE_SELECTION)
884 def show_recipes(self):
885 self.switch_page(self.RECIPE_SELECTION)
887 def initiate_new_build(self):
888 self.configuration.curr_mach = ""
889 self.image_configuration_page.switch_machine_combo()
890 self.switch_page(self.MACHINE_SELECTION)
892 def show_configuration(self):
893 self.switch_page(self.BASEIMG_SELECTED)
895 def stop_parse(self):
896 self.handler.cancel_parse()
898 def stop_build(self):
900 lbl = "<b>Force Stop build?</b>\nYou've already selected Stop once,"
901 lbl = lbl + " would you like to 'Force Stop' the build?\n\n"
902 lbl = lbl + "This will stop the build as quickly as possible but may"
903 lbl = lbl + " well leave your build directory in an unusable state"
904 lbl = lbl + " that requires manual steps to fix.\n"
905 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
906 button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
907 HobAltButton.style_button(button)
908 button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
909 HobButton.style_button(button)
911 lbl = "<b>Stop build?</b>\n\nAre you sure you want to stop this"
912 lbl = lbl + " build?\n\n'Force Stop' will stop the build as quickly as"
913 lbl = lbl + " possible but may well leave your build directory in an"
914 lbl = lbl + " unusable state that requires manual steps to fix.\n\n"
915 lbl = lbl + "'Stop' will stop the build as soon as all in"
916 lbl = lbl + " progress build tasks are finished. However if a"
917 lbl = lbl + " lengthy compilation phase is in progress this may take"
918 lbl = lbl + " some time."
919 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
920 button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
921 HobAltButton.style_button(button)
922 button = dialog.add_button("Stop", gtk.RESPONSE_OK)
923 HobAltButton.style_button(button)
924 button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
925 HobButton.style_button(button)
926 response = dialog.run()
928 if response != gtk.RESPONSE_CANCEL:
930 if response == gtk.RESPONSE_OK:
931 self.handler.cancel_build()
932 elif response == gtk.RESPONSE_YES:
933 self.handler.cancel_build(True)