summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/lib/toaster/toastergui/tables.py149
-rw-r--r--bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html14
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py10
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py9
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
22from toastergui.widgets import ToasterTable 22from toastergui.widgets import ToasterTable
23from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project 23from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project
24from orm.models import CustomImageRecipe, Package, Build, LogMessage, Task 24from orm.models import CustomImageRecipe, Package, Target, Build, LogMessage, Task
25from orm.models import ProjectTarget 25from orm.models import ProjectTarget
26from django.db.models import Q, Max, Count, When, Case, Value, IntegerField 26from django.db.models import Q, Max, Count, When, Case, Value, IntegerField
27from django.conf.urls import url 27from 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
628class 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
613class SelectPackagesTable(ToasterTable): 717class 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