diff options
Diffstat (limited to 'bitbake/lib/bb/ui/crumbs/builder.py')
-rwxr-xr-x | bitbake/lib/bb/ui/crumbs/builder.py | 873 |
1 files changed, 873 insertions, 0 deletions
diff --git a/bitbake/lib/bb/ui/crumbs/builder.py b/bitbake/lib/bb/ui/crumbs/builder.py new file mode 100755 index 0000000000..007167337f --- /dev/null +++ b/bitbake/lib/bb/ui/crumbs/builder.py | |||
@@ -0,0 +1,873 @@ | |||
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 | from bb.ui.crumbs.template import TemplateMgr | ||
30 | from bb.ui.crumbs.imageconfigurationpage import ImageConfigurationPage | ||
31 | from bb.ui.crumbs.recipeselectionpage import RecipeSelectionPage | ||
32 | from bb.ui.crumbs.packageselectionpage import PackageSelectionPage | ||
33 | from bb.ui.crumbs.builddetailspage import BuildDetailsPage | ||
34 | from bb.ui.crumbs.imagedetailspage import ImageDetailsPage | ||
35 | from bb.ui.crumbs.hobwidget import hwc | ||
36 | from bb.ui.crumbs.hig import CrumbsDialog, BinbDialog, \ | ||
37 | AdvancedSettingDialog, LayerSelectionDialog, \ | ||
38 | DeployImageDialog, ImageSelectionDialog | ||
39 | |||
40 | class Configuration: | ||
41 | '''Represents the data structure of configuration.''' | ||
42 | |||
43 | def __init__(self, params): | ||
44 | # Settings | ||
45 | self.curr_mach = "" | ||
46 | self.curr_distro = params["distro"] | ||
47 | self.dldir = params["dldir"] | ||
48 | self.sstatedir = params["sstatedir"] | ||
49 | self.sstatemirror = params["sstatemirror"] | ||
50 | self.pmake = params["pmake"] | ||
51 | self.bbthread = params["bbthread"] | ||
52 | self.curr_package_format = " ".join(params["pclass"].split("package_")).strip() | ||
53 | self.image_rootfs_size = params["image_rootfs_size"] | ||
54 | self.image_extra_size = params["image_extra_size"] | ||
55 | self.image_overhead_factor = params['image_overhead_factor'] | ||
56 | self.incompat_license = params["incompat_license"] | ||
57 | self.curr_sdk_machine = params["sdk_machine"] | ||
58 | self.extra_setting = {} | ||
59 | self.toolchain_build = False | ||
60 | self.image_fstypes = params["image_fstypes"].split() | ||
61 | # bblayers.conf | ||
62 | self.layers = params["layer"].split() | ||
63 | # image/recipes/packages | ||
64 | self.selected_image = None | ||
65 | self.selected_recipes = [] | ||
66 | self.selected_packages = [] | ||
67 | |||
68 | def load(self, template): | ||
69 | self.curr_mach = template.getVar("MACHINE") | ||
70 | self.curr_package_format = " ".join(template.getVar("PACKAGE_CLASSES").split("package_")).strip() | ||
71 | self.curr_distro = template.getVar("DISTRO") | ||
72 | self.dldir = template.getVar("DL_DIR") | ||
73 | self.sstatedir = template.getVar("SSTATE_DIR") | ||
74 | self.sstatemirror = template.getVar("SSTATE_MIRROR") | ||
75 | self.pmake = int(template.getVar("PARALLEL_MAKE").split()[1]) | ||
76 | self.bbthread = int(template.getVar("BB_NUMBER_THREAD")) | ||
77 | self.image_rootfs_size = int(template.getVar("IMAGE_ROOTFS_SIZE")) | ||
78 | self.image_extra_size = int(template.getVar("IMAGE_EXTRA_SPACE")) | ||
79 | # image_overhead_factor is read-only. | ||
80 | self.incompat_license = template.getVar("INCOMPATIBLE_LICENSE") | ||
81 | self.curr_sdk_machine = template.getVar("SDKMACHINE") | ||
82 | self.extra_setting = eval(template.getVar("EXTRA_SETTING")) | ||
83 | self.toolchain_build = eval(template.getVar("TOOLCHAIN_BUILD")) | ||
84 | self.image_fstypes = template.getVar("IMAGE_FSTYPES").split() | ||
85 | # bblayers.conf | ||
86 | self.layers = template.getVar("BBLAYERS").split() | ||
87 | # image/recipes/packages | ||
88 | self.selected_image = template.getVar("__SELECTED_IMAGE__") | ||
89 | self.selected_recipes = template.getVar("DEPENDS").split() | ||
90 | self.selected_packages = template.getVar("IMAGE_INSTALL").split() | ||
91 | |||
92 | def save(self, template, filename): | ||
93 | # bblayers.conf | ||
94 | template.setVar("BBLAYERS", " ".join(self.layers)) | ||
95 | # local.conf | ||
96 | template.setVar("MACHINE", self.curr_mach) | ||
97 | template.setVar("DISTRO", self.curr_distro) | ||
98 | template.setVar("DL_DIR", self.dldir) | ||
99 | template.setVar("SSTATE_DIR", self.sstatedir) | ||
100 | template.setVar("SSTATE_MIRROR", self.sstatemirror) | ||
101 | template.setVar("PARALLEL_MAKE", "-j %s" % self.pmake) | ||
102 | template.setVar("BB_NUMBER_THREAD", self.bbthread) | ||
103 | template.setVar("PACKAGE_CLASSES", " ".join(["package_" + i for i in self.curr_package_format.split()])) | ||
104 | template.setVar("IMAGE_ROOTFS_SIZE", self.image_rootfs_size) | ||
105 | template.setVar("IMAGE_EXTRA_SPACE", self.image_extra_size) | ||
106 | template.setVar("INCOMPATIBLE_LICENSE", self.incompat_license) | ||
107 | template.setVar("SDKMACHINE", self.curr_sdk_machine) | ||
108 | template.setVar("EXTRA_SETTING", self.extra_setting) | ||
109 | template.setVar("TOOLCHAIN_BUILD", self.toolchain_build) | ||
110 | template.setVar("IMAGE_FSTYPES", " ".join(self.image_fstypes).lstrip(" ")) | ||
111 | # image/recipes/packages | ||
112 | self.selected_image = filename | ||
113 | template.setVar("__SELECTED_IMAGE__", self.selected_image) | ||
114 | template.setVar("DEPENDS", self.selected_recipes) | ||
115 | template.setVar("IMAGE_INSTALL", self.selected_packages) | ||
116 | |||
117 | class Parameters: | ||
118 | '''Represents other variables like available machines, etc.''' | ||
119 | |||
120 | def __init__(self, params): | ||
121 | # Variables | ||
122 | self.all_machines = [] | ||
123 | self.all_package_formats = [] | ||
124 | self.all_distros = [] | ||
125 | self.all_sdk_machines = [] | ||
126 | self.max_threads = params["max_threads"] | ||
127 | self.all_layers = [] | ||
128 | self.core_base = params["core_base"] | ||
129 | self.image_names = [] | ||
130 | self.image_addr = params["image_addr"] | ||
131 | self.image_types = params["image_types"].split() | ||
132 | |||
133 | class Builder(gtk.Window): | ||
134 | |||
135 | (MACHINE_SELECTION, | ||
136 | LAYER_CHANGED, | ||
137 | RCPPKGINFO_POPULATING, | ||
138 | RCPPKGINFO_POPULATED, | ||
139 | RECIPE_SELECTION, | ||
140 | PACKAGE_GENERATING, | ||
141 | PACKAGE_GENERATED, | ||
142 | PACKAGE_SELECTION, | ||
143 | FAST_IMAGE_GENERATING, | ||
144 | IMAGE_GENERATING, | ||
145 | IMAGE_GENERATED, | ||
146 | MY_IMAGE_OPENED, | ||
147 | BACK, | ||
148 | END_NOOP) = range(14) | ||
149 | |||
150 | (IMAGE_CONFIGURATION, | ||
151 | RECIPE_DETAILS, | ||
152 | BUILD_DETAILS, | ||
153 | PACKAGE_DETAILS, | ||
154 | IMAGE_DETAILS, | ||
155 | END_TAB) = range(6) | ||
156 | |||
157 | __step2page__ = { | ||
158 | MACHINE_SELECTION : IMAGE_CONFIGURATION, | ||
159 | LAYER_CHANGED : IMAGE_CONFIGURATION, | ||
160 | RCPPKGINFO_POPULATING : IMAGE_CONFIGURATION, | ||
161 | RCPPKGINFO_POPULATED : IMAGE_CONFIGURATION, | ||
162 | RECIPE_SELECTION : RECIPE_DETAILS, | ||
163 | PACKAGE_GENERATING : BUILD_DETAILS, | ||
164 | PACKAGE_GENERATED : PACKAGE_DETAILS, | ||
165 | PACKAGE_SELECTION : PACKAGE_DETAILS, | ||
166 | FAST_IMAGE_GENERATING : BUILD_DETAILS, | ||
167 | IMAGE_GENERATING : BUILD_DETAILS, | ||
168 | IMAGE_GENERATED : IMAGE_DETAILS, | ||
169 | MY_IMAGE_OPENED : IMAGE_DETAILS, | ||
170 | END_NOOP : None, | ||
171 | } | ||
172 | |||
173 | def __init__(self, hobHandler, recipe_model, package_model): | ||
174 | super(Builder, self).__init__() | ||
175 | |||
176 | # handler | ||
177 | self.handler = hobHandler | ||
178 | |||
179 | self.template = None | ||
180 | |||
181 | # settings | ||
182 | params = self.handler.get_parameters() | ||
183 | self.configuration = Configuration(params) | ||
184 | self.parameters = Parameters(params) | ||
185 | |||
186 | # build step | ||
187 | self.current_step = None | ||
188 | self.previous_step = None | ||
189 | |||
190 | self.stopping = False | ||
191 | self.build_succeeded = True | ||
192 | |||
193 | # recipe model and package model | ||
194 | self.recipe_model = recipe_model | ||
195 | self.package_model = package_model | ||
196 | |||
197 | # create visual elements | ||
198 | self.create_visual_elements() | ||
199 | |||
200 | # connect the signals to functions | ||
201 | #self.connect("configure-event", self.resize_window_cb) | ||
202 | self.connect("delete-event", self.destroy_window_cb) | ||
203 | self.recipe_model.connect ("recipe-selection-changed", self.recipelist_changed_cb) | ||
204 | self.package_model.connect("package-selection-changed", self.packagelist_changed_cb) | ||
205 | self.recipe_model.connect ("recipelist-populated", self.recipelist_populated_cb) | ||
206 | self.package_model.connect("packagelist-populated", self.packagelist_populated_cb) | ||
207 | self.handler.connect("config-updated", self.handler_config_updated_cb) | ||
208 | self.handler.connect("package-formats-updated", self.handler_package_formats_updated_cb) | ||
209 | self.handler.connect("layers-updated", self.handler_layers_updated_cb) | ||
210 | self.handler.connect("parsing-started", self.handler_parsing_started_cb) | ||
211 | self.handler.connect("parsing", self.handler_parsing_cb) | ||
212 | self.handler.connect("parsing-completed", self.handler_parsing_completed_cb) | ||
213 | self.handler.build.connect("build-started", self.handler_build_started_cb) | ||
214 | self.handler.build.connect("build-succeeded", self.handler_build_succeeded_cb) | ||
215 | self.handler.build.connect("build-failed", self.handler_build_failed_cb) | ||
216 | self.handler.build.connect("task-started", self.handler_task_started_cb) | ||
217 | self.handler.connect("generating-data", self.handler_generating_data_cb) | ||
218 | self.handler.connect("data-generated", self.handler_data_generated_cb) | ||
219 | self.handler.connect("command-succeeded", self.handler_command_succeeded_cb) | ||
220 | self.handler.connect("command-failed", self.handler_command_failed_cb) | ||
221 | |||
222 | self.switch_page(self.MACHINE_SELECTION) | ||
223 | |||
224 | def create_visual_elements(self): | ||
225 | self.set_title("HOB -- Image Creator") | ||
226 | self.set_icon_name("applications-development") | ||
227 | self.set_position(gtk.WIN_POS_CENTER_ALWAYS) | ||
228 | self.set_resizable(True) | ||
229 | window_width = self.get_screen().get_width() | ||
230 | window_height = self.get_screen().get_height() | ||
231 | if window_width >= hwc.MAIN_WIN_WIDTH: | ||
232 | window_width = hwc.MAIN_WIN_WIDTH | ||
233 | window_height = hwc.MAIN_WIN_HEIGHT | ||
234 | else: | ||
235 | lbl = "<b>Screen dimension mismatched</b>\nfor better usability and visual effects," | ||
236 | lbl = lbl + " the screen dimension should be 1024x768 or above." | ||
237 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
238 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
239 | dialog.run() | ||
240 | dialog.destroy() | ||
241 | self.set_size_request(window_width, window_height) | ||
242 | |||
243 | self.vbox = gtk.VBox(False, 0) | ||
244 | self.vbox.set_border_width(0) | ||
245 | self.add(self.vbox) | ||
246 | |||
247 | # create pages | ||
248 | self.image_configuration_page = ImageConfigurationPage(self) | ||
249 | self.recipe_details_page = RecipeSelectionPage(self) | ||
250 | self.build_details_page = BuildDetailsPage(self) | ||
251 | self.package_details_page = PackageSelectionPage(self) | ||
252 | self.image_details_page = ImageDetailsPage(self) | ||
253 | |||
254 | self.nb = gtk.Notebook() | ||
255 | self.nb.set_show_tabs(False) | ||
256 | self.nb.insert_page(self.image_configuration_page, None, self.IMAGE_CONFIGURATION) | ||
257 | self.nb.insert_page(self.recipe_details_page, None, self.RECIPE_DETAILS) | ||
258 | self.nb.insert_page(self.build_details_page, None, self.BUILD_DETAILS) | ||
259 | self.nb.insert_page(self.package_details_page, None, self.PACKAGE_DETAILS) | ||
260 | self.nb.insert_page(self.image_details_page, None, self.IMAGE_DETAILS) | ||
261 | self.vbox.pack_start(self.nb, expand=True, fill=True) | ||
262 | |||
263 | self.show_all() | ||
264 | self.nb.set_current_page(0) | ||
265 | |||
266 | def get_split_model(self): | ||
267 | return self.handler.split_model | ||
268 | |||
269 | def load_template(self, path): | ||
270 | self.template = TemplateMgr() | ||
271 | self.template.load(path) | ||
272 | self.configuration.load(self.template) | ||
273 | |||
274 | if self.get_split_model(): | ||
275 | if not set(self.configuration.layers) <= set(self.parameters.all_layers): | ||
276 | return False | ||
277 | else: | ||
278 | for layer in self.configuration.layers: | ||
279 | if not os.path.exists(layer+'/conf/layer.conf'): | ||
280 | return False | ||
281 | |||
282 | self.switch_page(self.LAYER_CHANGED) | ||
283 | |||
284 | self.template.destroy() | ||
285 | self.template = None | ||
286 | |||
287 | def save_template(self, path): | ||
288 | if path.rfind("/") == -1: | ||
289 | filename = "default" | ||
290 | path = "." | ||
291 | else: | ||
292 | filename = path[path.rfind("/") + 1:len(path)] | ||
293 | path = path[0:path.rfind("/")] | ||
294 | |||
295 | self.template = TemplateMgr() | ||
296 | self.template.open(filename, path) | ||
297 | self.configuration.save(self.template, filename) | ||
298 | |||
299 | self.template.save() | ||
300 | self.template.destroy() | ||
301 | self.template = None | ||
302 | |||
303 | def switch_page(self, next_step): | ||
304 | # Main Workflow (Business Logic) | ||
305 | self.nb.set_current_page(self.__step2page__[next_step]) | ||
306 | |||
307 | if next_step == self.MACHINE_SELECTION: # init step | ||
308 | self.image_configuration_page.show_machine() | ||
309 | |||
310 | elif next_step == self.LAYER_CHANGED: | ||
311 | # after layers is changd by users | ||
312 | self.image_configuration_page.show_machine() | ||
313 | self.handler.refresh_layers(self.configuration.layers) | ||
314 | |||
315 | elif next_step == self.RCPPKGINFO_POPULATING: | ||
316 | # MACHINE CHANGED action or SETTINGS CHANGED | ||
317 | # show the progress bar | ||
318 | self.image_configuration_page.show_info_populating() | ||
319 | self.generate_recipes() | ||
320 | |||
321 | elif next_step == self.RCPPKGINFO_POPULATED: | ||
322 | self.image_configuration_page.show_info_populated() | ||
323 | |||
324 | elif next_step == self.RECIPE_SELECTION: | ||
325 | pass | ||
326 | |||
327 | elif next_step == self.PACKAGE_SELECTION: | ||
328 | pass | ||
329 | |||
330 | elif next_step == self.PACKAGE_GENERATING or next_step == self.FAST_IMAGE_GENERATING: | ||
331 | # both PACKAGE_GENEATING and FAST_IMAGE_GENERATING share the same page | ||
332 | self.build_details_page.show_page(next_step) | ||
333 | self.generate_packages() | ||
334 | |||
335 | elif next_step == self.PACKAGE_GENERATED: | ||
336 | pass | ||
337 | |||
338 | elif next_step == self.IMAGE_GENERATING: | ||
339 | # after packages are generated, selected_packages need to | ||
340 | # be updated in package_model per selected_image in recipe_model | ||
341 | self.build_details_page.show_page(next_step) | ||
342 | self.generate_image() | ||
343 | |||
344 | elif next_step == self.IMAGE_GENERATED: | ||
345 | self.image_details_page.show_page(next_step) | ||
346 | |||
347 | elif next_step == self.MY_IMAGE_OPENED: | ||
348 | self.image_details_page.show_page(next_step) | ||
349 | |||
350 | self.previous_step = self.current_step | ||
351 | self.current_step = next_step | ||
352 | |||
353 | def set_user_config(self): | ||
354 | self.handler.init_cooker() | ||
355 | # set bb layers | ||
356 | self.handler.set_bblayers(self.configuration.layers) | ||
357 | # set local configuration | ||
358 | self.handler.set_machine(self.configuration.curr_mach) | ||
359 | self.handler.set_package_format(self.configuration.curr_package_format) | ||
360 | self.handler.set_distro(self.configuration.curr_distro) | ||
361 | self.handler.set_dl_dir(self.configuration.dldir) | ||
362 | self.handler.set_sstate_dir(self.configuration.sstatedir) | ||
363 | self.handler.set_sstate_mirror(self.configuration.sstatemirror) | ||
364 | self.handler.set_pmake(self.configuration.pmake) | ||
365 | self.handler.set_bbthreads(self.configuration.bbthread) | ||
366 | self.handler.set_rootfs_size(self.configuration.image_rootfs_size) | ||
367 | self.handler.set_extra_size(self.configuration.image_extra_size) | ||
368 | self.handler.set_incompatible_license(self.configuration.incompat_license) | ||
369 | self.handler.set_sdk_machine(self.configuration.curr_sdk_machine) | ||
370 | self.handler.set_image_fstypes(self.configuration.image_fstypes) | ||
371 | self.handler.set_extra_config(self.configuration.extra_setting) | ||
372 | self.handler.set_extra_inherit("packageinfo") | ||
373 | |||
374 | def reset_recipe_model(self): | ||
375 | self.recipe_model.reset() | ||
376 | |||
377 | def reset_package_model(self): | ||
378 | self.package_model.reset() | ||
379 | |||
380 | def update_recipe_model(self, selected_image, selected_recipes): | ||
381 | self.recipe_model.set_selected_image(selected_image) | ||
382 | self.recipe_model.set_selected_recipes(selected_recipes) | ||
383 | |||
384 | def update_package_model(self, selected_packages): | ||
385 | left = self.package_model.set_selected_packages(selected_packages) | ||
386 | self.configuration.selected_packages += left | ||
387 | |||
388 | def generate_packages(self): | ||
389 | # Build packages | ||
390 | _, all_recipes = self.recipe_model.get_selected_recipes() | ||
391 | self.set_user_config() | ||
392 | self.handler.reset_build() | ||
393 | self.handler.generate_packages(all_recipes) | ||
394 | |||
395 | def generate_recipes(self): | ||
396 | # Parse recipes | ||
397 | self.set_user_config() | ||
398 | self.handler.generate_recipes() | ||
399 | |||
400 | def generate_image(self): | ||
401 | # Build image | ||
402 | self.set_user_config() | ||
403 | all_packages = self.package_model.get_selected_packages() | ||
404 | self.handler.reset_build() | ||
405 | self.handler.generate_image(all_packages, self.configuration.toolchain_build) | ||
406 | |||
407 | |||
408 | # Callback Functions | ||
409 | def handler_config_updated_cb(self, handler, which, values): | ||
410 | if which == "distro": | ||
411 | self.parameters.all_distros = values | ||
412 | elif which == "machine": | ||
413 | self.parameters.all_machines = values | ||
414 | self.image_configuration_page.update_machine_combo() | ||
415 | elif which == "machine-sdk": | ||
416 | self.parameters.all_sdk_machines = values | ||
417 | |||
418 | def handler_package_formats_updated_cb(self, handler, formats): | ||
419 | self.parameters.all_package_formats = formats | ||
420 | |||
421 | def handler_layers_updated_cb(self, handler, layers): | ||
422 | self.parameters.all_layers = layers | ||
423 | |||
424 | def handler_command_succeeded_cb(self, handler, initcmd): | ||
425 | if initcmd == self.handler.LAYERS_REFRESH: | ||
426 | self.image_configuration_page.switch_machine_combo() | ||
427 | elif initcmd in [self.handler.GENERATE_RECIPES, | ||
428 | self.handler.GENERATE_PACKAGES, | ||
429 | self.handler.GENERATE_IMAGE]: | ||
430 | self.handler.request_package_info_async() | ||
431 | elif initcmd == self.handler.POPULATE_PACKAGEINFO: | ||
432 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
433 | self.switch_page(self.IMAGE_GENERATING) | ||
434 | elif self.current_step == self.RCPPKGINFO_POPULATING: | ||
435 | self.switch_page(self.RCPPKGINFO_POPULATED) | ||
436 | elif self.current_step == self.PACKAGE_GENERATING: | ||
437 | self.switch_page(self.PACKAGE_GENERATED) | ||
438 | elif self.current_step == self.IMAGE_GENERATING: | ||
439 | self.switch_page(self.IMAGE_GENERATED) | ||
440 | |||
441 | def handler_command_failed_cb(self, handler, msg): | ||
442 | lbl = "<b>Error</b>\n" | ||
443 | lbl = lbl + "%s\n\n" % msg | ||
444 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_WARNING) | ||
445 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
446 | response = dialog.run() | ||
447 | dialog.destroy() | ||
448 | self.handler.clear_busy() | ||
449 | self.configuration.curr_mach = None | ||
450 | self.image_configuration_page.switch_machine_combo() | ||
451 | self.switch_page(self.MACHINE_SELECTION) | ||
452 | |||
453 | def window_sensitive(self, sensitive): | ||
454 | self.set_sensitive(sensitive) | ||
455 | if sensitive: | ||
456 | self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) | ||
457 | else: | ||
458 | self.get_root_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH)) | ||
459 | |||
460 | |||
461 | def handler_generating_data_cb(self, handler): | ||
462 | self.window_sensitive(False) | ||
463 | |||
464 | def handler_data_generated_cb(self, handler): | ||
465 | self.window_sensitive(True) | ||
466 | |||
467 | def recipelist_populated_cb(self, recipe_model): | ||
468 | selected_image = self.configuration.selected_image | ||
469 | selected_recipes = self.configuration.selected_recipes[:] | ||
470 | selected_packages = self.configuration.selected_packages[:] | ||
471 | |||
472 | self.recipe_model.image_list_append(selected_image, | ||
473 | " ".join(selected_recipes), | ||
474 | " ".join(selected_packages)) | ||
475 | |||
476 | self.image_configuration_page.update_image_combo(self.recipe_model, selected_image) | ||
477 | |||
478 | self.update_recipe_model(selected_image, selected_recipes) | ||
479 | |||
480 | def packagelist_populated_cb(self, package_model): | ||
481 | selected_packages = self.configuration.selected_packages[:] | ||
482 | self.update_package_model(selected_packages) | ||
483 | |||
484 | def recipelist_changed_cb(self, recipe_model): | ||
485 | self.recipe_details_page.refresh_selection() | ||
486 | |||
487 | def packagelist_changed_cb(self, package_model): | ||
488 | self.package_details_page.refresh_selection() | ||
489 | |||
490 | def handler_parsing_started_cb(self, handler, message): | ||
491 | if self.current_step != self.RCPPKGINFO_POPULATING: | ||
492 | return | ||
493 | |||
494 | fraction = 0 | ||
495 | if message["eventname"] == "TreeDataPreparationStarted": | ||
496 | fraction = 0.6 + fraction | ||
497 | self.image_configuration_page.update_progress_bar(message["title"], fraction) | ||
498 | |||
499 | def handler_parsing_cb(self, handler, message): | ||
500 | if self.current_step != self.RCPPKGINFO_POPULATING: | ||
501 | return | ||
502 | |||
503 | fraction = message["current"] * 1.0/message["total"] | ||
504 | if message["eventname"] == "TreeDataPreparationProgress": | ||
505 | fraction = 0.6 + 0.4 * fraction | ||
506 | else: | ||
507 | fraction = 0.6 * fraction | ||
508 | self.image_configuration_page.update_progress_bar(message["title"], fraction) | ||
509 | |||
510 | def handler_parsing_completed_cb(self, handler, message): | ||
511 | if self.current_step != self.RCPPKGINFO_POPULATING: | ||
512 | return | ||
513 | |||
514 | if message["eventname"] == "TreeDataPreparationCompleted": | ||
515 | fraction = 1.0 | ||
516 | else: | ||
517 | fraction = 0.6 | ||
518 | self.image_configuration_page.update_progress_bar(message["title"], fraction) | ||
519 | |||
520 | def handler_build_started_cb(self, running_build): | ||
521 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
522 | fraction = 0 | ||
523 | elif self.current_step == self.IMAGE_GENERATING: | ||
524 | if self.previous_step == self.FAST_IMAGE_GENERATING: | ||
525 | fraction = 0.9 | ||
526 | else: | ||
527 | fraction = 0 | ||
528 | elif self.current_step == self.PACKAGE_GENERATING: | ||
529 | fraction = 0 | ||
530 | self.build_details_page.update_progress_bar("Build Started: ", fraction) | ||
531 | |||
532 | def handler_build_succeeded_cb(self, running_build): | ||
533 | self.build_succeeded = True | ||
534 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
535 | fraction = 0.9 | ||
536 | elif self.current_step == self.IMAGE_GENERATING: | ||
537 | fraction = 1.0 | ||
538 | self.parameters.image_names = [] | ||
539 | linkname = 'hob-image-' + self.configuration.curr_mach | ||
540 | for image_type in self.parameters.image_types: | ||
541 | linkpath = self.parameters.image_addr + '/' + linkname + '.' + image_type | ||
542 | if os.path.exists(linkpath): | ||
543 | self.parameters.image_names.append(os.readlink(linkpath)) | ||
544 | elif self.current_step == self.PACKAGE_GENERATING: | ||
545 | fraction = 1.0 | ||
546 | self.build_details_page.update_progress_bar("Build Completed: ", fraction) | ||
547 | |||
548 | def handler_build_failed_cb(self, running_build): | ||
549 | self.build_succeeded = False | ||
550 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
551 | fraction = 0.9 | ||
552 | elif self.current_step == self.IMAGE_GENERATING: | ||
553 | fraction = 1.0 | ||
554 | elif self.current_step == self.PACKAGE_GENERATING: | ||
555 | fraction = 1.0 | ||
556 | self.build_details_page.update_progress_bar("Build Failed: ", fraction, False) | ||
557 | self.build_details_page.show_back_button() | ||
558 | self.build_details_page.hide_stop_button() | ||
559 | self.handler.build_failed_async() | ||
560 | self.stopping = False | ||
561 | |||
562 | def handler_task_started_cb(self, running_build, message): | ||
563 | fraction = message["current"] * 1.0/message["total"] | ||
564 | title = "Build packages" | ||
565 | if self.current_step == self.FAST_IMAGE_GENERATING: | ||
566 | if message["eventname"] == "sceneQueueTaskStarted": | ||
567 | fraction = 0.27 * fraction | ||
568 | elif message["eventname"] == "runQueueTaskStarted": | ||
569 | fraction = 0.27 + 0.63 * fraction | ||
570 | elif self.current_step == self.IMAGE_GENERATING: | ||
571 | title = "Build image" | ||
572 | if self.previous_step == self.FAST_IMAGE_GENERATING: | ||
573 | if message["eventname"] == "sceneQueueTaskStarted": | ||
574 | fraction = 0.27 + 0.63 + 0.03 * fraction | ||
575 | elif message["eventname"] == "runQueueTaskStarted": | ||
576 | fraction = 0.27 + 0.63 + 0.03 + 0.07 * fraction | ||
577 | else: | ||
578 | if message["eventname"] == "sceneQueueTaskStarted": | ||
579 | fraction = 0.2 * fraction | ||
580 | elif message["eventname"] == "runQueueTaskStarted": | ||
581 | fraction = 0.2 + 0.8 * fraction | ||
582 | elif self.current_step == self.PACKAGE_GENERATING: | ||
583 | if message["eventname"] == "sceneQueueTaskStarted": | ||
584 | fraction = 0.2 * fraction | ||
585 | elif message["eventname"] == "runQueueTaskStarted": | ||
586 | fraction = 0.2 + 0.8 * fraction | ||
587 | self.build_details_page.update_progress_bar(title + ": ", fraction) | ||
588 | |||
589 | def destroy_window_cb(self, widget, event): | ||
590 | lbl = "<b>Do you really want to exit the Hob image creator?</b>" | ||
591 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
592 | dialog.add_button(gtk.STOCK_YES, gtk.RESPONSE_YES) | ||
593 | dialog.add_button(gtk.STOCK_NO, gtk.RESPONSE_NO) | ||
594 | dialog.set_default_response(gtk.RESPONSE_NO) | ||
595 | response = dialog.run() | ||
596 | dialog.destroy() | ||
597 | if response == gtk.RESPONSE_YES: | ||
598 | gtk.main_quit() | ||
599 | return False | ||
600 | else: | ||
601 | return True | ||
602 | |||
603 | def build_packages(self): | ||
604 | _, all_recipes = self.recipe_model.get_selected_recipes() | ||
605 | if not all_recipes: | ||
606 | lbl = "<b>No selections made</b>\nYou have not made any selections" | ||
607 | lbl = lbl + " so there isn't anything to bake at this time." | ||
608 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
609 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
610 | dialog.run() | ||
611 | dialog.destroy() | ||
612 | return | ||
613 | self.switch_page(self.PACKAGE_GENERATING) | ||
614 | |||
615 | def build_image(self): | ||
616 | selected_packages = self.package_model.get_selected_packages() | ||
617 | if not selected_packages: | ||
618 | lbl = "<b>No selections made</b>\nYou have not made any selections" | ||
619 | lbl = lbl + " so there isn't anything to bake at this time." | ||
620 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
621 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
622 | dialog.run() | ||
623 | dialog.destroy() | ||
624 | return | ||
625 | self.switch_page(self.IMAGE_GENERATING) | ||
626 | |||
627 | def just_bake(self): | ||
628 | selected_image = self.recipe_model.get_selected_image() | ||
629 | selected_packages = self.package_model.get_selected_packages() or [] | ||
630 | |||
631 | # If no base image and no selected packages don't build anything | ||
632 | if not (selected_packages or selected_image != self.recipe_model.__dummy_image__): | ||
633 | lbl = "<b>No selections made</b>\nYou have not made any selections" | ||
634 | lbl = lbl + " so there isn't anything to bake at this time." | ||
635 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
636 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
637 | dialog.run() | ||
638 | dialog.destroy() | ||
639 | return | ||
640 | |||
641 | self.switch_page(self.FAST_IMAGE_GENERATING) | ||
642 | |||
643 | def show_binb_dialog(self, binb): | ||
644 | binb_dialog = BinbDialog("Brought in by:", binb, self) | ||
645 | binb_dialog.run() | ||
646 | binb_dialog.destroy() | ||
647 | |||
648 | def show_layer_selection_dialog(self): | ||
649 | dialog = LayerSelectionDialog(title = "Layer Selection", | ||
650 | layers = copy.deepcopy(self.configuration.layers), | ||
651 | all_layers = self.parameters.all_layers, | ||
652 | split_model = self.get_split_model(), | ||
653 | parent = self, | ||
654 | flags = gtk.DIALOG_MODAL | ||
655 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
656 | | gtk.DIALOG_NO_SEPARATOR, | ||
657 | buttons = (gtk.STOCK_OK, gtk.RESPONSE_YES, | ||
658 | gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) | ||
659 | response = dialog.run() | ||
660 | if response == gtk.RESPONSE_YES: | ||
661 | self.configuration.layers = dialog.layers | ||
662 | # DO refresh layers | ||
663 | if dialog.layers_changed: | ||
664 | self.switch_page(self.LAYER_CHANGED) | ||
665 | dialog.destroy() | ||
666 | |||
667 | def show_load_template_dialog(self): | ||
668 | dialog = gtk.FileChooserDialog("Load Template Files", self, | ||
669 | gtk.FILE_CHOOSER_ACTION_SAVE, | ||
670 | (gtk.STOCK_OPEN, gtk.RESPONSE_YES, | ||
671 | gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) | ||
672 | filter = gtk.FileFilter() | ||
673 | filter.set_name("HOB Files") | ||
674 | filter.add_pattern("*.hob") | ||
675 | dialog.add_filter(filter) | ||
676 | |||
677 | response = dialog.run() | ||
678 | if response == gtk.RESPONSE_YES: | ||
679 | path = dialog.get_filename() | ||
680 | self.load_template(path) | ||
681 | dialog.destroy() | ||
682 | |||
683 | def show_save_template_dialog(self): | ||
684 | dialog = gtk.FileChooserDialog("Save Template Files", self, | ||
685 | gtk.FILE_CHOOSER_ACTION_SAVE, | ||
686 | (gtk.STOCK_SAVE, gtk.RESPONSE_YES, | ||
687 | gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) | ||
688 | dialog.set_current_name("hob") | ||
689 | response = dialog.run() | ||
690 | if response == gtk.RESPONSE_YES: | ||
691 | path = dialog.get_filename() | ||
692 | self.save_template(path) | ||
693 | dialog.destroy() | ||
694 | |||
695 | def show_load_my_images_dialog(self): | ||
696 | dialog = ImageSelectionDialog(self.parameters.image_addr, self.parameters.image_types, | ||
697 | "Open My Images", self, | ||
698 | gtk.FILE_CHOOSER_ACTION_SAVE, | ||
699 | (gtk.STOCK_OPEN, gtk.RESPONSE_YES, | ||
700 | gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) | ||
701 | |||
702 | response = dialog.run() | ||
703 | if response == gtk.RESPONSE_YES: | ||
704 | if not dialog.image_names: | ||
705 | lbl = "<b>No selections made</b>\nYou have not made any selections" | ||
706 | crumbs_dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
707 | crumbs_dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
708 | crumbs_dialog.run() | ||
709 | crumbs_dialog.destroy() | ||
710 | dialog.destroy() | ||
711 | return | ||
712 | |||
713 | self.parameters.image_addr = dialog.image_folder | ||
714 | self.parameters.image_names = dialog.image_names[:] | ||
715 | self.switch_page(self.MY_IMAGE_OPENED) | ||
716 | |||
717 | dialog.destroy() | ||
718 | |||
719 | def show_adv_settings_dialog(self): | ||
720 | dialog = AdvancedSettingDialog(title = "Settings", | ||
721 | configuration = copy.deepcopy(self.configuration), | ||
722 | all_image_types = self.parameters.image_types, | ||
723 | all_package_formats = self.parameters.all_package_formats, | ||
724 | all_distros = self.parameters.all_distros, | ||
725 | all_sdk_machines = self.parameters.all_sdk_machines, | ||
726 | max_threads = self.parameters.max_threads, | ||
727 | split_model = self.get_split_model(), | ||
728 | parent = self, | ||
729 | flags = gtk.DIALOG_MODAL | ||
730 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
731 | | gtk.DIALOG_NO_SEPARATOR, | ||
732 | buttons = ("Save", gtk.RESPONSE_YES, | ||
733 | gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) | ||
734 | response = dialog.run() | ||
735 | if response == gtk.RESPONSE_YES: | ||
736 | self.configuration = dialog.configuration | ||
737 | # DO reparse recipes | ||
738 | if dialog.settings_changed: | ||
739 | if self.configuration.curr_mach == "": | ||
740 | self.switch_page(self.MACHINE_SELECTION) | ||
741 | else: | ||
742 | self.switch_page(self.RCPPKGINFO_POPULATING) | ||
743 | dialog.destroy() | ||
744 | |||
745 | def deploy_image(self, image_name): | ||
746 | if not image_name: | ||
747 | lbl = "<b>Please select an image to deploy.</b>" | ||
748 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
749 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
750 | dialog.run() | ||
751 | dialog.destroy() | ||
752 | return | ||
753 | |||
754 | image_path = os.path.join(self.parameters.image_addr, image_name) | ||
755 | dialog = DeployImageDialog(title = "Usb Image Maker", | ||
756 | image_path = image_path, | ||
757 | parent = self, | ||
758 | flags = gtk.DIALOG_MODAL | ||
759 | | gtk.DIALOG_DESTROY_WITH_PARENT | ||
760 | | gtk.DIALOG_NO_SEPARATOR, | ||
761 | buttons = ("Close", gtk.RESPONSE_NO, | ||
762 | "Make usb image", gtk.RESPONSE_YES)) | ||
763 | response = dialog.run() | ||
764 | dialog.destroy() | ||
765 | |||
766 | def runqemu_image(self, image_name): | ||
767 | if not image_name: | ||
768 | lbl = "<b>Please select an image to launch in QEMU.</b>" | ||
769 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
770 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
771 | dialog.run() | ||
772 | dialog.destroy() | ||
773 | return | ||
774 | |||
775 | dialog = gtk.FileChooserDialog("Load Kernel Files", self, | ||
776 | gtk.FILE_CHOOSER_ACTION_SAVE, | ||
777 | (gtk.STOCK_OPEN, gtk.RESPONSE_YES, | ||
778 | gtk.STOCK_CANCEL, gtk.RESPONSE_NO)) | ||
779 | filter = gtk.FileFilter() | ||
780 | filter.set_name("Kernel Files") | ||
781 | filter.add_pattern("*.bin") | ||
782 | dialog.add_filter(filter) | ||
783 | |||
784 | dialog.set_current_folder(self.parameters.image_addr) | ||
785 | |||
786 | response = dialog.run() | ||
787 | if response == gtk.RESPONSE_YES: | ||
788 | kernel_path = dialog.get_filename() | ||
789 | image_path = os.path.join(self.parameters.image_addr, image_name) | ||
790 | dialog.destroy() | ||
791 | |||
792 | if response == gtk.RESPONSE_YES: | ||
793 | source_env_path = os.path.join(self.parameters.core_base, "oe-init-build-env") | ||
794 | tmp_path = os.path.join(os.getcwd(), "tmp") | ||
795 | if os.path.exists(image_path) and os.path.exists(kernel_path) \ | ||
796 | and os.path.exists(source_env_path) and os.path.exists(tmp_path): | ||
797 | cmdline = "/usr/bin/xterm -e " | ||
798 | cmdline += "\" export OE_TMPDIR=" + tmp_path + "; " | ||
799 | cmdline += "source " + source_env_path + " " + os.getcwd() + "; " | ||
800 | cmdline += "runqemu " + kernel_path + " " + image_path + "; bash\"" | ||
801 | subprocess.Popen(shlex.split(cmdline)) | ||
802 | else: | ||
803 | lbl = "<b>Path error</b>\nOne of your paths is wrong," | ||
804 | lbl = lbl + " please make sure the following paths exist:\n" | ||
805 | lbl = lbl + "image path:" + image_path + "\n" | ||
806 | lbl = lbl + "kernel path:" + kernel_path + "\n" | ||
807 | lbl = lbl + "source environment path:" + source_env_path + "\n" | ||
808 | lbl = lbl + "tmp path: " + tmp_path + "." | ||
809 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
810 | dialog.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) | ||
811 | dialog.run() | ||
812 | dialog.destroy() | ||
813 | |||
814 | def show_packages(self, ask=True): | ||
815 | _, selected_recipes = self.recipe_model.get_selected_recipes() | ||
816 | if selected_recipes and ask: | ||
817 | lbl = "<b>Package list may be incomplete!</b>\nDo you want to build selected recipes" | ||
818 | lbl = lbl + " to get a full list (Yes) or just view the existing packages (No)?" | ||
819 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_INFO) | ||
820 | dialog.add_button(gtk.STOCK_YES, gtk.RESPONSE_YES) | ||
821 | dialog.add_button(gtk.STOCK_NO, gtk.RESPONSE_NO) | ||
822 | dialog.set_default_response(gtk.RESPONSE_YES) | ||
823 | response = dialog.run() | ||
824 | dialog.destroy() | ||
825 | if response == gtk.RESPONSE_YES: | ||
826 | self.switch_page(self.PACKAGE_GENERATING) | ||
827 | else: | ||
828 | self.switch_page(self.PACKAGE_SELECTION) | ||
829 | else: | ||
830 | self.switch_page(self.PACKAGE_SELECTION) | ||
831 | |||
832 | def show_recipes(self): | ||
833 | self.switch_page(self.RECIPE_SELECTION) | ||
834 | |||
835 | def initiate_new_build(self): | ||
836 | self.configuration.curr_mach = "" | ||
837 | self.image_configuration_page.switch_machine_combo() | ||
838 | self.switch_page(self.MACHINE_SELECTION) | ||
839 | |||
840 | def show_configuration(self): | ||
841 | self.switch_page(self.RCPPKGINFO_POPULATED) | ||
842 | |||
843 | def stop_build(self): | ||
844 | if self.stopping: | ||
845 | lbl = "<b>Force Stop build?</b>\nYou've already selected Stop once," | ||
846 | lbl = lbl + " would you like to 'Force Stop' the build?\n\n" | ||
847 | lbl = lbl + "This will stop the build as quickly as possible but may" | ||
848 | lbl = lbl + " well leave your build directory in an unusable state" | ||
849 | lbl = lbl + " that requires manual steps to fix.\n" | ||
850 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_WARNING) | ||
851 | dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) | ||
852 | dialog.add_button("Force Stop", gtk.RESPONSE_YES) | ||
853 | else: | ||
854 | lbl = "<b>Stop build?</b>\n\nAre you sure you want to stop this" | ||
855 | lbl = lbl + " build?\n\n'Force Stop' will stop the build as quickly as" | ||
856 | lbl = lbl + " possible but may well leave your build directory in an" | ||
857 | lbl = lbl + " unusable state that requires manual steps to fix.\n\n" | ||
858 | lbl = lbl + "'Stop' will stop the build as soon as all in" | ||
859 | lbl = lbl + " progress build tasks are finished. However if a" | ||
860 | lbl = lbl + " lengthy compilation phase is in progress this may take" | ||
861 | lbl = lbl + " some time." | ||
862 | dialog = CrumbsDialog(self, lbl, gtk.STOCK_DIALOG_WARNING) | ||
863 | dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) | ||
864 | dialog.add_button("Stop", gtk.RESPONSE_OK) | ||
865 | dialog.add_button("Force Stop", gtk.RESPONSE_YES) | ||
866 | response = dialog.run() | ||
867 | dialog.destroy() | ||
868 | if response != gtk.RESPONSE_CANCEL: | ||
869 | self.stopping = True | ||
870 | if response == gtk.RESPONSE_OK: | ||
871 | self.handler.cancel_build() | ||
872 | elif response == gtk.RESPONSE_YES: | ||
873 | self.handler.cancel_build(True) | ||