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