Hob: Get image name internally when updating the image description
[bitbake.git] / lib / bb / ui / crumbs / builder.py
1 #!/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
24 import gtk
25 import copy
26 import os
27 import subprocess
28 import shlex
29 import re
30 from bb.ui.crumbs.template import TemplateMgr
31 from bb.ui.crumbs.imageconfigurationpage import ImageConfigurationPage
32 from bb.ui.crumbs.recipeselectionpage import RecipeSelectionPage
33 from bb.ui.crumbs.packageselectionpage import PackageSelectionPage
34 from bb.ui.crumbs.builddetailspage import BuildDetailsPage
35 from bb.ui.crumbs.imagedetailspage import ImageDetailsPage
36 from bb.ui.crumbs.hobwidget import hwc, HobButton, HobAltButton, hcc
37 from bb.ui.crumbs.hig import CrumbsMessageDialog, ImageSelectionDialog, \
38                              AdvancedSettingDialog, LayerSelectionDialog, \
39                              DeployImageDialog
40 from bb.ui.crumbs.persistenttooltip import PersistentTooltip
41 import bb.ui.crumbs.utils
42
43 class Configuration:
44     '''Represents the data structure of configuration.'''
45
46     @classmethod
47     def parse_proxy_string(cls, proxy):
48         pattern = "^\s*((http|https|ftp|git|cvs)://)?((\S+):(\S+)@)?(\S+):(\d+)/?"
49         match = re.search(pattern, proxy)
50         if match:
51             return match.group(2), match.group(4), match.group(5), match.group(6), match.group(7)
52         else:
53             return None, None, None, "", ""
54
55     @classmethod
56     def make_host_string(cls, prot, user, passwd, host, default_prot=""):
57         if host == None or host == "":
58             return ""
59
60         passwd = passwd or ""
61
62         if user != None and user != "":
63             if prot == None or prot == "":
64                 prot = default_prot
65             return prot + "://" + user + ":" + passwd + "@" + host
66         else:
67             if prot == None or prot == "":
68                 return host
69             else:
70                 return prot + "://" + host
71
72     @classmethod
73     def make_port_string(cls, port):
74         port = port or ""
75         return port
76
77     @classmethod
78     def make_proxy_string(cls, prot, user, passwd, host, port, default_prot=""):
79         if host == None or host == "" or port == None or port == "":
80             return ""
81
82         return Configuration.make_host_string(prot, user, passwd, host, default_prot) + ":" + Configuration.make_port_string(port)
83
84     def __init__(self):
85         self.curr_mach = ""
86         # settings
87         self.curr_distro = ""
88         self.dldir = self.sstatedir = self.sstatemirror = ""
89         self.pmake = self.bbthread = 0
90         self.curr_package_format = ""
91         self.image_rootfs_size = self.image_extra_size = 0
92         self.image_overhead_factor = 1
93         self.incompat_license = ""
94         self.curr_sdk_machine = ""
95         self.conf_version = self.lconf_version = ""
96         self.extra_setting = {}
97         self.toolchain_build = False
98         self.image_fstypes = ""
99         # bblayers.conf
100         self.layers = []
101         # image/recipes/packages
102         self.clear_selection()
103
104         self.user_selected_packages = []
105
106         self.default_task = "build"
107
108         # proxy settings
109         self.enable_proxy = None
110         self.same_proxy = False
111         self.proxies = {
112             "http"  : [None, None, None, "", ""],  # protocol : [prot, user, passwd, host, port]
113             "https" : [None, None, None, "", ""],
114             "ftp"   : [None, None, None, "", ""],
115             "git"   : [None, None, None, "", ""],
116             "cvs"   : [None, None, None, "", ""],
117         }
118
119     def clear_selection(self):
120         self.selected_image = None
121         self.selected_recipes = []
122         self.selected_packages = []
123
124     def split_proxy(self, protocol, proxy):
125         entry = []
126         prot, user, passwd, host, port = Configuration.parse_proxy_string(proxy)
127         entry.append(prot)
128         entry.append(user)
129         entry.append(passwd)
130         entry.append(host)
131         entry.append(port)
132         self.proxies[protocol] = entry
133
134     def combine_proxy(self, protocol):
135         entry = self.proxies[protocol]
136         return Configuration.make_proxy_string(entry[0], entry[1], entry[2], entry[3], entry[4], protocol)
137
138     def combine_host_only(self, protocol):
139         entry = self.proxies[protocol]
140         return Configuration.make_host_string(entry[0], entry[1], entry[2], entry[3], protocol)
141
142     def combine_port_only(self, protocol):
143         entry = self.proxies[protocol]
144         return Configuration.make_port_string(entry[4])
145
146     def update(self, params):
147         # settings
148         self.curr_distro = params["distro"]
149         self.dldir = params["dldir"]
150         self.sstatedir = params["sstatedir"]
151         self.sstatemirror = params["sstatemirror"]
152         self.pmake = int(params["pmake"].split()[1])
153         self.bbthread = params["bbthread"]
154         self.curr_package_format = " ".join(params["pclass"].split("package_")).strip()
155         self.image_rootfs_size = params["image_rootfs_size"]
156         self.image_extra_size = params["image_extra_size"]
157         self.image_overhead_factor = params['image_overhead_factor']
158         self.incompat_license = params["incompat_license"]
159         self.curr_sdk_machine = params["sdk_machine"]
160         self.conf_version = params["conf_version"]
161         self.lconf_version = params["lconf_version"]
162         self.image_fstypes = params["image_fstypes"]
163         # self.extra_setting/self.toolchain_build
164         # bblayers.conf
165         self.layers = params["layer"].split()
166         self.default_task = params["default_task"]
167
168         # proxy settings
169         self.enable_proxy = params["http_proxy"] != "" or params["https_proxy"] != "" or params["ftp_proxy"] != "" \
170             or params["git_proxy_host"] != "" or params["git_proxy_port"] != ""                                    \
171             or params["cvs_proxy_host"] != "" or params["cvs_proxy_port"] != ""
172         self.split_proxy("http", params["http_proxy"])
173         self.split_proxy("https", params["https_proxy"])
174         self.split_proxy("ftp", params["ftp_proxy"])
175         self.split_proxy("git", params["git_proxy_host"] + ":" + params["git_proxy_port"])
176         self.split_proxy("cvs", params["cvs_proxy_host"] + ":" + params["cvs_proxy_port"])
177
178     def load(self, template):
179         self.curr_mach = template.getVar("MACHINE")
180         self.curr_package_format = " ".join(template.getVar("PACKAGE_CLASSES").split("package_")).strip()
181         self.curr_distro = template.getVar("DISTRO")
182         self.dldir = template.getVar("DL_DIR")
183         self.sstatedir = template.getVar("SSTATE_DIR")
184         self.sstatemirror = template.getVar("SSTATE_MIRROR")
185         try:
186             self.pmake = int(template.getVar("PARALLEL_MAKE").split()[1])
187         except:
188             pass
189         try:
190             self.bbthread = int(template.getVar("BB_NUMBER_THREADS"))
191         except:
192             pass
193         try:
194             self.image_rootfs_size = int(template.getVar("IMAGE_ROOTFS_SIZE"))
195         except:
196             pass
197         try:
198             self.image_extra_size = int(template.getVar("IMAGE_EXTRA_SPACE"))
199         except:
200             pass
201         # image_overhead_factor is read-only.
202         self.incompat_license = template.getVar("INCOMPATIBLE_LICENSE")
203         self.curr_sdk_machine = template.getVar("SDKMACHINE")
204         self.conf_version = template.getVar("CONF_VERSION")
205         self.lconf_version = template.getVar("LCONF_VERSION")
206         self.extra_setting = eval(template.getVar("EXTRA_SETTING"))
207         self.toolchain_build = eval(template.getVar("TOOLCHAIN_BUILD"))
208         self.image_fstypes = template.getVar("IMAGE_FSTYPES")
209         # bblayers.conf
210         self.layers = template.getVar("BBLAYERS").split()
211         # image/recipes/packages
212         self.selected_image = template.getVar("__SELECTED_IMAGE__")
213         self.selected_recipes = template.getVar("DEPENDS").split()
214         self.selected_packages = template.getVar("IMAGE_INSTALL").split()
215         # proxy
216         self.enable_proxy = eval(template.getVar("enable_proxy"))
217         self.same_proxy = eval(template.getVar("use_same_proxy"))
218         self.split_proxy("http", template.getVar("http_proxy"))
219         self.split_proxy("https", template.getVar("https_proxy"))
220         self.split_proxy("ftp", template.getVar("ftp_proxy"))
221         self.split_proxy("git", template.getVar("GIT_PROXY_HOST") + ":" + template.getVar("GIT_PROXY_PORT"))
222         self.split_proxy("cvs", template.getVar("CVS_PROXY_HOST") + ":" + template.getVar("CVS_PROXY_PORT"))
223
224     def save(self, template, defaults=False):
225         # bblayers.conf
226         template.setVar("BBLAYERS", " ".join(self.layers))
227         # local.conf
228         if not defaults:
229             template.setVar("MACHINE", self.curr_mach)
230         template.setVar("DISTRO", self.curr_distro)
231         template.setVar("DL_DIR", self.dldir)
232         template.setVar("SSTATE_DIR", self.sstatedir)
233         template.setVar("SSTATE_MIRROR", self.sstatemirror)
234         template.setVar("PARALLEL_MAKE", "-j %s" % self.pmake)
235         template.setVar("BB_NUMBER_THREADS", self.bbthread)
236         template.setVar("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()]))
237         template.setVar("IMAGE_ROOTFS_SIZE", self.image_rootfs_size)
238         template.setVar("IMAGE_EXTRA_SPACE", self.image_extra_size)
239         template.setVar("INCOMPATIBLE_LICENSE", self.incompat_license)
240         template.setVar("SDKMACHINE", self.curr_sdk_machine)
241         template.setVar("CONF_VERSION", self.conf_version)
242         template.setVar("LCONF_VERSION", self.lconf_version)
243         template.setVar("EXTRA_SETTING", self.extra_setting)
244         template.setVar("TOOLCHAIN_BUILD", self.toolchain_build)
245         template.setVar("IMAGE_FSTYPES", self.image_fstypes)
246         if not defaults:
247             # image/recipes/packages
248             template.setVar("__SELECTED_IMAGE__", self.selected_image)
249             template.setVar("DEPENDS", self.selected_recipes)
250             template.setVar("IMAGE_INSTALL", self.user_selected_packages)
251         # proxy
252         template.setVar("enable_proxy", self.enable_proxy)
253         template.setVar("use_same_proxy", self.same_proxy)
254         template.setVar("http_proxy", self.combine_proxy("http"))
255         template.setVar("https_proxy", self.combine_proxy("https"))
256         template.setVar("ftp_proxy", self.combine_proxy("ftp"))
257         template.setVar("GIT_PROXY_HOST", self.combine_host_only("git"))
258         template.setVar("GIT_PROXY_PORT", self.combine_port_only("git"))
259         template.setVar("CVS_PROXY_HOST", self.combine_host_only("cvs"))
260         template.setVar("CVS_PROXY_PORT", self.combine_port_only("cvs"))
261
262 class Parameters:
263     '''Represents other variables like available machines, etc.'''
264
265     def __init__(self):
266         # Variables
267         self.max_threads = 65535
268         self.core_base = ""
269         self.image_addr = ""
270         self.image_types = []
271         self.runnable_image_types = []
272         self.runnable_machine_patterns = []
273         self.deployable_image_types = []
274         self.tmpdir = ""
275
276         self.all_machines = []
277         self.all_package_formats = []
278         self.all_distros = []
279         self.all_sdk_machines = []
280         self.all_layers = []
281         self.image_names = []
282         self.image_white_pattern = ""
283         self.image_black_pattern = ""
284
285         # for build log to show
286         self.bb_version = ""
287         self.target_arch = ""
288         self.target_os = ""
289         self.distro_version = ""
290         self.tune_pkgarch = ""
291
292     def update(self, params):
293         self.max_threads = params["max_threads"]
294         self.core_base = params["core_base"]
295         self.image_addr = params["image_addr"]
296         self.image_types = params["image_types"].split()
297         self.runnable_image_types = params["runnable_image_types"].split()
298         self.runnable_machine_patterns = params["runnable_machine_patterns"].split()
299         self.deployable_image_types = params["deployable_image_types"].split()
300         self.tmpdir = params["tmpdir"]
301         self.image_white_pattern = params["image_white_pattern"]
302         self.image_black_pattern = params["image_black_pattern"]
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
310 def hob_conf_filter(fn, data):
311     if fn.endswith("/local.conf"):
312         distro = data.getVar("DISTRO_HOB")
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_MIRROR_HOB", "INCOMPATIBLE_LICENSE_HOB"]
322         for key in keys:
323             var_hob = data.getVar(key)
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")
330         if layers:
331             data.setVar("BBLAYERS", layers)
332         return
333
334 class Builder(gtk.Window):
335
336     (MACHINE_SELECTION,
337      RCPPKGINFO_POPULATING,
338      RCPPKGINFO_POPULATED,
339      BASEIMG_SELECTED,
340      RECIPE_SELECTION,
341      PACKAGE_GENERATING,
342      PACKAGE_GENERATED,
343      PACKAGE_SELECTION,
344      FAST_IMAGE_GENERATING,
345      IMAGE_GENERATING,
346      IMAGE_GENERATED,
347      MY_IMAGE_OPENED,
348      BACK,
349      END_NOOP) = range(14)
350
351     (IMAGE_CONFIGURATION,
352      RECIPE_DETAILS,
353      BUILD_DETAILS,
354      PACKAGE_DETAILS,
355      IMAGE_DETAILS,
356      END_TAB) = range(6)
357
358     __step2page__ = {
359         MACHINE_SELECTION     : IMAGE_CONFIGURATION,
360         RCPPKGINFO_POPULATING : IMAGE_CONFIGURATION,
361         RCPPKGINFO_POPULATED  : IMAGE_CONFIGURATION,
362         BASEIMG_SELECTED      : IMAGE_CONFIGURATION,
363         RECIPE_SELECTION      : RECIPE_DETAILS,
364         PACKAGE_GENERATING    : BUILD_DETAILS,
365         PACKAGE_GENERATED     : PACKAGE_DETAILS,
366         PACKAGE_SELECTION     : PACKAGE_DETAILS,
367         FAST_IMAGE_GENERATING : BUILD_DETAILS,
368         IMAGE_GENERATING      : BUILD_DETAILS,
369         IMAGE_GENERATED       : IMAGE_DETAILS,
370         MY_IMAGE_OPENED       : IMAGE_DETAILS,
371         END_NOOP              : None,
372     }
373
374     def __init__(self, hobHandler, recipe_model, package_model):
375         super(Builder, self).__init__()
376
377         self.hob_image = "hob-image"
378         self.hob_toolchain = "hob-toolchain"
379
380         # handler
381         self.handler = hobHandler
382
383         self.template = None
384
385         # configuration and parameters
386         self.configuration = Configuration()
387         self.parameters = Parameters()
388
389         # build step
390         self.current_step = None
391         self.previous_step = None
392
393         self.stopping = False
394
395         # recipe model and package model
396         self.recipe_model = recipe_model
397         self.package_model = package_model
398
399         # Indicate whether user has customized the image
400         self.customized = False
401
402         # Indicate whether the UI is working
403         self.sensitive = True
404
405         # create visual elements
406         self.create_visual_elements()
407
408         # connect the signals to functions
409         self.connect("delete-event", self.destroy_window_cb)
410         self.recipe_model.connect ("recipe-selection-changed",  self.recipelist_changed_cb)
411         self.package_model.connect("package-selection-changed", self.packagelist_changed_cb)
412         self.handler.connect("config-updated",           self.handler_config_updated_cb)
413         self.handler.connect("package-formats-updated",  self.handler_package_formats_updated_cb)
414         self.handler.connect("parsing-started",          self.handler_parsing_started_cb)
415         self.handler.connect("parsing",                  self.handler_parsing_cb)
416         self.handler.connect("parsing-completed",        self.handler_parsing_completed_cb)
417         self.handler.build.connect("build-started",      self.handler_build_started_cb)
418         self.handler.build.connect("build-succeeded",    self.handler_build_succeeded_cb)
419         self.handler.build.connect("build-failed",       self.handler_build_failed_cb)
420         self.handler.build.connect("task-started",       self.handler_task_started_cb)
421         self.handler.build.connect("log-error",          self.handler_build_failure_cb)
422         self.handler.build.connect("no-provider",        self.handler_no_provider_cb)
423         self.handler.connect("generating-data",          self.handler_generating_data_cb)
424         self.handler.connect("data-generated",           self.handler_data_generated_cb)
425         self.handler.connect("command-succeeded",        self.handler_command_succeeded_cb)
426         self.handler.connect("command-failed",           self.handler_command_failed_cb)
427
428         self.handler.set_config_filter(hob_conf_filter)
429
430         self.initiate_new_build_async()
431
432     def create_visual_elements(self):
433         self.set_title("Hob")
434         self.set_icon_name("applications-development")
435         self.set_resizable(True)
436         window_width = self.get_screen().get_width()
437         window_height = self.get_screen().get_height()
438         if window_width >= hwc.MAIN_WIN_WIDTH:
439             window_width = hwc.MAIN_WIN_WIDTH
440             window_height = hwc.MAIN_WIN_HEIGHT
441         self.set_size_request(window_width, window_height)
442
443         self.vbox = gtk.VBox(False, 0)
444         self.vbox.set_border_width(0)
445         self.add(self.vbox)
446
447         # create pages
448         self.image_configuration_page = ImageConfigurationPage(self)
449         self.recipe_details_page      = RecipeSelectionPage(self)
450         self.build_details_page       = BuildDetailsPage(self)
451         self.package_details_page     = PackageSelectionPage(self)
452         self.image_details_page       = ImageDetailsPage(self)
453
454         self.nb = gtk.Notebook()
455         self.nb.set_show_tabs(False)
456         self.nb.insert_page(self.image_configuration_page, None, self.IMAGE_CONFIGURATION)
457         self.nb.insert_page(self.recipe_details_page,      None, self.RECIPE_DETAILS)
458         self.nb.insert_page(self.build_details_page,       None, self.BUILD_DETAILS)
459         self.nb.insert_page(self.package_details_page,     None, self.PACKAGE_DETAILS)
460         self.nb.insert_page(self.image_details_page,       None, self.IMAGE_DETAILS)
461         self.vbox.pack_start(self.nb, expand=True, fill=True)
462
463         self.show_all()
464         self.nb.set_current_page(0)
465
466     def initiate_new_build_async(self):
467         self.switch_page(self.MACHINE_SELECTION)
468         if self.load_template(TemplateMgr.convert_to_template_pathfilename("default", ".hob/")) == None:
469             self.handler.init_cooker()
470             self.handler.set_extra_inherit("image_types")
471             self.handler.generate_configuration()
472
473     def update_config_async(self):
474         self.switch_page(self.MACHINE_SELECTION)
475         self.set_user_config()
476         self.handler.generate_configuration()
477
478     def sanity_check(self):
479         self.handler.trigger_sanity_check()
480
481     def populate_recipe_package_info_async(self):
482         self.switch_page(self.RCPPKGINFO_POPULATING)
483         # Parse recipes
484         self.set_user_config()
485         self.handler.generate_recipes()
486
487     def generate_packages_async(self):
488         self.switch_page(self.PACKAGE_GENERATING)
489         # Build packages
490         _, all_recipes = self.recipe_model.get_selected_recipes()
491         self.set_user_config()
492         self.handler.reset_build()
493         self.handler.generate_packages(all_recipes, self.configuration.default_task)
494
495     def fast_generate_image_async(self):
496         self.switch_page(self.FAST_IMAGE_GENERATING)
497         # Build packages
498         _, all_recipes = self.recipe_model.get_selected_recipes()
499         self.set_user_config()
500         self.handler.reset_build()
501         self.handler.generate_packages(all_recipes, self.configuration.default_task)
502
503     def generate_image_async(self):
504         self.switch_page(self.IMAGE_GENERATING)
505         self.handler.reset_build()
506         # Build image
507         self.set_user_config()
508         toolchain_packages = []
509         if self.configuration.toolchain_build:
510             toolchain_packages = self.package_model.get_selected_packages_toolchain()
511         if self.configuration.selected_image == self.recipe_model.__dummy_image__:
512             packages = self.package_model.get_selected_packages()
513             image = self.hob_image
514         else:
515             packages = []
516             image = self.configuration.selected_image
517         self.handler.generate_image(image,
518                                     self.hob_toolchain,
519                                     packages,
520                                     toolchain_packages,
521                                     self.configuration.default_task)
522
523     def get_parameters_sync(self):
524         return self.handler.get_parameters()
525
526     def request_package_info_async(self):
527         self.handler.request_package_info()
528
529     def cancel_build_sync(self, force=False):
530         self.handler.cancel_build(force)
531
532     def cancel_parse_sync(self):
533         self.handler.cancel_parse()
534
535     def load_template(self, path):
536         if not os.path.isfile(path):
537             return None
538
539         self.template = TemplateMgr()
540         try:
541             self.template.load(path)
542             self.configuration.load(self.template)
543         except Exception as e:
544             self.show_error_dialog("Hob Exception - %s" % (str(e)))
545             self.reset()
546         finally:
547             self.template.destroy()
548             self.template = None
549
550         for layer in self.configuration.layers:
551             if not os.path.exists(layer+'/conf/layer.conf'):
552                 return False
553
554         self.save_defaults() # remember layers and settings
555         self.update_config_async()
556         return True
557
558     def save_template(self, path, defaults=False):
559         if path.rfind("/") == -1:
560             filename = "default"
561             path = "."
562         else:
563             filename = path[path.rfind("/") + 1:len(path)]
564             path = path[0:path.rfind("/")]
565
566         self.template = TemplateMgr()
567         try:
568             self.template.open(filename, path)
569             self.configuration.save(self.template, defaults)
570
571             self.template.save()
572         except Exception as e:
573             self.show_error_dialog("Hob Exception - %s" % (str(e)))
574             self.reset()
575         finally:
576             self.template.destroy()
577             self.template = None
578
579     def save_defaults(self):
580         if not os.path.exists(".hob/"):
581             os.mkdir(".hob/")
582         self.save_template(".hob/default", True)
583
584     def switch_page(self, next_step):
585         # Main Workflow (Business Logic)
586         self.nb.set_current_page(self.__step2page__[next_step])
587
588         if next_step == self.MACHINE_SELECTION: # init step
589             self.image_configuration_page.show_machine()
590
591         elif next_step == self.RCPPKGINFO_POPULATING:
592             # MACHINE CHANGED action or SETTINGS CHANGED
593             # show the progress bar
594             self.image_configuration_page.show_info_populating()
595
596         elif next_step == self.RCPPKGINFO_POPULATED:
597             self.image_configuration_page.show_info_populated()
598
599         elif next_step == self.BASEIMG_SELECTED:
600             self.image_configuration_page.show_baseimg_selected()
601
602         elif next_step == self.RECIPE_SELECTION:
603             pass
604
605         elif next_step == self.PACKAGE_SELECTION:
606             pass
607
608         elif next_step == self.PACKAGE_GENERATING or next_step == self.FAST_IMAGE_GENERATING:
609             # both PACKAGE_GENEATING and FAST_IMAGE_GENERATING share the same page
610             self.build_details_page.show_page(next_step)
611
612         elif next_step == self.PACKAGE_GENERATED:
613             pass
614
615         elif next_step == self.IMAGE_GENERATING:
616             # after packages are generated, selected_packages need to
617             # be updated in package_model per selected_image in recipe_model
618             self.build_details_page.show_page(next_step)
619
620         elif next_step == self.IMAGE_GENERATED:
621             self.image_details_page.show_page(next_step)
622
623         elif next_step == self.MY_IMAGE_OPENED:
624             self.image_details_page.show_page(next_step)
625
626         self.previous_step = self.current_step
627         self.current_step = next_step
628
629     def set_user_config(self):
630         self.handler.init_cooker()
631         # set bb layers
632         self.handler.set_bblayers(self.configuration.layers)
633         # set local configuration
634         self.handler.set_machine(self.configuration.curr_mach)
635         self.handler.set_package_format(self.configuration.curr_package_format)
636         self.handler.set_distro(self.configuration.curr_distro)
637         self.handler.set_dl_dir(self.configuration.dldir)
638         self.handler.set_sstate_dir(self.configuration.sstatedir)
639         self.handler.set_sstate_mirror(self.configuration.sstatemirror)
640         self.handler.set_pmake(self.configuration.pmake)
641         self.handler.set_bbthreads(self.configuration.bbthread)
642         self.handler.set_rootfs_size(self.configuration.image_rootfs_size)
643         self.handler.set_extra_size(self.configuration.image_extra_size)
644         self.handler.set_incompatible_license(self.configuration.incompat_license)
645         self.handler.set_sdk_machine(self.configuration.curr_sdk_machine)
646         self.handler.set_image_fstypes(self.configuration.image_fstypes)
647         self.handler.set_extra_config(self.configuration.extra_setting)
648         self.handler.set_extra_inherit("packageinfo")
649         self.handler.set_extra_inherit("image_types")
650         # set proxies
651         if self.configuration.enable_proxy == True:
652             self.handler.set_http_proxy(self.configuration.combine_proxy("http"))
653             self.handler.set_https_proxy(self.configuration.combine_proxy("https"))
654             self.handler.set_ftp_proxy(self.configuration.combine_proxy("ftp"))
655             self.handler.set_git_proxy(self.configuration.combine_host_only("git"), self.configuration.combine_port_only("git"))
656             self.handler.set_cvs_proxy(self.configuration.combine_host_only("cvs"), self.configuration.combine_port_only("cvs"))
657         elif self.configuration.enable_proxy == False:
658             self.handler.set_http_proxy("")
659             self.handler.set_https_proxy("")
660             self.handler.set_ftp_proxy("")
661             self.handler.set_git_proxy("", "")
662             self.handler.set_cvs_proxy("", "")
663
664     def update_recipe_model(self, selected_image, selected_recipes):
665         self.recipe_model.set_selected_image(selected_image)
666         self.recipe_model.set_selected_recipes(selected_recipes)
667
668     def update_package_model(self, selected_packages):
669         left = self.package_model.set_selected_packages(selected_packages)
670         self.configuration.selected_packages += left
671
672     def update_configuration_parameters(self, params):
673         if params:
674             self.configuration.update(params)
675             self.parameters.update(params)
676
677     def reset(self):
678         self.configuration.curr_mach = ""
679         self.configuration.clear_selection()
680         self.image_configuration_page.switch_machine_combo()
681         self.switch_page(self.MACHINE_SELECTION)
682
683     # Callback Functions
684     def handler_config_updated_cb(self, handler, which, values):
685         if which == "distro":
686             self.parameters.all_distros = values
687         elif which == "machine":
688             self.parameters.all_machines = values
689             self.image_configuration_page.update_machine_combo()
690         elif which == "machine-sdk":
691             self.parameters.all_sdk_machines = values
692
693     def handler_package_formats_updated_cb(self, handler, formats):
694         self.parameters.all_package_formats = formats
695
696     def handler_command_succeeded_cb(self, handler, initcmd):
697         if initcmd == self.handler.GENERATE_CONFIGURATION:
698             self.update_configuration_parameters(self.get_parameters_sync())
699             self.sanity_check()
700         elif initcmd == self.handler.SANITY_CHECK:
701             self.image_configuration_page.switch_machine_combo()
702         elif initcmd in [self.handler.GENERATE_RECIPES,
703                          self.handler.GENERATE_PACKAGES,
704                          self.handler.GENERATE_IMAGE]:
705             self.update_configuration_parameters(self.get_parameters_sync())
706             self.request_package_info_async()
707         elif initcmd == self.handler.POPULATE_PACKAGEINFO:
708             if self.current_step == self.RCPPKGINFO_POPULATING:
709                 self.switch_page(self.RCPPKGINFO_POPULATED)
710                 self.rcppkglist_populated()
711                 return
712
713             self.rcppkglist_populated()
714             if self.current_step == self.FAST_IMAGE_GENERATING:
715                 self.generate_image_async()
716
717     def show_error_dialog(self, msg):
718         lbl = "<b>Error</b>\n"
719         lbl = lbl + "%s\n\n" % msg
720         dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR)
721         button = dialog.add_button("Close", gtk.RESPONSE_OK)
722         HobButton.style_button(button)
723         response = dialog.run()
724         dialog.destroy()
725
726     def handler_command_failed_cb(self, handler, msg):
727         if msg:
728             msg = msg.replace("your local.conf", "Settings")
729             self.show_error_dialog(msg)
730         self.reset()
731
732     def window_sensitive(self, sensitive):
733         self.image_configuration_page.machine_combo.set_sensitive(sensitive)
734         self.image_configuration_page.image_combo.set_sensitive(sensitive)
735         self.image_configuration_page.layer_button.set_sensitive(sensitive)
736         self.image_configuration_page.layer_info_icon.set_sensitive(sensitive)
737         self.image_configuration_page.toolbar.set_sensitive(sensitive)
738         self.image_configuration_page.view_recipes_button.set_sensitive(sensitive)
739         self.image_configuration_page.view_packages_button.set_sensitive(sensitive)
740         self.image_configuration_page.config_build_button.set_sensitive(sensitive)
741
742         self.recipe_details_page.set_sensitive(sensitive)
743         self.package_details_page.set_sensitive(sensitive)
744         self.build_details_page.set_sensitive(sensitive)
745         self.image_details_page.set_sensitive(sensitive)
746
747         if sensitive:
748             self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
749         else:
750             self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
751         self.sensitive = sensitive
752
753
754     def handler_generating_data_cb(self, handler):
755         self.window_sensitive(False)
756
757     def handler_data_generated_cb(self, handler):
758         self.window_sensitive(True)
759
760     def rcppkglist_populated(self):
761         selected_image = self.configuration.selected_image
762         selected_recipes = self.configuration.selected_recipes[:]
763         selected_packages = self.configuration.selected_packages[:]
764
765         self.image_configuration_page.update_image_combo(self.recipe_model, selected_image)
766         self.image_configuration_page.update_image_desc()
767         self.update_recipe_model(selected_image, selected_recipes)
768         self.update_package_model(selected_packages)
769
770     def recipelist_changed_cb(self, recipe_model):
771         self.recipe_details_page.refresh_selection()
772
773     def packagelist_changed_cb(self, package_model):
774         self.package_details_page.refresh_selection()
775
776     def handler_parsing_started_cb(self, handler, message):
777         if self.current_step != self.RCPPKGINFO_POPULATING:
778             return
779
780         fraction = 0
781         if message["eventname"] == "TreeDataPreparationStarted":
782             fraction = 0.6 + fraction
783             self.image_configuration_page.stop_button.set_sensitive(False)
784         else:
785             self.image_configuration_page.stop_button.set_sensitive(True)
786
787         self.image_configuration_page.update_progress_bar(message["title"], fraction)
788
789     def handler_parsing_cb(self, handler, message):
790         if self.current_step != self.RCPPKGINFO_POPULATING:
791             return
792
793         fraction = message["current"] * 1.0/message["total"]
794         if message["eventname"] == "TreeDataPreparationProgress":
795             fraction = 0.6 + 0.4 * fraction
796         else:
797             fraction = 0.6 * fraction
798         self.image_configuration_page.update_progress_bar(message["title"], fraction)
799
800     def handler_parsing_completed_cb(self, handler, message):
801         if self.current_step != self.RCPPKGINFO_POPULATING:
802             return
803
804         if message["eventname"] == "TreeDataPreparationCompleted":
805             fraction = 1.0
806         else:
807             fraction = 0.6
808         self.image_configuration_page.update_progress_bar(message["title"], fraction)
809
810     def handler_build_started_cb(self, running_build):
811         if self.current_step == self.FAST_IMAGE_GENERATING:
812             fraction = 0
813         elif self.current_step == self.IMAGE_GENERATING:
814             if self.previous_step == self.FAST_IMAGE_GENERATING:
815                 fraction = 0.9
816             else:
817                 fraction = 0
818         elif self.current_step == self.PACKAGE_GENERATING:
819             fraction = 0
820         self.build_details_page.update_progress_bar("Build Started: ", fraction)
821         self.build_details_page.show_configurations(self.configuration, self.parameters)
822
823     def build_succeeded(self):
824         if self.current_step == self.FAST_IMAGE_GENERATING:
825             fraction = 0.9
826         elif self.current_step == self.IMAGE_GENERATING:
827             fraction = 1.0
828             self.parameters.image_names = []
829             selected_image = self.recipe_model.get_selected_image()
830             if selected_image == self.recipe_model.__dummy_image__:
831                 linkname = 'hob-image-' + self.configuration.curr_mach
832             else:
833                 linkname = selected_image + '-' + self.configuration.curr_mach
834             for image_type in self.parameters.image_types:
835                 for real_image_type in hcc.SUPPORTED_IMAGE_TYPES[image_type]:
836                     linkpath = self.parameters.image_addr + '/' + linkname + '.' + real_image_type
837                     if os.path.exists(linkpath):
838                         self.parameters.image_names.append(os.readlink(linkpath))
839         elif self.current_step == self.PACKAGE_GENERATING:
840             fraction = 1.0
841         self.build_details_page.update_progress_bar("Build Completed: ", fraction)
842         self.handler.build_succeeded_async()
843         self.stopping = False
844
845         if self.current_step == self.PACKAGE_GENERATING:
846             self.switch_page(self.PACKAGE_GENERATED)
847         elif self.current_step == self.IMAGE_GENERATING:
848             self.switch_page(self.IMAGE_GENERATED)
849
850     def build_failed(self):
851         if self.stopping:
852             status = "stop"
853             message = "Build stopped: "
854             fraction = self.build_details_page.progress_bar.get_fraction()
855         else:
856             if self.current_step == self.FAST_IMAGE_GENERATING:
857                 fraction = 0.9
858             elif self.current_step == self.IMAGE_GENERATING:
859                 fraction = 1.0
860             elif self.current_step == self.PACKAGE_GENERATING:
861                 fraction = 1.0
862             status = "fail"
863             message = "Build failed: "
864         self.build_details_page.update_progress_bar(message, fraction, status)
865         self.build_details_page.show_back_button()
866         self.build_details_page.hide_stop_button()
867         self.handler.build_failed_async()
868         self.stopping = False
869
870     def handler_build_succeeded_cb(self, running_build):
871         if not self.stopping:
872             self.build_succeeded()
873         else:
874             self.build_failed()
875
876
877     def handler_build_failed_cb(self, running_build):
878         self.build_failed()
879
880     def handler_no_provider_cb(self, running_build, msg):
881         dialog = CrumbsMessageDialog(self, msg, gtk.STOCK_DIALOG_INFO)
882         button = dialog.add_button("Close", gtk.RESPONSE_OK)
883         HobButton.style_button(button)
884         dialog.run()
885         dialog.destroy()
886         self.build_failed()
887
888     def handler_task_started_cb(self, running_build, message): 
889         fraction = message["current"] * 1.0/message["total"]
890         title = "Build packages"
891         if self.current_step == self.FAST_IMAGE_GENERATING:
892             if message["eventname"] == "sceneQueueTaskStarted":
893                 fraction = 0.27 * fraction
894             elif message["eventname"] == "runQueueTaskStarted":
895                 fraction = 0.27 + 0.63 * fraction
896         elif self.current_step == self.IMAGE_GENERATING:
897             title = "Build image"
898             if self.previous_step == self.FAST_IMAGE_GENERATING:
899                 if message["eventname"] == "sceneQueueTaskStarted":
900                     fraction = 0.27 + 0.63 + 0.03 * fraction
901                 elif message["eventname"] == "runQueueTaskStarted":
902                     fraction = 0.27 + 0.63 + 0.03 + 0.07 * fraction
903             else:
904                 if message["eventname"] == "sceneQueueTaskStarted":
905                     fraction = 0.2 * fraction
906                 elif message["eventname"] == "runQueueTaskStarted":
907                     fraction = 0.2 + 0.8 * fraction
908         elif self.current_step == self.PACKAGE_GENERATING:
909             if message["eventname"] == "sceneQueueTaskStarted":
910                 fraction = 0.2 * fraction
911             elif message["eventname"] == "runQueueTaskStarted":
912                 fraction = 0.2 + 0.8 * fraction
913         self.build_details_page.update_progress_bar(title + ": ", fraction)
914         self.build_details_page.update_build_status(message["current"], message["total"], message["task"])
915
916     def handler_build_failure_cb(self, running_build):
917         self.build_details_page.show_issues()
918
919     def destroy_window_cb(self, widget, event):
920         if not self.sensitive:
921             return True
922         lbl = "<b>Do you really want to exit the Hob image creator?</b>"
923         dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
924         button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
925         HobAltButton.style_button(button)
926         button = dialog.add_button("Exit Hob", gtk.RESPONSE_YES)
927         HobButton.style_button(button)
928         dialog.set_default_response(gtk.RESPONSE_YES)
929         response = dialog.run()
930         dialog.destroy()
931         if response == gtk.RESPONSE_YES:
932             gtk.main_quit()
933             return False
934         else:
935             return True
936
937     def build_packages(self):
938         _, all_recipes = self.recipe_model.get_selected_recipes()
939         if not all_recipes:
940             lbl = "<b>No selections made</b>\nYou have not made any selections"
941             lbl = lbl + " so there isn't anything to bake at this time."
942             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
943             button = dialog.add_button("Close", gtk.RESPONSE_OK)
944             HobButton.style_button(button)
945             dialog.run()
946             dialog.destroy()
947             return
948         self.generate_packages_async()
949
950     def build_image(self):
951         selected_packages = self.package_model.get_selected_packages()
952         if not selected_packages:      
953             lbl = "<b>No selections made</b>\nYou have not made any selections"
954             lbl = lbl + " so there isn't anything to bake at this time."
955             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
956             button = dialog.add_button("Close", gtk.RESPONSE_OK)
957             HobButton.style_button(button)
958             dialog.run()
959             dialog.destroy()
960             return
961         self.generate_image_async()
962
963     def just_bake(self):
964         selected_image = self.recipe_model.get_selected_image()
965         selected_packages = self.package_model.get_selected_packages() or []
966
967         # If no base image and no selected packages don't build anything
968         if not (selected_packages or selected_image != self.recipe_model.__dummy_image__):
969             lbl = "<b>No selections made</b>\nYou have not made any selections"
970             lbl = lbl + " so there isn't anything to bake at this time."
971             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
972             button = dialog.add_button("Close", gtk.RESPONSE_OK)
973             HobButton.style_button(button)
974             dialog.run()
975             dialog.destroy()
976             return
977
978         self.fast_generate_image_async()
979
980     def show_binb_dialog(self, binb):
981         markup = "<b>Brought in by:</b>\n%s" % binb
982         ptip = PersistentTooltip(markup, self)
983
984         ptip.show()
985
986     def show_layer_selection_dialog(self):
987         dialog = LayerSelectionDialog(title = "Layers",
988                      layers = copy.deepcopy(self.configuration.layers),
989                      all_layers = self.parameters.all_layers,
990                      parent = self,
991                      flags = gtk.DIALOG_MODAL
992                          | gtk.DIALOG_DESTROY_WITH_PARENT
993                          | gtk.DIALOG_NO_SEPARATOR)
994         button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
995         HobAltButton.style_button(button)
996         button = dialog.add_button("OK", gtk.RESPONSE_YES)
997         HobButton.style_button(button)
998         response = dialog.run()
999         if response == gtk.RESPONSE_YES:
1000             self.configuration.layers = dialog.layers
1001             self.save_defaults() # remember layers
1002             # DO refresh layers
1003             if dialog.layers_changed:
1004                 self.update_config_async()
1005         dialog.destroy()
1006
1007     def show_load_template_dialog(self):
1008         dialog = gtk.FileChooserDialog("Load Template Files", self,
1009                                        gtk.FILE_CHOOSER_ACTION_OPEN)
1010         button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1011         HobAltButton.style_button(button)
1012         button = dialog.add_button("Open", gtk.RESPONSE_YES)
1013         HobButton.style_button(button)
1014         filter = gtk.FileFilter()
1015         filter.set_name("Hob Files")
1016         filter.add_pattern("*.hob")
1017         dialog.add_filter(filter)
1018
1019         response = dialog.run()
1020         path = None
1021         if response == gtk.RESPONSE_YES:
1022             path = dialog.get_filename()
1023         dialog.destroy()
1024         return response == gtk.RESPONSE_YES, path
1025
1026     def show_save_template_dialog(self):
1027         dialog = gtk.FileChooserDialog("Save Template Files", self,
1028                                        gtk.FILE_CHOOSER_ACTION_SAVE)
1029         button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1030         HobAltButton.style_button(button)
1031         button = dialog.add_button("Save", gtk.RESPONSE_YES)
1032         HobButton.style_button(button)
1033         dialog.set_current_name("hob")
1034         response = dialog.run()
1035         if response == gtk.RESPONSE_YES:
1036             path = dialog.get_filename()
1037             self.save_template(path)
1038         dialog.destroy()
1039
1040     def show_load_my_images_dialog(self):
1041         dialog = ImageSelectionDialog(self.parameters.image_addr, self.parameters.image_types,
1042                                       "Open My Images", self,
1043                                        gtk.FILE_CHOOSER_ACTION_SAVE)
1044         button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1045         HobAltButton.style_button(button)
1046         button = dialog.add_button("Open", gtk.RESPONSE_YES)
1047         HobButton.style_button(button)
1048         response = dialog.run()
1049         if response == gtk.RESPONSE_YES:
1050             if not dialog.image_names:
1051                 lbl = "<b>No selections made</b>\nYou have not made any selections"
1052                 crumbs_dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
1053                 button = crumbs_dialog.add_button("Close", gtk.RESPONSE_OK)
1054                 HobButton.style_button(button)
1055                 crumbs_dialog.run()
1056                 crumbs_dialog.destroy()
1057                 dialog.destroy()
1058                 return
1059
1060             self.parameters.image_addr = dialog.image_folder
1061             self.parameters.image_names = dialog.image_names[:]
1062             self.switch_page(self.MY_IMAGE_OPENED)
1063
1064         dialog.destroy()
1065
1066     def show_adv_settings_dialog(self):
1067         dialog = AdvancedSettingDialog(title = "Settings",
1068             configuration = copy.deepcopy(self.configuration),
1069             all_image_types = self.parameters.image_types,
1070             all_package_formats = self.parameters.all_package_formats,
1071             all_distros = self.parameters.all_distros,
1072             all_sdk_machines = self.parameters.all_sdk_machines,
1073             max_threads = self.parameters.max_threads,
1074             parent = self,
1075             flags = gtk.DIALOG_MODAL
1076                     | gtk.DIALOG_DESTROY_WITH_PARENT
1077                     | gtk.DIALOG_NO_SEPARATOR)
1078         button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1079         HobAltButton.style_button(button)
1080         button = dialog.add_button("Save", gtk.RESPONSE_YES)
1081         HobButton.style_button(button)
1082         response = dialog.run()
1083         settings_changed = False
1084         if response == gtk.RESPONSE_YES:
1085             self.configuration = dialog.configuration
1086             self.save_defaults() # remember settings
1087             settings_changed = dialog.settings_changed
1088         dialog.destroy()
1089         return response == gtk.RESPONSE_YES, settings_changed
1090
1091     def reparse_post_adv_settings(self):
1092         if not self.configuration.curr_mach:
1093             self.update_config_async()
1094         else:
1095             self.configuration.clear_selection()
1096             # DO reparse recipes
1097             self.populate_recipe_package_info_async()
1098
1099     def deploy_image(self, image_name):
1100         if not image_name:
1101             lbl = "<b>Please select an image to deploy.</b>"
1102             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
1103             button = dialog.add_button("Close", gtk.RESPONSE_OK)
1104             HobButton.style_button(button)
1105             dialog.run()
1106             dialog.destroy()
1107             return
1108
1109         image_path = os.path.join(self.parameters.image_addr, image_name)
1110         dialog = DeployImageDialog(title = "Usb Image Maker",
1111             image_path = image_path,
1112             parent = self,
1113             flags = gtk.DIALOG_MODAL
1114                     | gtk.DIALOG_DESTROY_WITH_PARENT
1115                     | gtk.DIALOG_NO_SEPARATOR)
1116         button = dialog.add_button("Close", gtk.RESPONSE_NO)
1117         HobAltButton.style_button(button)
1118         button = dialog.add_button("Make usb image", gtk.RESPONSE_YES)
1119         HobButton.style_button(button)
1120         response = dialog.run()
1121         dialog.destroy()
1122
1123     def get_kernel_file_name(self, image_path):
1124         name_list = []
1125         kernel_name = ""
1126         if image_path:
1127             files = [f for f in os.listdir(image_path) if f[0] <> '.']
1128             for check_file in files:
1129                 if check_file.endswith(".bin"):
1130                     name_splits = check_file.split(".")[0]
1131                     if self.configuration.curr_mach in name_splits.split("-"):
1132                         kernel_name = check_file
1133                     if not os.path.islink(os.path.join(image_path, check_file)):
1134                         name_list.append(check_file)
1135
1136         return kernel_name, len(name_list)
1137
1138     def runqemu_image(self, image_name):
1139         if not image_name:
1140             lbl = "<b>Please select an image to launch in QEMU.</b>"
1141             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
1142             button = dialog.add_button("Close", gtk.RESPONSE_OK)
1143             HobButton.style_button(button)
1144             dialog.run()
1145             dialog.destroy()
1146             return
1147
1148         kernel_name, kernels_number = self.get_kernel_file_name(self.parameters.image_addr)
1149         if not kernel_name or kernels_number > 1:
1150             dialog = gtk.FileChooserDialog("Load Kernel Files", self,
1151                                            gtk.FILE_CHOOSER_ACTION_SAVE)
1152             button = dialog.add_button("Cancel", gtk.RESPONSE_NO)
1153             HobAltButton.style_button(button)
1154             button = dialog.add_button("Open", gtk.RESPONSE_YES)
1155             HobButton.style_button(button)
1156             filter = gtk.FileFilter()
1157             filter.set_name("Kernel Files")
1158             filter.add_pattern("*.bin")
1159             dialog.add_filter(filter)
1160
1161             dialog.set_current_folder(self.parameters.image_addr)
1162
1163             response = dialog.run()
1164             if response == gtk.RESPONSE_YES:
1165                 kernel_path = dialog.get_filename()
1166                 image_path = os.path.join(self.parameters.image_addr, image_name)
1167             dialog.destroy()
1168
1169         elif kernel_name:
1170             kernel_path = os.path.join(self.parameters.image_addr, kernel_name)
1171             image_path = os.path.join(self.parameters.image_addr, image_name)
1172             response = gtk.RESPONSE_YES
1173
1174         if response == gtk.RESPONSE_YES:
1175             source_env_path = os.path.join(self.parameters.core_base, "oe-init-build-env")
1176             tmp_path = self.parameters.tmpdir
1177             cmdline = bb.ui.crumbs.utils.which_terminal()
1178             if os.path.exists(image_path) and os.path.exists(kernel_path) \
1179                and os.path.exists(source_env_path) and os.path.exists(tmp_path) \
1180                and cmdline:
1181                 cmdline += "\' bash -c \"export OE_TMPDIR=" + tmp_path + "; "
1182                 cmdline += "source " + source_env_path + " " + os.getcwd() + "; "
1183                 cmdline += "runqemu " + kernel_path + " " + image_path + "\"\'"
1184                 subprocess.Popen(shlex.split(cmdline))
1185             else:
1186                 lbl = "<b>Path error</b>\nOne of your paths is wrong,"
1187                 lbl = lbl + " please make sure the following paths exist:\n"
1188                 lbl = lbl + "image path:" + image_path + "\n"
1189                 lbl = lbl + "kernel path:" + kernel_path + "\n"
1190                 lbl = lbl + "source environment path:" + source_env_path + "\n"
1191                 lbl = lbl + "tmp path: " + tmp_path + "."
1192                 lbl = lbl + "You may be missing either xterm or vte for terminal services."
1193                 dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_ERROR)
1194                 button = dialog.add_button("Close", gtk.RESPONSE_OK)
1195                 HobButton.style_button(button)
1196                 dialog.run()
1197                 dialog.destroy()
1198
1199     def show_packages(self, ask=True):
1200         _, selected_recipes = self.recipe_model.get_selected_recipes()
1201         if selected_recipes and ask:
1202             lbl = "<b>Package list may be incomplete!</b>\nDo you want to build selected recipes"
1203             lbl = lbl + " to get a full list or just view the existing packages?"
1204             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_INFO)
1205             button = dialog.add_button("View packages", gtk.RESPONSE_NO)
1206             HobAltButton.style_button(button)
1207             button = dialog.add_button("Build packages", gtk.RESPONSE_YES)
1208             HobButton.style_button(button)
1209             dialog.set_default_response(gtk.RESPONSE_YES)
1210             response = dialog.run()
1211             dialog.destroy()
1212             if response == gtk.RESPONSE_YES:
1213                 self.generate_packages_async()
1214             else:
1215                 self.switch_page(self.PACKAGE_SELECTION)
1216         else:
1217             self.switch_page(self.PACKAGE_SELECTION)
1218
1219     def show_recipes(self):
1220         self.switch_page(self.RECIPE_SELECTION)
1221
1222     def show_configuration(self):
1223         self.switch_page(self.BASEIMG_SELECTED)
1224
1225     def stop_build(self):
1226         if self.stopping:
1227             lbl = "<b>Force Stop build?</b>\nYou've already selected Stop once,"
1228             lbl = lbl + " would you like to 'Force Stop' the build?\n\n"
1229             lbl = lbl + "This will stop the build as quickly as possible but may"
1230             lbl = lbl + " well leave your build directory in an  unusable state"
1231             lbl = lbl + " that requires manual steps to fix.\n"
1232             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
1233             button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
1234             HobAltButton.style_button(button)
1235             button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
1236             HobButton.style_button(button)
1237         else:
1238             lbl = "<b>Stop build?</b>\n\nAre you sure you want to stop this"
1239             lbl = lbl + " build?\n\n'Force Stop' will stop the build as quickly as"
1240             lbl = lbl + " possible but may well leave your build directory in an"
1241             lbl = lbl + " unusable state that requires manual steps to fix.\n\n"
1242             lbl = lbl + "'Stop' will stop the build as soon as all in"
1243             lbl = lbl + " progress build tasks are finished. However if a"
1244             lbl = lbl + " lengthy compilation phase is in progress this may take"
1245             lbl = lbl + " some time."
1246             dialog = CrumbsMessageDialog(self, lbl, gtk.STOCK_DIALOG_WARNING)
1247             button = dialog.add_button("Cancel", gtk.RESPONSE_CANCEL)
1248             HobAltButton.style_button(button)
1249             button = dialog.add_button("Stop", gtk.RESPONSE_OK)
1250             HobAltButton.style_button(button)
1251             button = dialog.add_button("Force Stop", gtk.RESPONSE_YES)
1252             HobButton.style_button(button)
1253         response = dialog.run()
1254         dialog.destroy()
1255         if response != gtk.RESPONSE_CANCEL:
1256             self.stopping = True
1257         if response == gtk.RESPONSE_OK:
1258             self.cancel_build_sync()
1259         elif response == gtk.RESPONSE_YES:
1260             self.cancel_build_sync(True)