bitbake: toaster: port table for Built packages to ToasterTable
This is the table that displays all the packages built in the build. Build -> Packages. Adds a template snippet for the git revision popover. (Bitbake rev: df62f38ff4e634544c9b1e97c5f6ca45e84a4f1e) Signed-off-by: Michael Wood <michael.g.wood@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
parent
b63f9518e7
commit
a786ac14f1
|
@ -0,0 +1,152 @@
|
|||
#
|
||||
# ex:ts=4:sw=4:sts=4:et
|
||||
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# BitBake Toaster Implementation
|
||||
#
|
||||
# Copyright (C) 2016 Intel Corporation
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License version 2 as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
from orm.models import Build
|
||||
import toastergui.tables as tables
|
||||
|
||||
from toastergui.widgets import ToasterTable
|
||||
|
||||
|
||||
class BuildTablesMixin(ToasterTable):
|
||||
def get_context_data(self, **kwargs):
|
||||
# We need to be explicit about which superclass we're calling here
|
||||
# Otherwise the MRO gets in a right mess
|
||||
context = ToasterTable.get_context_data(self, **kwargs)
|
||||
context['build'] = Build.objects.get(pk=kwargs['build_id'])
|
||||
return context
|
||||
|
||||
|
||||
class BuiltPackagesTableBase(tables.PackagesTable):
|
||||
""" Table to display all the packages built in a build """
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BuiltPackagesTableBase, self).__init__(*args, **kwargs)
|
||||
self.title = "Packages built"
|
||||
self.default_orderby = "name"
|
||||
|
||||
def setup_queryset(self, *args, **kwargs):
|
||||
build = Build.objects.get(pk=kwargs['build_id'])
|
||||
self.static_context_extra['build'] = build
|
||||
self.queryset = build.package_set.all().exclude(recipe=None)
|
||||
self.queryset = self.queryset.order_by(self.default_orderby)
|
||||
|
||||
def setup_columns(self, *args, **kwargs):
|
||||
super(BuiltPackagesTableBase, self).setup_columns(*args, **kwargs)
|
||||
|
||||
def pkg_link_template(val):
|
||||
""" return the template used for the link with the val as the
|
||||
element value i.e. inside the <a></a>"""
|
||||
|
||||
return ('''
|
||||
<a href="
|
||||
{%% url "package_built_detail" extra.build.pk data.pk %%}
|
||||
">%s</a>
|
||||
''' % val)
|
||||
|
||||
def recipe_link_template(val):
|
||||
return ('''
|
||||
{%% if data.recipe %%}
|
||||
<a href="
|
||||
{%% url "recipe" extra.build.pk data.recipe.pk %%}
|
||||
">%(value)s</a>
|
||||
{%% else %%}
|
||||
%(value)s
|
||||
{%% endif %%}
|
||||
''' % {'value': val})
|
||||
|
||||
add_pkg_link_to = ['name', 'version', 'size', 'license']
|
||||
add_recipe_link_to = ['recipe__name', 'recipe__version']
|
||||
|
||||
# Add the recipe and pkg build links to the required columns
|
||||
for column in self.columns:
|
||||
# Convert to template field style accessors
|
||||
tmplv = column['field_name'].replace('__', '.')
|
||||
tmplv = "{{data.%s}}" % tmplv
|
||||
|
||||
if column['field_name'] in add_pkg_link_to:
|
||||
# Don't overwrite an existing template
|
||||
if column['static_data_template']:
|
||||
column['static_data_template'] =\
|
||||
pkg_link_template(column['static_data_template'])
|
||||
else:
|
||||
column['static_data_template'] = pkg_link_template(tmplv)
|
||||
|
||||
column['static_data_name'] = column['field_name']
|
||||
|
||||
elif column['field_name'] in add_recipe_link_to:
|
||||
# Don't overwrite an existing template
|
||||
if column['static_data_template']:
|
||||
column['static_data_template'] =\
|
||||
recipe_link_template(column['static_data_template'])
|
||||
else:
|
||||
column['static_data_template'] =\
|
||||
recipe_link_template(tmplv)
|
||||
column['static_data_name'] = column['field_name']
|
||||
|
||||
self.add_column(title="Layer",
|
||||
field_name="recipe__layer_version__layer__name",
|
||||
hidden=True,
|
||||
orderable=True)
|
||||
|
||||
self.add_column(title="Layer branch",
|
||||
field_name="recipe__layer_version__branch",
|
||||
hidden=True,
|
||||
orderable=True)
|
||||
|
||||
git_rev_template = '''
|
||||
{% with vcs_ref=data.recipe.layer_version.commit %}
|
||||
{% include 'snippets/gitrev_popover.html' %}
|
||||
{% endwith %}
|
||||
'''
|
||||
|
||||
self.add_column(title="Layer commit",
|
||||
static_data_name='vcs_ref',
|
||||
static_data_template=git_rev_template,
|
||||
hidden=True)
|
||||
|
||||
|
||||
class BuiltPackagesTable(BuildTablesMixin, BuiltPackagesTableBase):
|
||||
""" Show all the packages built for the selected build """
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BuiltPackagesTable, self).__init__(*args, **kwargs)
|
||||
self.title = "Packages built"
|
||||
self.default_orderby = "name"
|
||||
|
||||
self.empty_state =\
|
||||
('<strong>No packages were built.</strong> How did this happen?'
|
||||
'Well, BitBake reuses as much stuff as possible.'
|
||||
'If all of the packages needed were already built and available'
|
||||
'in your build infrastructure, BitBake'
|
||||
'will not rebuild any of them. This might be slightly confusing,'
|
||||
'but it does make everything faster.')
|
||||
|
||||
def setup_columns(self, *args, **kwargs):
|
||||
super(BuiltPackagesTable, self).setup_columns(*args, **kwargs)
|
||||
|
||||
def remove_dep_cols(columns):
|
||||
for column in columns:
|
||||
# We don't need these fields
|
||||
if column['static_data_name'] in ['reverse_dependencies',
|
||||
'dependencies']:
|
||||
continue
|
||||
|
||||
yield column
|
||||
|
||||
self.columns = list(remove_dep_cols(self.columns))
|
|
@ -146,15 +146,8 @@ class LayersTable(ToasterTable):
|
|||
static_data_template=git_dir_template)
|
||||
|
||||
revision_template = '''
|
||||
{% load projecttags %}
|
||||
{% with vcs_ref=data.get_vcs_reference %}
|
||||
{% if vcs_ref|is_shaid %}
|
||||
<a class="btn" data-content="<ul class='unstyled'> <li>{{vcs_ref}}</li> </ul>">
|
||||
{{vcs_ref|truncatechars:10}}
|
||||
</a>
|
||||
{% else %}
|
||||
{{vcs_ref}}
|
||||
{% endif %}
|
||||
{% include 'snippets/gitrev_popover.html' %}
|
||||
{% endwith %}
|
||||
'''
|
||||
|
||||
|
@ -718,6 +711,7 @@ class PackagesTable(ToasterTable):
|
|||
|
||||
self.add_column(title="Approx Size",
|
||||
orderable=True,
|
||||
field_name="size",
|
||||
static_data_name="size",
|
||||
static_data_template="{% load projecttags %} \
|
||||
{{data.size|filtered_filesizeformat}}")
|
||||
|
|
|
@ -23,10 +23,19 @@
|
|||
{% block localbreadcrumb %}{% endblock %}
|
||||
</ul>
|
||||
<script>
|
||||
$( function () {
|
||||
$(document).ready(function(){
|
||||
$('#breadcrumb > li').append('<span class="divider">→</span>');
|
||||
$('#breadcrumb > li:last').addClass("active");
|
||||
$('#breadcrumb > li:last > span').remove();
|
||||
|
||||
$("#build-menu li a").each(function(){
|
||||
/* Set the page active state in the Build menu */
|
||||
if (window.location.href.split('?')[0] === $(this).prop("href")){
|
||||
$(this).parent().addClass("active");
|
||||
} else {
|
||||
$(this).parent().removeClass("active");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
@ -35,7 +44,7 @@
|
|||
<div class="row">
|
||||
<!-- begin left sidebar container -->
|
||||
<div id="nav" class="col-md-2">
|
||||
<ul class="nav nav-list well">
|
||||
<ul class="nav nav-list well" id="build-menu">
|
||||
<li
|
||||
{% if request.resolver_match.url_name == 'builddashboard' %}
|
||||
class="active"
|
||||
|
@ -54,25 +63,14 @@
|
|||
{% block nav-configuration %}
|
||||
<li><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
|
||||
{% endblock %}
|
||||
{% block nav-tasks %}
|
||||
|
||||
<li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
|
||||
{% endblock %}
|
||||
{% block nav-recipes %}
|
||||
<li><a href="{% url 'recipes' build.pk %}">Recipes</a></li>
|
||||
{% endblock %}
|
||||
{% block nav-packages %}
|
||||
<li><a href="{% url 'packages' build.pk %}">Packages</a></li>
|
||||
{% endblock %}
|
||||
<li class="nav-header">Performance</li>
|
||||
{% block nav-buildtime %}
|
||||
<li><a href="{% url 'buildtime' build.pk %}">Time</a></li>
|
||||
{% endblock %}
|
||||
{% block nav-cputime %}
|
||||
<li><a href="{% url 'cputime' build.pk %}">CPU usage</a></li>
|
||||
{% endblock %}
|
||||
{% block nav-diskio %}
|
||||
<li><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li>
|
||||
{% endblock %}
|
||||
|
||||
<li class="divider"></li>
|
||||
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
{% extends "basebuildpage.html" %}
|
||||
|
||||
{% load projecttags %}
|
||||
|
||||
{% block title %} Packages built - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %}
|
||||
{% block localbreadcrumb %}
|
||||
<li>Packages</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block nav-packages %}
|
||||
<li class="active"><a href="{% url 'packages' build.pk %}">Packages</a></li>
|
||||
{% endblock %}
|
||||
|
||||
{% block buildinfomain %}
|
||||
<div class="col-md-10">
|
||||
|
||||
{% if not request.GET.filter and not request.GET.search and not objects.paginator.count %}
|
||||
|
||||
<!-- Empty - no data in database -->
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
Packages
|
||||
</h1>
|
||||
</div>
|
||||
<div class="alert alert-info lead">
|
||||
<strong>No packages were built.</strong> How did this happen? Well, BitBake reuses as much stuff as possible.
|
||||
If all of the packages needed were already built and available in your build infrastructure, BitBake
|
||||
will not rebuild any of them. This might be slightly confusing, but it does make everything faster.
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
{% if request.GET.search and objects.paginator.count > 0 %}
|
||||
{{objects.paginator.count}} package{{objects.paginator.count|pluralize}} found
|
||||
{%elif request.GET.search and objects.paginator.count == 0%}
|
||||
No packages found
|
||||
{%else%}
|
||||
Packages
|
||||
{%endif%}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{% if objects.paginator.count == 0 %}
|
||||
<div class="alert">
|
||||
<form class="no-results input-append" id="searchform">
|
||||
<input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="input-append-addon btn" tabindex="-1"><i class="glyphicon glyphicon-remove"></i></a>{% endif %}
|
||||
<button class="btn" type="submit" value="Search">Search</button>
|
||||
<button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all packages</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
{% include "basetable_top.html" %}
|
||||
|
||||
{% for package in objects %}
|
||||
|
||||
<tr class="data">
|
||||
|
||||
<!-- Package -->
|
||||
<td class="package_name"><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.name}}</a></td>
|
||||
<!-- Package Version -->
|
||||
<td class="package_version">{%if package.version%}<a href="{% url "package_built_detail" build.pk package.pk %}">{{package.version}}-{{package.revision}}</a>{%endif%}</td>
|
||||
<!-- Package Size -->
|
||||
<td class="size sizecol">{{package.size|filtered_filesizeformat}}</td>
|
||||
<!-- License -->
|
||||
<td class="license">{{package.license}}</td>
|
||||
|
||||
{%if package.recipe%}
|
||||
<!-- Recipe -->
|
||||
<td class="recipe__name"><a href="{% url "recipe" build.pk package.recipe.pk %}">{{package.recipe.name}}</a></td>
|
||||
<!-- Recipe Version -->
|
||||
<td class="recipe__version"><a href="{% url "recipe" build.pk package.recipe.pk %}">{{package.recipe.version}}</a></td>
|
||||
|
||||
<!-- Layer -->
|
||||
<td class="recipe__layer_version__layer__name">{{package.recipe.layer_version.layer.name}}</td>
|
||||
<!-- Layer branch -->
|
||||
<td class="recipe__layer_version__branch">{{package.recipe.layer_version.branch}}</td>
|
||||
<!-- Layer commit -->
|
||||
<td class="recipe__layer_version__layer__commit">
|
||||
<a class="btn"
|
||||
data-content="<ul class='list-unstyled'>
|
||||
<li>{{package.recipe.layer_version.commit}}</li>
|
||||
</ul>">
|
||||
{{package.recipe.layer_version.commit|truncatechars:13}}
|
||||
</a>
|
||||
</td>
|
||||
<!-- Layer directory -->
|
||||
{%else%}
|
||||
<td class="recipe__name"></td>
|
||||
<td class="recipe__version"></td>
|
||||
<td class="recipe__layer_version__layer__name"></td>
|
||||
<td class="recipe__layer_version__branch"></td>
|
||||
<td class="recipe__layer_version__layer__commit"></td>
|
||||
<td class="recipe__layer_version__local_path"></td>
|
||||
{%endif%}
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% include "basetable_bottom.html" %}
|
||||
{% endif %} {# objects.paginator.count #}
|
||||
{% endif %} {# Empty #}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "basebuildpage.html" %}
|
||||
|
||||
{% load projecttags %}
|
||||
|
||||
{% block title %} {{title}} - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %}
|
||||
{% block localbreadcrumb %}
|
||||
<li>{{title}}</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block nav-packages %}
|
||||
{% endblock %}
|
||||
|
||||
{% block buildinfomain %}
|
||||
<div class="span10">
|
||||
{% url 'builtpackagestable' build.id as xhr_table_url %}
|
||||
<div class="page-header">
|
||||
<h1>
|
||||
{{title}} (<span class="table-count-{{table_name}}">0</span>) </h2>
|
||||
</h1>
|
||||
</div>
|
||||
{% include "toastertable.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
|||
{% load projecttags %}
|
||||
{% if vcs_ref|is_shaid %}
|
||||
<a class="btn" data-content="<ul class='unstyled'> <li>{{vcs_ref}}</li> </ul>">
|
||||
{{vcs_ref|truncatechars:10}}
|
||||
</a>
|
||||
{% else %}
|
||||
{{vcs_ref}}
|
||||
{% endif %}
|
|
@ -21,6 +21,7 @@ from django.views.generic import RedirectView, TemplateView
|
|||
|
||||
from django.http import HttpResponseBadRequest
|
||||
from toastergui import tables
|
||||
from toastergui import buildtables
|
||||
from toastergui import typeaheads
|
||||
from toastergui import api
|
||||
|
||||
|
@ -44,7 +45,11 @@ urlpatterns = patterns('toastergui.views',
|
|||
url(r'^build/(?P<build_id>\d+)/recipe/(?P<recipe_id>\d+)$', 'recipe', name='recipe'),
|
||||
url(r'^build/(?P<build_id>\d+)/recipe_packages/(?P<recipe_id>\d+)$', 'recipe_packages', name='recipe_packages'),
|
||||
|
||||
url(r'^build/(?P<build_id>\d+)/packages/$', 'bpackage', name='packages'),
|
||||
url(r'^build/(?P<build_id>\d+)/packages/$',
|
||||
buildtables.BuiltPackagesTable.as_view(
|
||||
template_name="buildinfo-toastertable.html"),
|
||||
name='packages'),
|
||||
|
||||
url(r'^build/(?P<build_id>\d+)/package/(?P<package_id>\d+)$', 'package_built_detail',
|
||||
name='package_built_detail'),
|
||||
url(r'^build/(?P<build_id>\d+)/package_built_dependencies/(?P<package_id>\d+)$',
|
||||
|
|
|
@ -1493,96 +1493,6 @@ def configvars(request, build_id):
|
|||
_set_parameters_values(pagesize, orderby, request)
|
||||
return response
|
||||
|
||||
def bpackage(request, build_id):
|
||||
template = 'bpackage.html'
|
||||
(pagesize, orderby) = _get_parameters_values(request, 100, 'name:+')
|
||||
mandatory_parameters = { 'count' : pagesize, 'page' : 1, 'orderby' : orderby }
|
||||
retval = _verify_parameters( request.GET, mandatory_parameters )
|
||||
if retval:
|
||||
return _redirect_parameters( 'packages', request.GET, mandatory_parameters, build_id = build_id)
|
||||
(filter_string, search_term, ordering_string) = _search_tuple(request, Package)
|
||||
queryset = Package.objects.filter(build = build_id).filter(size__gte=0)
|
||||
queryset = _get_queryset(Package, queryset, filter_string, search_term, ordering_string, 'name')
|
||||
|
||||
packages = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1))
|
||||
|
||||
build = Build.objects.get( pk = build_id )
|
||||
|
||||
context = {
|
||||
'objectname': 'packages built',
|
||||
'build': build,
|
||||
'project': build.project,
|
||||
'objects' : packages,
|
||||
'default_orderby' : 'name:+',
|
||||
'tablecols':[
|
||||
{
|
||||
'name':'Package',
|
||||
'qhelp':'Packaged output resulting from building a recipe',
|
||||
'orderfield': _get_toggle_order(request, "name"),
|
||||
'ordericon':_get_toggle_order_icon(request, "name"),
|
||||
},
|
||||
{
|
||||
'name':'Package version',
|
||||
'qhelp':'The package version and revision',
|
||||
},
|
||||
{
|
||||
'name':'Size',
|
||||
'qhelp':'The size of the package',
|
||||
'orderfield': _get_toggle_order(request, "size", True),
|
||||
'ordericon':_get_toggle_order_icon(request, "size"),
|
||||
'orderkey' : 'size',
|
||||
'clclass': 'size', 'hidden': 0,
|
||||
'dclass' : 'span2',
|
||||
},
|
||||
{
|
||||
'name':'License',
|
||||
'qhelp':'The license under which the package is distributed. Multiple license names separated by the pipe character indicates a choice between licenses. Multiple license names separated by the ampersand character indicates multiple licenses exist that cover different parts of the source',
|
||||
'orderfield': _get_toggle_order(request, "license"),
|
||||
'ordericon':_get_toggle_order_icon(request, "license"),
|
||||
'orderkey' : 'license',
|
||||
'clclass': 'license', 'hidden': 1,
|
||||
},
|
||||
{
|
||||
'name':'Recipe',
|
||||
'qhelp':'The name of the recipe building the package',
|
||||
'orderfield': _get_toggle_order(request, "recipe__name"),
|
||||
'ordericon':_get_toggle_order_icon(request, "recipe__name"),
|
||||
'orderkey' : 'recipe__name',
|
||||
'clclass': 'recipe__name', 'hidden': 0,
|
||||
},
|
||||
{
|
||||
'name':'Recipe version',
|
||||
'qhelp':'Version and revision of the recipe building the package',
|
||||
'clclass': 'recipe__version', 'hidden': 1,
|
||||
},
|
||||
{
|
||||
'name':'Layer',
|
||||
'qhelp':'The name of the layer providing the recipe that builds the package',
|
||||
'orderfield': _get_toggle_order(request, "recipe__layer_version__layer__name"),
|
||||
'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__layer__name"),
|
||||
'orderkey' : 'recipe__layer_version__layer__name',
|
||||
'clclass': 'recipe__layer_version__layer__name', 'hidden': 1,
|
||||
},
|
||||
{
|
||||
'name':'Layer branch',
|
||||
'qhelp':'The Git branch of the layer providing the recipe that builds the package',
|
||||
'orderfield': _get_toggle_order(request, "recipe__layer_version__branch"),
|
||||
'ordericon':_get_toggle_order_icon(request, "recipe__layer_version__branch"),
|
||||
'orderkey' : 'recipe__layer_version__branch',
|
||||
'clclass': 'recipe__layer_version__branch', 'hidden': 1,
|
||||
},
|
||||
{
|
||||
'name':'Layer commit',
|
||||
'qhelp':'The Git commit of the layer providing the recipe that builds the package',
|
||||
'clclass': 'recipe__layer_version__layer__commit', 'hidden': 1,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
response = render(request, template, context)
|
||||
_set_parameters_values(pagesize, orderby, request)
|
||||
return response
|
||||
|
||||
def bfile(request, build_id, package_id):
|
||||
template = 'bfile.html'
|
||||
files = Package_File.objects.filter(package = package_id)
|
||||
|
|
Loading…
Reference in New Issue