diff options
| author | Michael Wood <michael.g.wood@intel.com> | 2015-11-04 15:17:45 +0000 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-02-10 13:29:17 +0000 |
| commit | d6e7e4ad43471fdaa1b6184bd13c91069478839e (patch) | |
| tree | b20a3016acd99133f29f294059fcea12dfed99f8 /bitbake/lib/toaster | |
| parent | 43f0a05fa4da39be3ed84a49a3fba6951110a8fd (diff) | |
| download | poky-d6e7e4ad43471fdaa1b6184bd13c91069478839e.tar.gz | |
bitbake: toaster: tables Add table for Packages and update SelectPackagesTable
Create a Packages table for use as the image details page.
Change the SelectPackagesTable table to inherit from the Packages table.
Remove the need for a separate view by adding the additional template
context items to the Table's page context.
(Bitbake rev: 336b1d8369d9e86ece78b63cb0e140e653216011)
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>
Diffstat (limited to 'bitbake/lib/toaster')
| -rw-r--r-- | bitbake/lib/toaster/toastergui/tables.py | 149 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html | 14 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/urls.py | 10 | ||||
| -rwxr-xr-x | bitbake/lib/toaster/toastergui/views.py | 9 |
4 files changed, 143 insertions, 39 deletions
diff --git a/bitbake/lib/toaster/toastergui/tables.py b/bitbake/lib/toaster/toastergui/tables.py index 7b335c8870..6c167a9f4d 100644 --- a/bitbake/lib/toaster/toastergui/tables.py +++ b/bitbake/lib/toaster/toastergui/tables.py | |||
| @@ -21,7 +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, Build, LogMessage, Task | 24 | from orm.models import CustomImageRecipe, Package, Target, Build, LogMessage, Task |
| 25 | from orm.models import ProjectTarget | 25 | from orm.models import ProjectTarget |
| 26 | from django.db.models import Q, Max, Count, When, Case, Value, IntegerField | 26 | from django.db.models import Q, Max, Count, When, Case, Value, IntegerField |
| 27 | from django.conf.urls import url | 27 | from django.conf.urls import url |
| @@ -483,8 +483,8 @@ class CustomImagesTable(ToasterTable): | |||
| 483 | def get_context_data(self, **kwargs): | 483 | def get_context_data(self, **kwargs): |
| 484 | context = super(CustomImagesTable, self).get_context_data(**kwargs) | 484 | context = super(CustomImagesTable, self).get_context_data(**kwargs) |
| 485 | project = Project.objects.get(pk=kwargs['pid']) | 485 | project = Project.objects.get(pk=kwargs['pid']) |
| 486 | # TODO put project into the ToasterTable base class | ||
| 486 | context['project'] = project | 487 | context['project'] = project |
| 487 | context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project'])) | ||
| 488 | return context | 488 | return context |
| 489 | 489 | ||
| 490 | def setup_queryset(self, *args, **kwargs): | 490 | def setup_queryset(self, *args, **kwargs): |
| @@ -502,22 +502,31 @@ class CustomImagesTable(ToasterTable): | |||
| 502 | 502 | ||
| 503 | self.add_column(title="Custom image", | 503 | self.add_column(title="Custom image", |
| 504 | hideable=False, | 504 | hideable=False, |
| 505 | orderable=True, | ||
| 506 | field_name="name", | ||
| 505 | static_data_name="name", | 507 | static_data_name="name", |
| 506 | static_data_template=name_link_template) | 508 | static_data_template=name_link_template) |
| 507 | 509 | ||
| 508 | self.add_column(title="Recipe file", | 510 | self.add_column(title="Recipe file", |
| 509 | static_data_name='recipe_file', | 511 | static_data_name='recipe_file', |
| 510 | static_data_template='') | 512 | static_data_template='', |
| 513 | field_name='local_path') | ||
| 514 | |||
| 515 | approx_packages_template = ''' | ||
| 516 | <a href="{% url 'customrecipe' extra.pid data.id %}"> | ||
| 517 | {{data.package_set.all|length}} | ||
| 518 | </a>''' | ||
| 511 | 519 | ||
| 512 | approx_packages_template = '<a href="#imagedetails">{{data.packages.all|length}}</a>' | ||
| 513 | self.add_column(title="Approx packages", | 520 | self.add_column(title="Approx packages", |
| 514 | static_data_name='approx_packages', | 521 | static_data_name='approx_packages', |
| 515 | static_data_template=approx_packages_template) | 522 | static_data_template=approx_packages_template) |
| 516 | 523 | ||
| 517 | 524 | ||
| 518 | build_btn_template = '''<button data-recipe-name="{{data.name}}" | 525 | build_btn_template = ''' |
| 526 | <button data-recipe-name="{{data.name}}" | ||
| 519 | class="btn btn-block build-recipe-btn" style="margin-top: 5px;" > | 527 | class="btn btn-block build-recipe-btn" style="margin-top: 5px;" > |
| 520 | Build</button>''' | 528 | Build |
| 529 | </button>''' | ||
| 521 | 530 | ||
| 522 | self.add_column(title="Build", | 531 | self.add_column(title="Build", |
| 523 | hideable=False, | 532 | hideable=False, |
| @@ -540,12 +549,19 @@ class ImageRecipesTable(RecipesTable): | |||
| 540 | 549 | ||
| 541 | 550 | ||
| 542 | def setup_columns(self, *args, **kwargs): | 551 | def setup_columns(self, *args, **kwargs): |
| 552 | |||
| 553 | name_link_template = ''' | ||
| 554 | <a href="{% url 'recipedetails' extra.pid data.pk %}">{{data.name}}</a> | ||
| 555 | ''' | ||
| 556 | |||
| 543 | self.add_column(title="Image recipe", | 557 | self.add_column(title="Image recipe", |
| 544 | help_text="When you build an image recipe, you get an " | 558 | help_text="When you build an image recipe, you get an " |
| 545 | "image: a root file system you can" | 559 | "image: a root file system you can" |
| 546 | "deploy to a machine", | 560 | "deploy to a machine", |
| 547 | hideable=False, | 561 | hideable=False, |
| 548 | orderable=True, | 562 | orderable=True, |
| 563 | static_data_name="name", | ||
| 564 | static_data_template=name_link_template, | ||
| 549 | field_name="name") | 565 | field_name="name") |
| 550 | 566 | ||
| 551 | super(ImageRecipesTable, self).setup_columns(*args, **kwargs) | 567 | super(ImageRecipesTable, self).setup_columns(*args, **kwargs) |
| @@ -609,8 +625,96 @@ class SoftwareRecipesTable(RecipesTable): | |||
| 609 | 625 | ||
| 610 | self.add_column(**RecipesTable.build_col) | 626 | self.add_column(**RecipesTable.build_col) |
| 611 | 627 | ||
| 628 | class PackagesTable(ToasterTable): | ||
| 629 | """ Table to display the packages in a recipe from it's last successful | ||
| 630 | build""" | ||
| 631 | |||
| 632 | def __init__(self, *args, **kwargs): | ||
| 633 | super(PackagesTable, self).__init__(*args, **kwargs) | ||
| 634 | self.title = "Packages included" | ||
| 635 | self.packages = None | ||
| 636 | self.default_orderby = "name" | ||
| 637 | |||
| 638 | def create_package_list(self, recipe, project_id): | ||
| 639 | """Creates a list of packages for the specified recipe by looking for | ||
| 640 | the last SUCCEEDED build of ther recipe""" | ||
| 641 | |||
| 642 | target = Target.objects.filter(Q(target=recipe.name) & | ||
| 643 | Q(build__project_id=project_id) & | ||
| 644 | Q(build__outcome=Build.SUCCEEDED) | ||
| 645 | ).last() | ||
| 646 | |||
| 647 | if target: | ||
| 648 | return target.build.package_set.all() | ||
| 649 | |||
| 650 | # Target/recipe never successfully built so empty queryset | ||
| 651 | return Package.objects.none() | ||
| 652 | |||
| 653 | def get_context_data(self, **kwargs): | ||
| 654 | """Context for rendering the sidebar and other items on the recipe | ||
| 655 | details page """ | ||
| 656 | context = super(PackagesTable, self).get_context_data(**kwargs) | ||
| 657 | |||
| 658 | recipe = Recipe.objects.get(pk=kwargs['recipe_id']) | ||
| 659 | project = Project.objects.get(pk=kwargs['pid']) | ||
| 660 | |||
| 661 | in_project = (recipe.layer_version.pk in | ||
| 662 | project.get_project_layer_versions(pk=True)) | ||
| 663 | |||
| 664 | packages = self.create_package_list(recipe, project.pk) | ||
| 665 | |||
| 666 | context.update({'project': project, | ||
| 667 | 'recipe' : recipe, | ||
| 668 | 'packages': packages, | ||
| 669 | 'approx_pkg_size' : packages.aggregate(Sum('size')), | ||
| 670 | 'in_project' : in_project, | ||
| 671 | }) | ||
| 672 | |||
| 673 | return context | ||
| 674 | |||
| 675 | def setup_queryset(self, *args, **kwargs): | ||
| 676 | recipe = Recipe.objects.get(pk=kwargs['recipe_id']) | ||
| 677 | |||
| 678 | self.queryset = self.create_package_list(recipe, kwargs['pid']) | ||
| 679 | self.queryset = self.queryset.order_by('name') | ||
| 680 | |||
| 681 | def setup_columns(self, *args, **kwargs): | ||
| 682 | self.add_column(title="Package", | ||
| 683 | hideable=False, | ||
| 684 | orderable=True, | ||
| 685 | field_name="name") | ||
| 686 | |||
| 687 | self.add_column(title="Package Version", | ||
| 688 | field_name="version", | ||
| 689 | hideable=False) | ||
| 690 | |||
| 691 | self.add_column(title="Approx Size", | ||
| 692 | orderable=True, | ||
| 693 | static_data_name="size", | ||
| 694 | static_data_template="{% load projecttags %} \ | ||
| 695 | {{data.size|filtered_filesizeformat}}") | ||
| 696 | |||
| 697 | self.add_column(title="License", | ||
| 698 | field_name="license", | ||
| 699 | orderable=True) | ||
| 700 | |||
| 701 | |||
| 702 | self.add_column(title="Dependencies", | ||
| 703 | static_data_name="dependencies", | ||
| 704 | static_data_template='\ | ||
| 705 | {% include "snippets/pkg_dependencies_popover.html" %}') | ||
| 706 | |||
| 707 | self.add_column(title="Recipe", | ||
| 708 | field_name="recipe__name", | ||
| 709 | orderable=True, | ||
| 710 | hidden=True) | ||
| 711 | |||
| 712 | self.add_column(title="Recipe version", | ||
| 713 | field_name="recipe__version", | ||
| 714 | hidden=True) | ||
| 715 | |||
| 612 | 716 | ||
| 613 | class SelectPackagesTable(ToasterTable): | 717 | class SelectPackagesTable(PackagesTable): |
| 614 | """ Table to display the packages to add and remove from an image """ | 718 | """ Table to display the packages to add and remove from an image """ |
| 615 | 719 | ||
| 616 | def __init__(self, *args, **kwargs): | 720 | def __init__(self, *args, **kwargs): |
| @@ -637,29 +741,25 @@ class SelectPackagesTable(ToasterTable): | |||
| 637 | self.static_context_extra['current_packages'] = \ | 741 | self.static_context_extra['current_packages'] = \ |
| 638 | cust_recipe.packages.values_list('pk', flat=True) | 742 | cust_recipe.packages.values_list('pk', flat=True) |
| 639 | 743 | ||
| 640 | def setup_columns(self, *args, **kwargs): | 744 | def get_context_data(self, **kwargs): |
| 641 | self.add_column(title="Package", | 745 | context = super(SelectPackagesTable, self).get_context_data(**kwargs) |
| 642 | hideable=False, | 746 | custom_recipe = CustomImageRecipe.objects.get(pk=kwargs['recipe_id']) |
| 643 | orderable=True, | ||
| 644 | field_name="name") | ||
| 645 | 747 | ||
| 646 | self.add_column(title="Package Version", | 748 | context['recipe'] = custom_recipe |
| 647 | field_name="version") | 749 | context['approx_pkg_size'] = custom_recipe.package_set.aggregate(Sum('size')) |
| 750 | return context | ||
| 648 | 751 | ||
| 649 | self.add_column(title="Approx Size", | 752 | |
| 650 | orderable=True, | 753 | def setup_columns(self, *args, **kwargs): |
| 651 | static_data_name="size", | 754 | super(SelectPackagesTable, self).setup_columns(*args, **kwargs) |
| 652 | static_data_template="{% load projecttags %} \ | ||
| 653 | {{data.size|filtered_filesizeformat}}") | ||
| 654 | self.add_column(title="summary", | ||
| 655 | field_name="summary") | ||
| 656 | 755 | ||
| 657 | self.add_column(title="Add | Remove", | 756 | self.add_column(title="Add | Remove", |
| 757 | hideable=False, | ||
| 658 | help_text="Use the add and remove buttons to modify " | 758 | help_text="Use the add and remove buttons to modify " |
| 659 | "the package content of you custom image", | 759 | "the package content of you custom image", |
| 660 | static_data_name="add_rm_pkg_btn", | 760 | static_data_name="add_rm_pkg_btn", |
| 661 | static_data_template='{% include "pkg_add_rm_btn.html" %}', | 761 | static_data_template='{% include "pkg_add_rm_btn.html" %}', |
| 662 | static_data_template='{% include "pkg_add_rm_btn.html" %}' | 762 | filter_name="in_current_image" |
| 663 | ) | 763 | ) |
| 664 | 764 | ||
| 665 | def setup_filters(self, *args, **kwargs): | 765 | def setup_filters(self, *args, **kwargs): |
| @@ -681,12 +781,11 @@ class SelectPackagesTable(ToasterTable): | |||
| 681 | self.filter_not_in_image) | 781 | self.filter_not_in_image) |
| 682 | ]) | 782 | ]) |
| 683 | 783 | ||
| 684 | def filter_in_image(self, count_only=False): | 784 | def filter_in_image(self): |
| 685 | return self.queryset.filter( | 785 | return self.queryset.filter( |
| 686 | pk__in=self.static_context_extra['current_packages']) | 786 | pk__in=self.static_context_extra['current_packages']) |
| 687 | 787 | ||
| 688 | 788 | def filter_not_in_image(self): | |
| 689 | def filter_not_in_image(self, count_only=False): | ||
| 690 | return self.queryset.exclude( | 789 | return self.queryset.exclude( |
| 691 | pk__in=self.static_context_extra['current_packages']) | 790 | pk__in=self.static_context_extra['current_packages']) |
| 692 | 791 | ||
diff --git a/bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html b/bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html new file mode 100644 index 0000000000..a08409ac7f --- /dev/null +++ b/bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | {# Popover that displays the dependences and sizes of a package 'data' used in the Packages table #} | ||
| 2 | {% with data.package_dependencies_source.count as dep_count %} | ||
| 3 | {% load projecttags %} | ||
| 4 | {% if dep_count %} | ||
| 5 | <a data-content="<ul class='unstyled'> | ||
| 6 | {% for dep in data.package_dependencies_source.all %} | ||
| 7 | <li>{{dep.depends_on.name}} {% if dep.depends_on.size > 0 %}({{dep.depends_on.size|filtered_filesizeformat}}){% endif %}</li> | ||
| 8 | {% endfor %} | ||
| 9 | </ul>" title="" class="btn" data-original-title=" | ||
| 10 | <strong>{{data.name}}</strong> dependencies - <strong>{{data.package_dependencies_source.get_total_source_deps_size.depends_on__size__sum|filtered_filesizeformat}}</strong>"> | ||
| 11 | {{dep_count}} | ||
| 12 | </a> | ||
| 13 | {% endif %} | ||
| 14 | {% endwith %} | ||
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py index 2164c4c8f7..969a29b228 100644 --- a/bitbake/lib/toaster/toastergui/urls.py +++ b/bitbake/lib/toaster/toastergui/urls.py | |||
| @@ -109,13 +109,10 @@ urlpatterns = patterns('toastergui.views', | |||
| 109 | tables.NewCustomImagesTable.as_view(template_name="newcustomimage.html"), | 109 | tables.NewCustomImagesTable.as_view(template_name="newcustomimage.html"), |
| 110 | name="newcustomimage"), | 110 | name="newcustomimage"), |
| 111 | 111 | ||
| 112 | |||
| 113 | url(r'^project/(?P<pid>\d+)/layers/$', | 112 | url(r'^project/(?P<pid>\d+)/layers/$', |
| 114 | tables.LayersTable.as_view(template_name="generic-toastertable-page.html"), | 113 | tables.LayersTable.as_view(template_name="generic-toastertable-page.html"), |
| 115 | name="projectlayers"), | 114 | name="projectlayers"), |
| 116 | 115 | ||
| 117 | |||
| 118 | |||
| 119 | url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$', | 116 | url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$', |
| 120 | 'layerdetails', name='layerdetails'), | 117 | 'layerdetails', name='layerdetails'), |
| 121 | 118 | ||
| @@ -133,17 +130,20 @@ urlpatterns = patterns('toastergui.views', | |||
| 133 | 130 | ||
| 134 | 131 | ||
| 135 | url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipeid>\d+)/selectpackages/$', | 132 | url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipeid>\d+)/selectpackages/$', |
| 136 | tables.SelectPackagesTable.as_view(template_name="generic-toastertable-page.html"), name="recipeselectpackages"), | 133 | tables.SelectPackagesTable.as_view(), name="recipeselectpackages"), |
| 137 | 134 | ||
| 138 | 135 | ||
| 139 | url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)$', | 136 | url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)$', |
| 140 | 'customrecipe', | 137 | tables.SelectPackagesTable.as_view(template_name="customrecipe.html"), |
| 141 | name="customrecipe"), | 138 | name="customrecipe"), |
| 142 | 139 | ||
| 143 | url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)/download$', | 140 | url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)/download$', |
| 144 | 'customrecipe_download', | 141 | 'customrecipe_download', |
| 145 | name="customrecipedownload"), | 142 | name="customrecipedownload"), |
| 146 | 143 | ||
| 144 | url(r'^project/(?P<pid>\d+)/recipe/(?P<recipe_id>\d+)$', | ||
| 145 | tables.PackagesTable.as_view(template_name="recipedetails.html"), | ||
| 146 | name="recipedetails"), | ||
| 147 | 147 | ||
| 148 | # typeahead api end points | 148 | # typeahead api end points |
| 149 | url(r'^xhr_typeahead/(?P<pid>\d+)/layers$', | 149 | url(r'^xhr_typeahead/(?P<pid>\d+)/layers$', |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index b58f916d8c..f6f1a54597 100755 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -2594,15 +2594,6 @@ if True: | |||
| 2594 | 2594 | ||
| 2595 | return(vars_managed,sorted(vars_fstypes),vars_blacklist) | 2595 | return(vars_managed,sorted(vars_fstypes),vars_blacklist) |
| 2596 | 2596 | ||
| 2597 | def customrecipe(request, pid, recipe_id): | ||
| 2598 | project = Project.objects.get(pk=pid) | ||
| 2599 | context = {'project' : project, | ||
| 2600 | 'projectlayers': [], | ||
| 2601 | 'recipe' : CustomImageRecipe.objects.get(pk=recipe_id) | ||
| 2602 | } | ||
| 2603 | |||
| 2604 | return render(request, "customrecipe.html", context) | ||
| 2605 | |||
| 2606 | @_template_renderer("projectconf.html") | 2597 | @_template_renderer("projectconf.html") |
| 2607 | def projectconf(request, pid): | 2598 | def projectconf(request, pid): |
| 2608 | 2599 | ||
