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>
This commit is contained in:
Michael Wood 2015-11-04 15:17:45 +00:00 committed by Richard Purdie
parent 43f0a05fa4
commit d6e7e4ad43
4 changed files with 144 additions and 40 deletions

View File

@ -21,7 +21,7 @@
from toastergui.widgets import ToasterTable from toastergui.widgets import ToasterTable
from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project
from orm.models import CustomImageRecipe, Package, Build, LogMessage, Task from orm.models import CustomImageRecipe, Package, Target, Build, LogMessage, Task
from orm.models import ProjectTarget from orm.models import ProjectTarget
from django.db.models import Q, Max, Count, When, Case, Value, IntegerField from django.db.models import Q, Max, Count, When, Case, Value, IntegerField
from django.conf.urls import url from django.conf.urls import url
@ -483,8 +483,8 @@ class CustomImagesTable(ToasterTable):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(CustomImagesTable, self).get_context_data(**kwargs) context = super(CustomImagesTable, self).get_context_data(**kwargs)
project = Project.objects.get(pk=kwargs['pid']) project = Project.objects.get(pk=kwargs['pid'])
# TODO put project into the ToasterTable base class
context['project'] = project context['project'] = project
context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project']))
return context return context
def setup_queryset(self, *args, **kwargs): def setup_queryset(self, *args, **kwargs):
@ -502,22 +502,31 @@ class CustomImagesTable(ToasterTable):
self.add_column(title="Custom image", self.add_column(title="Custom image",
hideable=False, hideable=False,
orderable=True,
field_name="name",
static_data_name="name", static_data_name="name",
static_data_template=name_link_template) static_data_template=name_link_template)
self.add_column(title="Recipe file", self.add_column(title="Recipe file",
static_data_name='recipe_file', static_data_name='recipe_file',
static_data_template='') static_data_template='',
field_name='local_path')
approx_packages_template = '''
<a href="{% url 'customrecipe' extra.pid data.id %}">
{{data.package_set.all|length}}
</a>'''
approx_packages_template = '<a href="#imagedetails">{{data.packages.all|length}}</a>'
self.add_column(title="Approx packages", self.add_column(title="Approx packages",
static_data_name='approx_packages', static_data_name='approx_packages',
static_data_template=approx_packages_template) static_data_template=approx_packages_template)
build_btn_template = '''<button data-recipe-name="{{data.name}}" build_btn_template = '''
<button data-recipe-name="{{data.name}}"
class="btn btn-block build-recipe-btn" style="margin-top: 5px;" > class="btn btn-block build-recipe-btn" style="margin-top: 5px;" >
Build</button>''' Build
</button>'''
self.add_column(title="Build", self.add_column(title="Build",
hideable=False, hideable=False,
@ -540,12 +549,19 @@ class ImageRecipesTable(RecipesTable):
def setup_columns(self, *args, **kwargs): def setup_columns(self, *args, **kwargs):
name_link_template = '''
<a href="{% url 'recipedetails' extra.pid data.pk %}">{{data.name}}</a>
'''
self.add_column(title="Image recipe", self.add_column(title="Image recipe",
help_text="When you build an image recipe, you get an " help_text="When you build an image recipe, you get an "
"image: a root file system you can" "image: a root file system you can"
"deploy to a machine", "deploy to a machine",
hideable=False, hideable=False,
orderable=True, orderable=True,
static_data_name="name",
static_data_template=name_link_template,
field_name="name") field_name="name")
super(ImageRecipesTable, self).setup_columns(*args, **kwargs) super(ImageRecipesTable, self).setup_columns(*args, **kwargs)
@ -609,8 +625,96 @@ class SoftwareRecipesTable(RecipesTable):
self.add_column(**RecipesTable.build_col) self.add_column(**RecipesTable.build_col)
class PackagesTable(ToasterTable):
""" Table to display the packages in a recipe from it's last successful
build"""
class SelectPackagesTable(ToasterTable): def __init__(self, *args, **kwargs):
super(PackagesTable, self).__init__(*args, **kwargs)
self.title = "Packages included"
self.packages = None
self.default_orderby = "name"
def create_package_list(self, recipe, project_id):
"""Creates a list of packages for the specified recipe by looking for
the last SUCCEEDED build of ther recipe"""
target = Target.objects.filter(Q(target=recipe.name) &
Q(build__project_id=project_id) &
Q(build__outcome=Build.SUCCEEDED)
).last()
if target:
return target.build.package_set.all()
# Target/recipe never successfully built so empty queryset
return Package.objects.none()
def get_context_data(self, **kwargs):
"""Context for rendering the sidebar and other items on the recipe
details page """
context = super(PackagesTable, self).get_context_data(**kwargs)
recipe = Recipe.objects.get(pk=kwargs['recipe_id'])
project = Project.objects.get(pk=kwargs['pid'])
in_project = (recipe.layer_version.pk in
project.get_project_layer_versions(pk=True))
packages = self.create_package_list(recipe, project.pk)
context.update({'project': project,
'recipe' : recipe,
'packages': packages,
'approx_pkg_size' : packages.aggregate(Sum('size')),
'in_project' : in_project,
})
return context
def setup_queryset(self, *args, **kwargs):
recipe = Recipe.objects.get(pk=kwargs['recipe_id'])
self.queryset = self.create_package_list(recipe, kwargs['pid'])
self.queryset = self.queryset.order_by('name')
def setup_columns(self, *args, **kwargs):
self.add_column(title="Package",
hideable=False,
orderable=True,
field_name="name")
self.add_column(title="Package Version",
field_name="version",
hideable=False)
self.add_column(title="Approx Size",
orderable=True,
static_data_name="size",
static_data_template="{% load projecttags %} \
{{data.size|filtered_filesizeformat}}")
self.add_column(title="License",
field_name="license",
orderable=True)
self.add_column(title="Dependencies",
static_data_name="dependencies",
static_data_template='\
{% include "snippets/pkg_dependencies_popover.html" %}')
self.add_column(title="Recipe",
field_name="recipe__name",
orderable=True,
hidden=True)
self.add_column(title="Recipe version",
field_name="recipe__version",
hidden=True)
class SelectPackagesTable(PackagesTable):
""" Table to display the packages to add and remove from an image """ """ Table to display the packages to add and remove from an image """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -637,29 +741,25 @@ class SelectPackagesTable(ToasterTable):
self.static_context_extra['current_packages'] = \ self.static_context_extra['current_packages'] = \
cust_recipe.packages.values_list('pk', flat=True) cust_recipe.packages.values_list('pk', flat=True)
def get_context_data(self, **kwargs):
context = super(SelectPackagesTable, self).get_context_data(**kwargs)
custom_recipe = CustomImageRecipe.objects.get(pk=kwargs['recipe_id'])
context['recipe'] = custom_recipe
context['approx_pkg_size'] = custom_recipe.package_set.aggregate(Sum('size'))
return context
def setup_columns(self, *args, **kwargs): def setup_columns(self, *args, **kwargs):
self.add_column(title="Package", super(SelectPackagesTable, self).setup_columns(*args, **kwargs)
hideable=False,
orderable=True,
field_name="name")
self.add_column(title="Package Version",
field_name="version")
self.add_column(title="Approx Size",
orderable=True,
static_data_name="size",
static_data_template="{% load projecttags %} \
{{data.size|filtered_filesizeformat}}")
self.add_column(title="summary",
field_name="summary")
self.add_column(title="Add | Remove", self.add_column(title="Add | Remove",
hideable=False,
help_text="Use the add and remove buttons to modify " help_text="Use the add and remove buttons to modify "
"the package content of you custom image", "the package content of you custom image",
static_data_name="add_rm_pkg_btn", static_data_name="add_rm_pkg_btn",
static_data_template='{% include "pkg_add_rm_btn.html" %}', static_data_template='{% include "pkg_add_rm_btn.html" %}',
static_data_template='{% include "pkg_add_rm_btn.html" %}' filter_name="in_current_image"
) )
def setup_filters(self, *args, **kwargs): def setup_filters(self, *args, **kwargs):
@ -681,12 +781,11 @@ class SelectPackagesTable(ToasterTable):
self.filter_not_in_image) self.filter_not_in_image)
]) ])
def filter_in_image(self, count_only=False): def filter_in_image(self):
return self.queryset.filter( return self.queryset.filter(
pk__in=self.static_context_extra['current_packages']) pk__in=self.static_context_extra['current_packages'])
def filter_not_in_image(self):
def filter_not_in_image(self, count_only=False):
return self.queryset.exclude( return self.queryset.exclude(
pk__in=self.static_context_extra['current_packages']) pk__in=self.static_context_extra['current_packages'])

View File

@ -0,0 +1,14 @@
{# Popover that displays the dependences and sizes of a package 'data' used in the Packages table #}
{% with data.package_dependencies_source.count as dep_count %}
{% load projecttags %}
{% if dep_count %}
<a data-content="<ul class='unstyled'>
{% for dep in data.package_dependencies_source.all %}
<li>{{dep.depends_on.name}} {% if dep.depends_on.size > 0 %}({{dep.depends_on.size|filtered_filesizeformat}}){% endif %}</li>
{% endfor %}
</ul>" title="" class="btn" data-original-title="
<strong>{{data.name}}</strong> dependencies - <strong>{{data.package_dependencies_source.get_total_source_deps_size.depends_on__size__sum|filtered_filesizeformat}}</strong>">
{{dep_count}}
</a>
{% endif %}
{% endwith %}

View File

@ -109,13 +109,10 @@ urlpatterns = patterns('toastergui.views',
tables.NewCustomImagesTable.as_view(template_name="newcustomimage.html"), tables.NewCustomImagesTable.as_view(template_name="newcustomimage.html"),
name="newcustomimage"), name="newcustomimage"),
url(r'^project/(?P<pid>\d+)/layers/$', url(r'^project/(?P<pid>\d+)/layers/$',
tables.LayersTable.as_view(template_name="generic-toastertable-page.html"), tables.LayersTable.as_view(template_name="generic-toastertable-page.html"),
name="projectlayers"), name="projectlayers"),
url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$', url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$',
'layerdetails', name='layerdetails'), 'layerdetails', name='layerdetails'),
@ -133,17 +130,20 @@ urlpatterns = patterns('toastergui.views',
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipeid>\d+)/selectpackages/$', url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipeid>\d+)/selectpackages/$',
tables.SelectPackagesTable.as_view(template_name="generic-toastertable-page.html"), name="recipeselectpackages"), tables.SelectPackagesTable.as_view(), name="recipeselectpackages"),
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)$', url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)$',
'customrecipe', tables.SelectPackagesTable.as_view(template_name="customrecipe.html"),
name="customrecipe"), name="customrecipe"),
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)/download$', url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)/download$',
'customrecipe_download', 'customrecipe_download',
name="customrecipedownload"), name="customrecipedownload"),
url(r'^project/(?P<pid>\d+)/recipe/(?P<recipe_id>\d+)$',
tables.PackagesTable.as_view(template_name="recipedetails.html"),
name="recipedetails"),
# typeahead api end points # typeahead api end points
url(r'^xhr_typeahead/(?P<pid>\d+)/layers$', url(r'^xhr_typeahead/(?P<pid>\d+)/layers$',

View File

@ -2594,15 +2594,6 @@ if True:
return(vars_managed,sorted(vars_fstypes),vars_blacklist) return(vars_managed,sorted(vars_fstypes),vars_blacklist)
def customrecipe(request, pid, recipe_id):
project = Project.objects.get(pk=pid)
context = {'project' : project,
'projectlayers': [],
'recipe' : CustomImageRecipe.objects.get(pk=recipe_id)
}
return render(request, "customrecipe.html", context)
@_template_renderer("projectconf.html") @_template_renderer("projectconf.html")
def projectconf(request, pid): def projectconf(request, pid):