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 = []
72 self.all_proxy = params["all_proxy"]
73 self.http_proxy = params["http_proxy"]
74 self.ftp_proxy = params["ftp_proxy"]
75 self.https_proxy = params["https_proxy"]
76 self.git_proxy_host = params["git_proxy_host"]
77 self.git_proxy_port = params["git_proxy_port"]
78 self.cvs_proxy_host = params["cvs_proxy_host"]
79 self.cvs_proxy_port = params["cvs_proxy_port"]
81 def load(self, template):
82 self.curr_mach = template.getVar("MACHINE")
83 self.curr_package_format = " ".join(template.getVar("PACKAGE_CLASSES").split("package_")).strip()
84 self.curr_distro = template.getVar("DISTRO")
85 self.dldir = template.getVar("DL_DIR")
86 self.sstatedir = template.getVar("SSTATE_DIR")
87 self.sstatemirror = template.getVar("SSTATE_MIRROR")
88 self.pmake = int(template.getVar("PARALLEL_MAKE").split()[1])
89 self.bbthread = int(template.getVar("BB_NUMBER_THREADS"))
90 self.image_rootfs_size = int(template.getVar("IMAGE_ROOTFS_SIZE"))
91 self.image_extra_size = int(template.getVar("IMAGE_EXTRA_SPACE"))
92 # image_overhead_factor is read-only.
93 self.incompat_license = template.getVar("INCOMPATIBLE_LICENSE")
94 self.curr_sdk_machine = template.getVar("SDKMACHINE")
95 self.conf_version = template.getVar("CONF_VERSION")
96 self.lconf_version = template.getVar("LCONF_VERSION")
97 self.extra_setting = eval(template.getVar("EXTRA_SETTING"))
98 self.toolchain_build = eval(template.getVar("TOOLCHAIN_BUILD"))
99 self.image_fstypes = template.getVar("IMAGE_FSTYPES").split()
101 self.layers = template.getVar("BBLAYERS").split()
102 # image/recipes/packages
103 self.selected_image = template.getVar("__SELECTED_IMAGE__")
104 self.selected_recipes = template.getVar("DEPENDS").split()
105 self.selected_packages = template.getVar("IMAGE_INSTALL").split()
107 self.all_proxy = template.getVar("all_proxy")
108 self.http_proxy = template.getVar("http_proxy")
109 self.ftp_proxy = template.getVar("ftp_proxy")
110 self.https_proxy = template.getVar("https_proxy")
111 self.git_proxy_host = template.getVar("GIT_PROXY_HOST")
112 self.git_proxy_port = template.getVar("GIT_PROXY_PORT")
113 self.cvs_proxy_host = template.getVar("CVS_PROXY_HOST")
114 self.cvs_proxy_port = template.getVar("CVS_PROXY_PORT")
116 def save(self, template, filename):
118 template.setVar("BBLAYERS", " ".join(self.layers))
120 template.setVar("MACHINE", self.curr_mach)
121 template.setVar("DISTRO", self.curr_distro)
122 template.setVar("DL_DIR", self.dldir)
123 template.setVar("SSTATE_DIR", self.sstatedir)
124 template.setVar("SSTATE_MIRROR", self.sstatemirror)
125 template.setVar("PARALLEL_MAKE", "-j %s" % self.pmake)
126 template.setVar("BB_NUMBER_THREADS", self.bbthread)
127 template.setVar("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()]))
128 template.setVar("IMAGE_ROOTFS_SIZE", self.image_rootfs_size)
129 template.setVar("IMAGE_EXTRA_SPACE", self.image_extra_size)
130 template.setVar("INCOMPATIBLE_LICENSE", self.incompat_license)
131 template.setVar("SDKMACHINE", self.curr_sdk_machine)
132 template.setVar("CONF_VERSION", self.conf_version)
133 template.setVar("LCONF_VERSION", self.lconf_version)
134 template.setVar("EXTRA_SETTING", self.extra_setting)
135 template.setVar("TOOLCHAIN_BUILD", self.toolchain_build)
136 template.setVar("IMAGE_FSTYPES", " ".join(self.image_fstypes).lstrip(" "))
137 # image/recipes/packages
138 self.selected_image = filename
139 template.setVar("__SELECTED_IMAGE__", self.selected_image)
140 template.setVar("DEPENDS", self.selected_recipes)
141 template.setVar("IMAGE_INSTALL", self.selected_packages)
143 template.setVar("all_proxy", self.all_proxy)
144 template.setVar("http_proxy", self.http_proxy)
145 template.setVar("ftp_proxy", self.ftp_proxy)
146 template.setVar("https_proxy", self.https_proxy)
147 template.setVar("GIT_PROXY_HOST", self.git_proxy_host)
148 template.setVar("GIT_PROXY_PORT", self.git_proxy_port)
149 template.setVar("CVS_PROXY_HOST", self.cvs_proxy_host)
150 template.setVar("CVS_PROXY_PORT", self.cvs_proxy_port)
153 '''Represents other variables like available machines, etc.'''
155 def __init__(self, params):
157 self.all_machines = []
158 self.all_package_formats = []
159 self.all_distros = []
160 self.all_sdk_machines = []
161 self.max_threads = params["max_threads"]
163 self.core_base = params["core_base"]
164 self.image_names = []
165 self.image_addr = params["image_addr"]
166 self.image_types = params["image_types"].split()
167 self.runnable_image_types = params["runnable_image_types"].split()
168 self.runnable_machine_patterns = params["runnable_machine_patterns"].split()
169 self.deployable_image_types = params["deployable_image_types"].split()
170 self.tmpdir = params["tmpdir"]
171 self.distro_version = params["distro_version"]
172 self.target_os = params["target_os"]
173 self.target_arch = params["target_arch"]
174 self.tune_pkgarch = params["tune_pkgarch"]
175 self.bb_version = params["bb_version"]
176 self.tune_arch = params["tune_arch"]
177 self.enable_proxy = False
179 class Builder(gtk.Window):
183 RCPPKGINFO_POPULATING,
184 RCPPKGINFO_POPULATED,
190 FAST_IMAGE_GENERATING,
195 END_NOOP) = range(15)
197 (IMAGE_CONFIGURATION,
205 MACHINE_SELECTION : IMAGE_CONFIGURATION,
206 LAYER_CHANGED : IMAGE_CONFIGURATION,
207 RCPPKGINFO_POPULATING : IMAGE_CONFIGURATION,
208 RCPPKGINFO_POPULATED : IMAGE_CONFIGURATION,
209 BASEIMG_SELECTED : IMAGE_CONFIGURATION,
210 RECIPE_SELECTION : RECIPE_DETAILS,
211 PACKAGE_GENERATING : BUILD_DETAILS,
212 PACKAGE_GENERATED : PACKAGE_DETAILS,
213 PACKAGE_SELECTION : PACKAGE_DETAILS,
214 FAST_IMAGE_GENERATING : BUILD_DETAILS,
215 IMAGE_GENERATING : BUILD_DETAILS,
216 IMAGE_GENERATED : IMAGE_DETAILS,
217 MY_IMAGE_OPENED : IMAGE_DETAILS,
221 def __init__(self, hobHandler, recipe_model, package_model):
222 super(Builder, self).__init__()
225 self.handler = hobHandler
230 self.current_step = None
231 self.previous_step = None
233 self.stopping = False
235 # recipe model and package model
236 self.recipe_model = recipe_model
237 self.package_model = package_model
239 # create visual elements
240 self.create_visual_elements()
242 # connect the signals to functions
243 self.connect("delete-event", self.destroy_window_cb)
244 self.recipe_model.connect ("recipe-selection-changed", self.recipelist_changed_cb)
245 self.package_model.connect("package-selection-changed", self.packagelist_changed_cb)
246 self.handler.connect("config-updated", self.handler_config_updated_cb)
247 self.handler.connect("package-formats-updated", self.handler_package_formats_updated_cb)
248 self.handler.connect("layers-updated", self.handler_layers_updated_cb)
249 self.handler.connect("parsing-started", self.handler_parsing_started_cb)
250 self.handler.connect("parsing", self.handler_parsing_cb)
251 self.handler.connect("parsing-completed", self.handler_parsing_completed_cb)
252 self.handler.build.connect("build-started", self.handler_build_started_cb)
253 self.handler.build.connect("build-succeeded", self.handler_build_succeeded_cb)
254 self.handler.build.connect("build-failed", self.handler_build_failed_cb)
255 self.handler.build.connect("task-started", self.handler_task_started_cb)
256 self.handler.build.connect("log-error", self.handler_build_failure_cb)
257 self.handler.connect("generating-data", self.handler_generating_data_cb)
258 self.handler.connect("data-generated", self.handler_data_generated_cb)
259 self.handler.connect("command-succeeded", self.handler_command_succeeded_cb)
260 self.handler.connect("command-failed", self.handler_command_failed_cb)
262 self.handler.init_cooker()
263 self.handler.set_extra_inherit("image_types")
264 self.handler.parse_config()
266 self.switch_page(self.MACHINE_SELECTION)
268 def create_visual_elements(self):
269 self.set_title("Hob")
270 self.set_icon_name("applications-development")
271 self.set_resizable(True)
272 window_width = self.get_screen().get_width()
273 window_height = self.get_screen().get_height()
274 if window_width >= hwc.MAIN_WIN_WIDTH:
275 window_width = hwc.MAIN_WIN_WIDTH
276 window_height = hwc.MAIN_WIN_HEIGHT
277 self.set_size_request(window_width, window_height)
279 self.vbox = gtk.VBox(False, 0)
280 self.vbox.set_border_width(0)
284 self.image_configuration_page = ImageConfigurationPage(self)
285 self.recipe_details_page = RecipeSelectionPage(self)
286 self.build_details_page = BuildDetailsPage(self)
287 self.package_details_page = PackageSelectionPage(self)
288 self.image_details_page = ImageDetailsPage(self)
290 self.nb = gtk.Notebook()
291 self.nb.set_show_tabs(False)
292 self.nb.insert_page(self.image_configuration_page, None, self.IMAGE_CONFIGURATION)
293 self.nb.insert_page(self.recipe_details_page, None, self.RECIPE_DETAILS)
294 self.nb.insert_page(self.build_details_page, None, self.BUILD_DETAILS)
295 self.nb.insert_page(self.package_details_page, None, self.PACKAGE_DETAILS)
296 self.nb.insert_page(self.image_details_page, None, self.IMAGE_DETAILS)
297 self.vbox.pack_start(self.nb, expand=True, fill=True)
300 self.nb.set_current_page(0)
302 def load_template(self, path):
303 self.template = TemplateMgr()
304 self.template.load(path)
305 self.configuration.load(self.template)
307 for layer in self.configuration.layers:
308 if not os.path.exists(layer+'/conf/layer.conf'):
311 self.switch_page(self.LAYER_CHANGED)
313 self.template.destroy()
316 def save_template(self, path):
317 if path.rfind("/") == -1:
321 filename = path[path.rfind("/") + 1:len(path)]
322 path = path[0:path.rfind("/")]
324 self.template = TemplateMgr()
325 self.template.open(filename, path)
326 self.configuration.save(self.template, filename)
329 self.template.destroy()
332 def switch_page(self, next_step):
333 # Main Workflow (Business Logic)
334 self.nb.set_current_page(self.__step2page__[next_step])
336 if next_step == self.MACHINE_SELECTION: # init step
337 self.image_configuration_page.show_machine()
339 elif next_step == self.LAYER_CHANGED:
340 # after layers is changd by users
341 self.image_configuration_page.show_machine()
342 self.handler.refresh_layers(self.configuration.layers)
344 elif next_step == self.RCPPKGINFO_POPULATING:
345 # MACHINE CHANGED action or SETTINGS CHANGED
346 # show the progress bar
347 self.image_configuration_page.show_info_populating()
348 self.generate_recipes()
350 elif next_step == self.RCPPKGINFO_POPULATED:
351 self.image_configuration_page.show_info_populated()
353 elif next_step == self.BASEIMG_SELECTED:
354 self.image_configuration_page.show_baseimg_selected()
356 elif next_step == self.RECIPE_SELECTION:
359 elif next_step == self.PACKAGE_SELECTION:
362 elif next_step == self.PACKAGE_GENERATING or next_step == self.FAST_IMAGE_GENERATING:
363 # both PACKAGE_GENEATING and FAST_IMAGE_GENERATING share the same page
364 self.build_details_page.show_page(next_step)
365 self.generate_packages()
367 elif next_step == self.PACKAGE_GENERATED:
370 elif next_step == self.IMAGE_GENERATING:
371 # after packages are generated, selected_packages need to
372 # be updated in package_model per selected_image in recipe_model
373 self.build_details_page.show_page(next_step)
374 self.generate_image()
376 elif next_step == self.IMAGE_GENERATED:
377 self.image_details_page.show_page(next_step)
379 elif next_step == self.MY_IMAGE_OPENED:
380 self.image_details_page.show_page(next_step)
382 self.previous_step = self.current_step
383 self.current_step = next_step
385 def set_user_config(self):
386 self.handler.init_cooker()
388 self.handler.set_bblayers(self.configuration.layers)
389 # set local configuration
390 self.handler.set_machine(self.configuration.curr_mach)
391 self.handler.set_package_format(self.configuration.curr_package_format)
392 self.handler.set_distro(self.configuration.curr_distro)
393 self.handler.set_dl_dir(self.configuration.dldir)
394 self.handler.set_sstate_dir(self.configuration.sstatedir)
395 self.handler.set_sstate_mirror(self.configuration.sstatemirror)
396 self.handler.set_pmake(self.configuration.pmake)
397 self.handler.set_bbthreads(self.configuration.bbthread)
398 self.handler.set_rootfs_size(self.configuration.image_rootfs_size)
399 self.handler.set_extra_size(self.configuration.image_extra_size)
400 self.handler.set_incompatible_license(self.configuration.incompat_license)
401 self.handler.set_sdk_machine(self.configuration.curr_sdk_machine)
402 self.handler.set_image_fstypes(self.configuration.image_fstypes)
403 self.handler.set_extra_config(self.configuration.extra_setting)
404 self.handler.set_extra_inherit("packageinfo")
406 if self.parameters.enable_proxy:
407 self.handler.set_http_proxy(self.configuration.http_proxy)
408 self.handler.set_https_proxy(self.configuration.https_proxy)
409 self.handler.set_ftp_proxy(self.configuration.ftp_proxy)
410 self.handler.set_all_proxy(self.configuration.all_proxy)
411 self.handler.set_git_proxy(self.configuration.git_proxy_host, self.configuration.git_proxy_port)
412 self.handler.set_cvs_proxy(self.configuration.cvs_proxy_host, self.configuration.cvs_proxy_port)
414 def update_recipe_model(self, selected_image, selected_recipes):
415 self.recipe_model.set_selected_image(selected_image)
416 self.recipe_model.set_selected_recipes(selected_recipes)
418 def update_package_model(self, selected_packages):
419 left = self.package_model.set_selected_packages(selected_packages)
420 self.configuration.selected_packages += left
422 def generate_packages(self):
424 _, all_recipes = self.recipe_model.get_selected_recipes()
425 self.set_user_config()
426 self.handler.reset_build()
427 self.handler.generate_packages(all_recipes)
429 def generate_recipes(self):
431 self.set_user_config()
432 self.handler.generate_recipes()
434 def generate_image(self):
436 self.set_user_config()
437 all_packages = self.package_model.get_selected_packages()
438 self.handler.reset_build()
439 self.handler.generate_image(all_packages, self.configuration.toolchain_build)
443 def handler_config_updated_cb(self, handler, which, values):
444 if which == "distro":
445 self.parameters.all_distros = values
446 elif which == "machine":
447 self.parameters.all_machines = values
448 self.image_configuration_page.update_machine_combo()
449 elif which == "machine-sdk":
450 self.parameters.all_sdk_machines = values
452 def handler_package_formats_updated_cb(self, handler, formats):
453 self.parameters.all_package_formats = formats
455 def handler_layers_updated_cb(self, handler, layers):
456 self.parameters.all_layers = layers
458 def handler_command_succeeded_cb(self, handler, initcmd):
459 if initcmd == self.handler.PARSE_CONFIG:
461 params = self.handler.get_parameters()
462 self.configuration = Configuration(params)
463 self.parameters = Parameters(params)
464 self.handler.generate_configuration()
465 elif initcmd == self.handler.GENERATE_CONFIGURATION:
466 self.image_configuration_page.switch_machine_combo()
467 elif initcmd in [self.handler.GENERATE_RECIPES,
468 self.handler.GENERATE_PACKAGES,
469 self.handler.GENERATE_IMAGE]:
470 self.handler.request_package_info_async()
471 elif initcmd == self.handler.POPULATE_PACKAGEINFO:
472 if self.current_step == self.RCPPKGINFO_POPULATING:
473 self.switch_page(self.RCPPKGINFO_POPULATED)
474 self.rcppkglist_populated()
477 self.rcppkglist_populated()
478 if self.current_step == self.FAST_IMAGE_GENERATING:
479 self.switch_page(self.IMAGE_GENERATING)
480 elif self.current_step == self.PACKAGE_GENERATING:
481 self.switch_page(self.PACKAGE_GENERATED)
482 elif self.current_step == self.IMAGE_GENERATING:
483 self.switch_page(self.IMAGE_GENERATED)
485 def handler_command_failed_cb(self, handler, msg):
487 lbl = "<b>Error</b>\n"
488 lbl = lbl + "%s\n\n" % msg
489 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
490 button = dialog.add_button("Close", gtk.RESPONSE_OK)
491 HobButton.style_button(button)
492 response = dialog.run()
494 self.handler.clear_busy()
495 self.configuration.curr_mach = None
496 self.image_configuration_page.switch_machine_combo()
497 self.switch_page(self.MACHINE_SELECTION)
499 def window_sensitive(self, sensitive):
500 self.image_configuration_page.machine_combo.set_sensitive(sensitive)
501 self.image_configuration_page.image_combo.set_sensitive(sensitive)
502 self.image_configuration_page.layer_button.set_sensitive(sensitive)
503 self.image_configuration_page.layer_info_icon.set_sensitive(sensitive)
504 self.image_configuration_page.toolbar.set_sensitive(sensitive)
505 self.image_configuration_page.view_recipes_button.set_sensitive(sensitive)
506 self.image_configuration_page.view_packages_button.set_sensitive(sensitive)
507 self.image_configuration_page.config_build_button.set_sensitive(sensitive)
509 self.recipe_details_page.set_sensitive(sensitive)
510 self.package_details_page.set_sensitive(sensitive)
511 self.build_details_page.set_sensitive(sensitive)
512 self.image_details_page.set_sensitive(sensitive)
515 self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
517 self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
520 def handler_generating_data_cb(self, handler):
521 self.window_sensitive(False)
523 def handler_data_generated_cb(self, handler):
524 self.window_sensitive(True)
526 def rcppkglist_populated(self):
527 selected_image = self.configuration.selected_image
528 selected_recipes = self.configuration.selected_recipes[:]
529 selected_packages = self.configuration.selected_packages[:]
531 self.recipe_model.image_list_append(selected_image,
532 " ".join(selected_recipes),
533 " ".join(selected_packages))
535 self.image_configuration_page.update_image_combo(self.recipe_model, selected_image)
536 self.update_recipe_model(selected_image, selected_recipes)
537 self.update_package_model(selected_packages)
539 def recipelist_changed_cb(self, recipe_model):
540 self.recipe_details_page.refresh_selection()
542 def packagelist_changed_cb(self, package_model):
543 self.package_details_page.refresh_selection()
545 def handler_parsing_started_cb(self, handler, message):
546 if self.current_step != self.RCPPKGINFO_POPULATING:
550 if message["eventname"] == "TreeDataPreparationStarted":
551 fraction = 0.6 + fraction
552 self.image_configuration_page.stop_button.set_sensitive(False)
554 self.image_configuration_page.stop_button.set_sensitive(True)
556 self.image_configuration_page.update_progress_bar(message["title"], fraction)
558 def handler_parsing_cb(self, handler, message):
559 if self.current_step != self.RCPPKGINFO_POPULATING:
562 fraction = message["current"] * 1.0/message["total"]
563 if message["eventname"] == "TreeDataPreparationProgress":
564 fraction = 0.6 + 0.4 * fraction
566 fraction = 0.6 * fraction
567 self.image_configuration_page.update_progress_bar(message["title"], fraction)
569 def handler_parsing_completed_cb(self, handler, message):
570 if self.current_step != self.RCPPKGINFO_POPULATING:
573 if message["eventname"] == "TreeDataPreparationCompleted":
577 self.image_configuration_page.update_progress_bar(message["title"], fraction)
579 def handler_build_started_cb(self, running_build):
580 if self.current_step == self.FAST_IMAGE_GENERATING:
582 elif self.current_step == self.IMAGE_GENERATING:
583 if self.previous_step == self.FAST_IMAGE_GENERATING:
587 elif self.current_step == self.PACKAGE_GENERATING:
589 self.build_details_page.update_progress_bar("Build Started: ", fraction)
590 self.build_details_page.reset_build_status()
591 self.build_details_page.reset_issues()
592 self.build_details_page.show_configurations(self.configuration, self.parameters)
594 def build_succeeded(self):
595 if self.current_step == self.FAST_IMAGE_GENERATING:
597 elif self.current_step == self.IMAGE_GENERATING:
599 self.parameters.image_names = []
600 linkname = 'hob-image-' + self.configuration.curr_mach
601 for image_type in self.parameters.image_types:
602 linkpath = self.parameters.image_addr + '/' + linkname + '.' + image_type
603 if os.path.exists(linkpath):
604 self.parameters.image_names.append(os.readlink(linkpath))
605 elif self.current_step == self.PACKAGE_GENERATING:
607 self.build_details_page.update_progress_bar("Build Completed: ", fraction)
608 self.stopping = False
610 def build_failed(self):
611 if self.current_step == self.FAST_IMAGE_GENERATING:
613 elif self.current_step == self.IMAGE_GENERATING:
615 elif self.current_step == self.PACKAGE_GENERATING:
617 self.build_details_page.update_progress_bar("Build Failed: ", fraction, False)
618 self.build_details_page.show_back_button()
619 self.build_details_page.hide_stop_button()
620 self.handler.build_failed_async()
621 self.stopping = False
623 def handler_build_succeeded_cb(self, running_build):
624 if not self.stopping:
625 self.build_succeeded()
630 def handler_build_failed_cb(self, running_build):
633 def handler_task_started_cb(self, running_build, message):
634 fraction = message["current"] * 1.0/message["total"]
635 title = "Build packages"
636 if self.current_step == self.FAST_IMAGE_GENERATING:
637 if message["eventname"] == "sceneQueueTaskStarted":
638 fraction = 0.27 * fraction
639 elif message["eventname"] == "runQueueTaskStarted":
640 fraction = 0.27 + 0.63 * fraction
641 elif self.current_step == self.IMAGE_GENERATING:
642 title = "Build image"
643 if self.previous_step == self.FAST_IMAGE_GENERATING:
644 if message["eventname"] == "sceneQueueTaskStarted":
645 fraction = 0.27 + 0.63 + 0.03 * fraction
646 elif message["eventname"] == "runQueueTaskStarted":
647 fraction = 0.27 + 0.63 + 0.03 + 0.07 * fraction
649 if message["eventname"] == "sceneQueueTaskStarted":
650 fraction = 0.2 * fraction
651 elif message["eventname"] == "runQueueTaskStarted":
652 fraction = 0.2 + 0.8 * fraction
653 elif self.current_step == self.PACKAGE_GENERATING:
654 if message["eventname"] == "sceneQueueTaskStarted":
655 fraction = 0.2 * fraction
656 elif message["eventname"] == "runQueueTaskStarted":
657 fraction = 0.2 + 0.8 * fraction
658 self.build_details_page.update_progress_bar(title + ": ", fraction)
659 self.build_details_page.update_build_status(message["current"], message["total"], message["task"])
661 def handler_build_failure_cb(self, running_build):
662 self.build_details_page.show_issues()
664 def destroy_window_cb(self, widget, event):
665 lbl = "<b>Do you really want to exit the Hob image creator?</b>"
666 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
667 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
668 HobAltButton.style_button(button)
669 button = dialog.add_button("Exit Hob", gtk.RESPONSE_YES)
670 HobButton.style_button(button)
671 dialog.set_default_response(gtk.RESPONSE_YES)
672 response = dialog.run()
674 if response == gtk.RESPONSE_YES:
680 def build_packages(self):
681 _, all_recipes = self.recipe_model.get_selected_recipes()
683 lbl = "<b>No selections made</b>\nYou have not made any selections"
684 lbl = lbl + " so there isn't anything to bake at this time."
685 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
686 button = dialog.add_button("Close", gtk.RESPONSE_OK)
687 HobButton.style_button(button)
691 self.switch_page(self.PACKAGE_GENERATING)
693 def build_image(self):
694 selected_packages = self.package_model.get_selected_packages()
695 if not selected_packages:
696 lbl = "<b>No selections made</b>\nYou have not made any selections"
697 lbl = lbl + " so there isn't anything to bake at this time."
698 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
699 button = dialog.add_button("Close", gtk.RESPONSE_OK)
700 HobButton.style_button(button)
704 self.switch_page(self.IMAGE_GENERATING)
707 selected_image = self.recipe_model.get_selected_image()
708 selected_packages = self.package_model.get_selected_packages() or []
710 # If no base image and no selected packages don't build anything
711 if not (selected_packages or selected_image != self.recipe_model.__dummy_image__):
712 lbl = "<b>No selections made</b>\nYou have not made any selections"
713 lbl = lbl + " so there isn't anything to bake at this time."
714 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
715 button = dialog.add_button("Close", gtk.RESPONSE_OK)
716 HobButton.style_button(button)
721 self.switch_page(self.FAST_IMAGE_GENERATING)
723 def show_binb_dialog(self, binb):
724 markup = "<b>Brought in by:</b>\n%s" % binb
725 ptip = PersistentTooltip(markup)
729 def show_layer_selection_dialog(self):
730 dialog = LayerSelectionDialog(title = "Layers",
731 layers = copy.deepcopy(self.configuration.layers),
732 all_layers = self.parameters.all_layers,
734 flags = gtk.DIALOG_MODAL
735 | gtk.DIALOG_DESTROY_WITH_PARENT
736 | gtk.DIALOG_NO_SEPARATOR)
737 button = dialog.add_button("Close", gtk.RESPONSE_YES)
738 HobButton.style_button(button)
739 response = dialog.run()
740 if response == gtk.RESPONSE_YES:
741 self.configuration.layers = dialog.layers
743 if dialog.layers_changed:
744 self.switch_page(self.LAYER_CHANGED)
747 def show_load_template_dialog(self):
748 dialog = gtk.FileChooserDialog("Load Template Files", self,
749 gtk.FILE_CHOOSER_ACTION_OPEN)
750 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
751 HobAltButton.style_button(button)
752 button = dialog.add_button("Open", gtk.RESPONSE_YES)
753 HobButton.style_button(button)
754 filter = gtk.FileFilter()
755 filter.set_name("Hob Files")
756 filter.add_pattern("*.hob")
757 dialog.add_filter(filter)
759 response = dialog.run()
761 if response == gtk.RESPONSE_YES:
762 path = dialog.get_filename()
764 return response == gtk.RESPONSE_YES, path
766 def show_save_template_dialog(self):
767 dialog = gtk.FileChooserDialog("Save Template Files", self,
768 gtk.FILE_CHOOSER_ACTION_SAVE)
769 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
770 HobAltButton.style_button(button)
771 button = dialog.add_button("Save", gtk.RESPONSE_YES)
772 HobButton.style_button(button)
773 dialog.set_current_name("hob")
774 response = dialog.run()
775 if response == gtk.RESPONSE_YES:
776 path = dialog.get_filename()
777 self.save_template(path)
780 def show_load_my_images_dialog(self):
781 dialog = ImageSelectionDialog(self.parameters.image_addr, self.parameters.image_types,
782 "Open My Images", self,
783 gtk.FILE_CHOOSER_ACTION_SAVE)
784 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
785 HobAltButton.style_button(button)
786 button = dialog.add_button("Open", gtk.RESPONSE_YES)
787 HobButton.style_button(button)
788 response = dialog.run()
789 if response == gtk.RESPONSE_YES:
790 if not dialog.image_names:
791 lbl = "<b>No selections made</b>\nYou have not made any selections"
792 crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
793 button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
794 HobButton.style_button(button)
796 crumbs_dialog.destroy()
800 self.parameters.image_addr = dialog.image_folder
801 self.parameters.image_names = dialog.image_names[:]
802 self.switch_page(self.MY_IMAGE_OPENED)
806 def show_adv_settings_dialog(self):
807 dialog = AdvancedSettingDialog(title = "Settings",
808 configuration = copy.deepcopy(self.configuration),
809 all_image_types = self.parameters.image_types,
810 all_package_formats = self.parameters.all_package_formats,
811 all_distros = self.parameters.all_distros,
812 all_sdk_machines = self.parameters.all_sdk_machines,
813 max_threads = self.parameters.max_threads,
814 enable_proxy = self.parameters.enable_proxy,
816 flags = gtk.DIALOG_MODAL
817 | gtk.DIALOG_DESTROY_WITH_PARENT
818 | gtk.DIALOG_NO_SEPARATOR)
819 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
820 HobAltButton.style_button(button)
821 button = dialog.add_button("Save", gtk.RESPONSE_YES)
822 HobButton.style_button(button)
823 response = dialog.run()
824 settings_changed = False
825 if response == gtk.RESPONSE_YES:
826 self.parameters.enable_proxy = dialog.enable_proxy
827 self.configuration = dialog.configuration
828 settings_changed = dialog.settings_changed
830 return response == gtk.RESPONSE_YES, settings_changed
832 def reparse_post_adv_settings(self):
834 if self.configuration.curr_mach == "":
835 self.switch_page(self.MACHINE_SELECTION)
837 self.switch_page(self.RCPPKGINFO_POPULATING)
839 def deploy_image(self, image_name):
841 lbl = "<b>Please select an image to deploy.</b>"
842 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
843 button = dialog.add_button("Close", gtk.RESPONSE_OK)
844 HobButton.style_button(button)
849 image_path = os.path.join(self.parameters.image_addr, image_name)
850 dialog = DeployImageDialog(title = "Usb Image Maker",
851 image_path = image_path,
853 flags = gtk.DIALOG_MODAL
854 | gtk.DIALOG_DESTROY_WITH_PARENT
855 | gtk.DIALOG_NO_SEPARATOR)
856 button = dialog.add_button("Close", gtk.RESPONSE_NO)
857 HobAltButton.style_button(button)
858 button = dialog.add_button("Make usb image", gtk.RESPONSE_YES)
859 HobButton.style_button(button)
860 response = dialog.run()
863 def runqemu_image(self, image_name):
865 lbl = "<b>Please select an image to launch in QEMU.</b>"
866 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
867 button = dialog.add_button("Close", gtk.RESPONSE_OK)
868 HobButton.style_button(button)
873 dialog = gtk.FileChooserDialog("Load Kernel Files", self,
874 gtk.FILE_CHOOSER_ACTION_SAVE)
875 button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
876 HobAltButton.style_button(button)
877 button = dialog.add_button("Open", gtk.RESPONSE_YES)
878 HobButton.style_button(button)
879 filter = gtk.FileFilter()
880 filter.set_name("Kernel Files")
881 filter.add_pattern("*.bin")
882 dialog.add_filter(filter)
884 dialog.set_current_folder(self.parameters.image_addr)
886 response = dialog.run()
887 if response == gtk.RESPONSE_YES:
888 kernel_path = dialog.get_filename()
889 image_path = os.path.join(self.parameters.image_addr, image_name)
892 if response == gtk.RESPONSE_YES:
893 source_env_path = os.path.join(self.parameters.core_base, "oe-init-build-env")
894 tmp_path = self.parameters.tmpdir
895 if os.path.exists(image_path) and os.path.exists(kernel_path) \
896 and os.path.exists(source_env_path) and os.path.exists(tmp_path):
897 cmdline = "/usr/bin/xterm -e "
898 cmdline += "\" export OE_TMPDIR=" + tmp_path + "; "
899 cmdline += "source " + source_env_path + " " + os.getcwd() + "; "
900 cmdline += "runqemu " + kernel_path + " " + image_path + "; bash\""
901 subprocess.Popen(shlex.split(cmdline))
903 lbl = "<b>Path error</b>\nOne of your paths is wrong,"
904 lbl = lbl + " please make sure the following paths exist:\n"
905 lbl = lbl + "image path:" + image_path + "\n"
906 lbl = lbl + "kernel path:" + kernel_path + "\n"
907 lbl = lbl + "source environment path:" + source_env_path + "\n"
908 lbl = lbl + "tmp path: " + tmp_path + "."
909 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR)
910 button = dialog.add_button("Close", gtk.RESPONSE_OK)
911 HobButton.style_button(button)
915 def show_packages(self, ask=True):
916 _, selected_recipes = self.recipe_model.get_selected_recipes()
917 if selected_recipes and ask:
918 lbl = "<b>Package list may be incomplete!</b>\nDo you want to build selected recipes"
919 lbl = lbl + " to get a full list or just view the existing packages?"
920 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
921 button = dialog.add_button("View packages", gtk.RESPONSE_NO)
922 HobAltButton.style_button(button)
923 button = dialog.add_button("Build packages", gtk.RESPONSE_YES)
924 HobButton.style_button(button)
925 dialog.set_default_response(gtk.RESPONSE_YES)
926 response = dialog.run()
928 if response == gtk.RESPONSE_YES:
929 self.switch_page(self.PACKAGE_GENERATING)
931 self.switch_page(self.PACKAGE_SELECTION)
933 self.switch_page(self.PACKAGE_SELECTION)
935 def show_recipes(self):
936 self.switch_page(self.RECIPE_SELECTION)
938 def initiate_new_build(self):
939 self.configuration.curr_mach = ""
940 self.image_configuration_page.switch_machine_combo()
941 self.switch_page(self.MACHINE_SELECTION)
943 def show_configuration(self):
944 self.switch_page(self.BASEIMG_SELECTED)
946 def stop_parse(self):
947 self.handler.cancel_parse()
949 def stop_build(self):
951 lbl = "<b>Force Stop build?</b>\nYou've already selected Stop once,"
952 lbl = lbl + " would you like to 'Force Stop' the build?\n\n"
953 lbl = lbl + "This will stop the build as quickly as possible but may"
954 lbl = lbl + " well leave your build directory in an unusable state"
955 lbl = lbl + " that requires manual steps to fix.\n"
956 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
957 button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
958 HobAltButton.style_button(button)
959 button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
960 HobButton.style_button(button)
962 lbl = "<b>Stop build?</b>\n\nAre you sure you want to stop this"
963 lbl = lbl + " build?\n\n'Force Stop' will stop the build as quickly as"
964 lbl = lbl + " possible but may well leave your build directory in an"
965 lbl = lbl + " unusable state that requires manual steps to fix.\n\n"
966 lbl = lbl + "'Stop' will stop the build as soon as all in"
967 lbl = lbl + " progress build tasks are finished. However if a"
968 lbl = lbl + " lengthy compilation phase is in progress this may take"
969 lbl = lbl + " some time."
970 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
971 button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
972 HobAltButton.style_button(button)
973 button = dialog.add_button("Stop", gtk.RESPONSE_OK)
974 HobAltButton.style_button(button)
975 button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
976 HobButton.style_button(button)
977 response = dialog.run()
979 if response != gtk.RESPONSE_CANCEL:
981 if response == gtk.RESPONSE_OK:
982 self.handler.cancel_build()
983 elif response == gtk.RESPONSE_YES:
984 self.handler.cancel_build(True)