diff options
author | Michael Wood <michael.g.wood@intel.com> | 2015-09-28 21:45:23 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-09-29 14:11:37 +0100 |
commit | 37948cc5d0e9274a2ca0ec70a5b4788fa26e55e5 (patch) | |
tree | 76359d92d68c0e2fba1984b213b1dff3f976d6ce | |
parent | a3ff4b28baa9f4cc76ec4993f862f2ed7bd20f65 (diff) | |
download | poky-37948cc5d0e9274a2ca0ec70a5b4788fa26e55e5.tar.gz |
bitbake: toaster: Add ToasterTables for Image customisation feature
- Split up the recipes tables into Image recipes and Software Recipes
- Add CustomImageRecipe table
- Add SelectPackagesTable table
- Add NewCustomImagesTable table
(Bitbake rev: 4e5472e9ba6850081baa9d56fabc4ddb1aa24846)
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: brian avery <avery.brian@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | bitbake/lib/toaster/toastergui/tables.py | 222 |
1 files changed, 188 insertions, 34 deletions
diff --git a/bitbake/lib/toaster/toastergui/tables.py b/bitbake/lib/toaster/toastergui/tables.py index 70e4b6d782..1526d59004 100644 --- a/bitbake/lib/toaster/toastergui/tables.py +++ b/bitbake/lib/toaster/toastergui/tables.py | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | from toastergui.widgets import ToasterTable | 22 | from toastergui.widgets import ToasterTable |
23 | from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project | 23 | from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project |
24 | from orm.models import CustomImageRecipe, Package | ||
24 | from django.db.models import Q, Max | 25 | from django.db.models import Q, Max |
25 | from django.conf.urls import url | 26 | from django.conf.urls import url |
26 | from django.core.urlresolvers import reverse | 27 | from django.core.urlresolvers import reverse |
@@ -310,13 +311,20 @@ class LayerMachinesTable(MachinesTable): | |||
310 | 311 | ||
311 | 312 | ||
312 | class RecipesTable(ToasterTable, ProjectFiltersMixin): | 313 | class RecipesTable(ToasterTable, ProjectFiltersMixin): |
313 | """Table of Recipes in Toaster""" | 314 | """Table of All Recipes in Toaster""" |
314 | 315 | ||
315 | def __init__(self, *args, **kwargs): | 316 | def __init__(self, *args, **kwargs): |
316 | super(RecipesTable, self).__init__(*args, **kwargs) | 317 | super(RecipesTable, self).__init__(*args, **kwargs) |
317 | self.empty_state = "Toaster has no recipe information. To generate recipe information you can configure a layer source then run a build." | 318 | self.empty_state = "Toaster has no recipe information. To generate recipe information you can configure a layer source then run a build." |
318 | self.default_orderby = "name" | 319 | self.default_orderby = "name" |
319 | 320 | ||
321 | build_col = { 'title' : "Build", | ||
322 | 'help_text' : "Add or delete recipes to and from your project", | ||
323 | 'hideable' : False, | ||
324 | 'filter_name' : "in_current_project", | ||
325 | 'static_data_name' : "add-del-layers", | ||
326 | 'static_data_template' : '{% include "recipe_btn.html" %}'} | ||
327 | |||
320 | def get_context_data(self, **kwargs): | 328 | def get_context_data(self, **kwargs): |
321 | project = Project.objects.get(pk=kwargs['pid']) | 329 | project = Project.objects.get(pk=kwargs['pid']) |
322 | context = super(RecipesTable, self).get_context_data(**kwargs) | 330 | context = super(RecipesTable, self).get_context_data(**kwargs) |
@@ -327,17 +335,6 @@ class RecipesTable(ToasterTable, ProjectFiltersMixin): | |||
327 | 335 | ||
328 | return context | 336 | return context |
329 | 337 | ||
330 | def setup_filters(self, *args, **kwargs): | ||
331 | project = Project.objects.get(pk=kwargs['pid']) | ||
332 | self.project_layers = project.projectlayer_equivalent_set() | ||
333 | |||
334 | self.add_filter(title="Filter by project recipes", | ||
335 | name="in_current_project", | ||
336 | filter_actions=[ | ||
337 | self.make_filter_action("in_project", "Recipes provided by layers added to this project", self.filter_in_project), | ||
338 | self.make_filter_action("not_in_project", "Recipes provided by layers not added to this project", self.filter_not_in_project) | ||
339 | ]) | ||
340 | |||
341 | 338 | ||
342 | def setup_queryset(self, *args, **kwargs): | 339 | def setup_queryset(self, *args, **kwargs): |
343 | prj = Project.objects.get(pk = kwargs['pid']) | 340 | prj = Project.objects.get(pk = kwargs['pid']) |
@@ -348,12 +345,6 @@ class RecipesTable(ToasterTable, ProjectFiltersMixin): | |||
348 | 345 | ||
349 | def setup_columns(self, *args, **kwargs): | 346 | def setup_columns(self, *args, **kwargs): |
350 | 347 | ||
351 | self.add_column(title="Recipe", | ||
352 | help_text="Information about a single piece of software, including where to download the source, configuration options, how to compile the source files and how to package the compiled output", | ||
353 | hideable=False, | ||
354 | orderable=True, | ||
355 | field_name="name") | ||
356 | |||
357 | self.add_column(title="Recipe Version", | 348 | self.add_column(title="Recipe Version", |
358 | hidden=True, | 349 | hidden=True, |
359 | field_name="version") | 350 | field_name="version") |
@@ -398,18 +389,6 @@ class RecipesTable(ToasterTable, ProjectFiltersMixin): | |||
398 | self.add_column(title="Revision", | 389 | self.add_column(title="Revision", |
399 | field_name="layer_version__get_vcs_reference") | 390 | field_name="layer_version__get_vcs_reference") |
400 | 391 | ||
401 | self.add_column(title="Build", | ||
402 | help_text="Add or delete recipes to and from your project", | ||
403 | hideable=False, | ||
404 | filter_name="in_current_project", | ||
405 | static_data_name="add-del-layers", | ||
406 | static_data_template='{% include "recipe_btn.html" %}') | ||
407 | |||
408 | project = Project.objects.get(pk=kwargs['pid']) | ||
409 | self.add_column(title="Project compatible Layer ID", | ||
410 | displayable = False, | ||
411 | field_name = "projectcompatible_layer", | ||
412 | computation = lambda x: (x.layer_version.get_equivalents_wpriority(project)[0])) | ||
413 | 392 | ||
414 | class LayerRecipesTable(RecipesTable): | 393 | class LayerRecipesTable(RecipesTable): |
415 | """ Smaller version of the Recipes table for use in layer details """ | 394 | """ Smaller version of the Recipes table for use in layer details """ |
@@ -446,10 +425,185 @@ class LayerRecipesTable(RecipesTable): | |||
446 | static_data_name="add-del-layers", | 425 | static_data_name="add-del-layers", |
447 | static_data_template=build_recipe_template) | 426 | static_data_template=build_recipe_template) |
448 | 427 | ||
449 | class ProjectLayersRecipesTable(RecipesTable): | 428 | class CustomImagesTable(ToasterTable): |
450 | """ Table that lists only recipes available for layers added to the project """ | 429 | """ Table to display your custom images """ |
430 | def __init__(self, *args, **kwargs): | ||
431 | super(CustomImagesTable, self).__init__(*args, **kwargs) | ||
432 | self.title = "Custom images" | ||
433 | |||
434 | def get_context_data(self, **kwargs): | ||
435 | context = super(CustomImagesTable, self).get_context_data(**kwargs) | ||
436 | project = Project.objects.get(pk=kwargs['pid']) | ||
437 | context['project'] = project | ||
438 | context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project'])) | ||
439 | return context | ||
440 | |||
441 | def setup_queryset(self, *args, **kwargs): | ||
442 | prj = Project.objects.get(pk = kwargs['pid']) | ||
443 | self.queryset = CustomImageRecipe.objects.filter(project=prj) | ||
444 | self.queryset = self.queryset.order_by('name') | ||
445 | |||
446 | def setup_columns(self, *args, **kwargs): | ||
447 | |||
448 | name_link_template = ''' | ||
449 | <a href="{% url 'customrecipe' extra.pid data.id %}"> | ||
450 | {{data.name}} | ||
451 | </a> | ||
452 | ''' | ||
453 | |||
454 | self.add_column(title="Custom image", | ||
455 | hideable=False, | ||
456 | static_data_name="name", | ||
457 | static_data_template=name_link_template) | ||
458 | |||
459 | self.add_column(title="Recipe file", | ||
460 | static_data_name='recipe_file', | ||
461 | static_data_template='') | ||
462 | |||
463 | approx_packages_template = '<a href="#imagedetails">{{data.packages.all|length}}</a>' | ||
464 | self.add_column(title="Approx packages", | ||
465 | static_data_name='approx_packages', | ||
466 | static_data_template=approx_packages_template) | ||
467 | |||
468 | |||
469 | build_btn_template = '''<button data-recipe-name="{{data.name}}" | ||
470 | class="btn btn-block build-recipe-btn" style="margin-top: 5px;" > | ||
471 | Build</button>''' | ||
472 | |||
473 | self.add_column(title="Build", | ||
474 | hideable=False, | ||
475 | static_data_name='build_custom_img', | ||
476 | static_data_template=build_btn_template) | ||
477 | |||
478 | class ImageRecipesTable(RecipesTable): | ||
479 | """ A subset of the recipes table which displayed just image recipes """ | ||
480 | |||
481 | def __init__(self, *args, **kwargs): | ||
482 | super(ImageRecipesTable, self).__init__(*args, **kwargs) | ||
483 | self.title = "Compatible image recipes" | ||
484 | |||
485 | def setup_queryset(self, *args, **kwargs): | ||
486 | super(ImageRecipesTable, self).setup_queryset(*args, **kwargs) | ||
487 | |||
488 | self.queryset = self.queryset.filter(is_image=True) | ||
489 | |||
490 | |||
491 | def setup_columns(self, *args, **kwargs): | ||
492 | self.add_column(title="Image recipe", | ||
493 | help_text="When you build an image recipe, you get an " | ||
494 | "image: a root file system you can" | ||
495 | "deploy to a machine", | ||
496 | hideable=False, | ||
497 | orderable=True, | ||
498 | field_name="name") | ||
499 | |||
500 | super(ImageRecipesTable, self).setup_columns(*args, **kwargs) | ||
501 | |||
502 | self.add_column(**RecipesTable.build_col) | ||
503 | |||
504 | |||
505 | class NewCustomImagesTable(ImageRecipesTable): | ||
506 | """ Table which displays Images recipes which can be customised """ | ||
507 | def __init__(self, *args, **kwargs): | ||
508 | super(NewCustomImagesTable, self).__init__(*args, **kwargs) | ||
509 | self.title = "Select the image recipe you want to customise" | ||
451 | 510 | ||
452 | def setup_queryset(self, *args, **kwargs): | 511 | def setup_queryset(self, *args, **kwargs): |
453 | super(ProjectLayersRecipesTable, self).setup_queryset(*args, **kwargs) | 512 | super(ImageRecipesTable, self).setup_queryset(*args, **kwargs) |
513 | |||
514 | self.queryset = self.queryset.filter(is_image=True) | ||
515 | |||
516 | def setup_columns(self, *args, **kwargs): | ||
517 | self.add_column(title="Image recipe", | ||
518 | help_text="When you build an image recipe, you get an " | ||
519 | "image: a root file system you can" | ||
520 | "deploy to a machine", | ||
521 | hideable=False, | ||
522 | orderable=True, | ||
523 | field_name="recipe__name") | ||
524 | |||
525 | super(ImageRecipesTable, self).setup_columns(*args, **kwargs) | ||
526 | |||
527 | self.add_column(title="Customise", | ||
528 | hideable=False, | ||
529 | filter_name="in_current_project", | ||
530 | static_data_name="customise-or-add-recipe", | ||
531 | static_data_template='{% include "customise_btn.html" %}') | ||
532 | |||
533 | |||
534 | class SoftwareRecipesTable(RecipesTable): | ||
535 | """ Displays just the software recipes """ | ||
536 | def __init__(self, *args, **kwargs): | ||
537 | super(SoftwareRecipesTable, self).__init__(*args, **kwargs) | ||
538 | self.title = "Compatible software recipes" | ||
539 | |||
540 | def setup_queryset(self, *args, **kwargs): | ||
541 | super(SoftwareRecipesTable, self).setup_queryset(*args, **kwargs) | ||
542 | |||
543 | self.queryset = self.queryset.filter(is_image=False) | ||
544 | |||
545 | |||
546 | def setup_columns(self, *args, **kwargs): | ||
547 | self.add_column(title="Software recipe", | ||
548 | help_text="Information about a single piece of " | ||
549 | "software, including where to download the source, " | ||
550 | "configuration options, how to compile the source " | ||
551 | "files and how to package the compiled output", | ||
552 | hideable=False, | ||
553 | orderable=True, | ||
554 | field_name="name") | ||
555 | |||
556 | super(SoftwareRecipesTable, self).setup_columns(*args, **kwargs) | ||
557 | |||
558 | self.add_column(**RecipesTable.build_col) | ||
559 | |||
560 | |||
561 | class SelectPackagesTable(ToasterTable): | ||
562 | """ Table to display the packages to add and remove from an image """ | ||
563 | |||
564 | def __init__(self, *args, **kwargs): | ||
565 | super(SelectPackagesTable, self).__init__(*args, **kwargs) | ||
566 | self.title = "Add | Remove packages" | ||
567 | |||
568 | def setup_queryset(self, *args, **kwargs): | ||
569 | cust_recipe = CustomImageRecipe.objects.get(pk=kwargs['recipeid']) | ||
454 | prj = Project.objects.get(pk = kwargs['pid']) | 570 | prj = Project.objects.get(pk = kwargs['pid']) |
455 | self.queryset = self.queryset.filter(layer_version__in = prj.projectlayer_equivalent_set()) | 571 | |
572 | current_packages = cust_recipe.packages.all() | ||
573 | |||
574 | # Get all the packages that are in the custom image | ||
575 | # Get all the packages built by builds in the current project | ||
576 | # but not those ones that are already in the custom image | ||
577 | self.queryset = Package.objects.filter( | ||
578 | Q(pk__in=current_packages) | | ||
579 | (Q(build__project=prj) & | ||
580 | ~Q(name__in=current_packages.values_list('name')))) | ||
581 | |||
582 | self.queryset = self.queryset.order_by('name') | ||
583 | |||
584 | self.static_context_extra['recipe_id'] = kwargs['recipeid'] | ||
585 | self.static_context_extra['current_packages'] = \ | ||
586 | cust_recipe.packages.values_list('pk', flat=True) | ||
587 | |||
588 | def setup_columns(self, *args, **kwargs): | ||
589 | self.add_column(title="Package", | ||
590 | hideable=False, | ||
591 | orderable=True, | ||
592 | field_name="name") | ||
593 | |||
594 | self.add_column(title="Package Version", | ||
595 | field_name="version") | ||
596 | |||
597 | self.add_column(title="Approx Size", | ||
598 | orderable=True, | ||
599 | static_data_name="size", | ||
600 | static_data_template="{% load projecttags %} \ | ||
601 | {{data.size|filtered_filesizeformat}}") | ||
602 | self.add_column(title="summary", | ||
603 | field_name="summary") | ||
604 | |||
605 | self.add_column(title="Add | Remove", | ||
606 | help_text="Use the add and remove buttons to modify " | ||
607 | "the package content of you custom image", | ||
608 | static_data_name="add_rm_pkg_btn", | ||
609 | static_data_template='{% include "pkg_add_rm_btn.html" %}') | ||