mirror of
https://git.yoctoproject.org/poky
synced 2026-04-26 09:32:14 +02:00
bitbake: toaster: add Image detail and multiple targets to dashboard
Filled in the Image section detail information and allow for multiple targets. Each target has a separate section. Added license manifest display. Changed the target of the license manifest link. Added Tasks failed in the build summary. The target lists required filters to create sorted lists. [YOCTO #4258] [YOCTO #5936] (Bitbake rev: 09b099903bdf51bfb277b9a8f922255cfe83ab96) Signed-off-by: Farrell Wymore <farrell.wymore@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
8c3eb5ee45
commit
405e190b31
@@ -50,6 +50,11 @@ class Build(models.Model):
|
||||
build_name = models.CharField(max_length=100)
|
||||
bitbake_version = models.CharField(max_length=50)
|
||||
|
||||
def get_sorted_target_list(self):
|
||||
tgts = Target.objects.filter(build_id = self.id).order_by( 'target' );
|
||||
return( tgts );
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Target(models.Model):
|
||||
search_allowed_fields = ['target', 'file_name']
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
{% load projecttags %}
|
||||
{% load humanize %}
|
||||
{% block pagecontent %}
|
||||
|
||||
@@ -8,7 +9,7 @@
|
||||
<div class="section">
|
||||
<ul class="breadcrumb" id="breadcrumb">
|
||||
<li><a href="{% url 'all-builds' %}">All builds</a></li>
|
||||
<li><a href="{%url 'builddashboard' build.pk%}">{{build.target_set.all.0.target}} {%if build.target_set.all.count > 1%}(+{{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})</a></li>
|
||||
<li><a href="{%url 'builddashboard' build.pk%}">{{build.get_sorted_target_list.0.target}} {%if build.target_set.all.count > 1%}(+ {{build.target_set.all.count|add:"-1"}}){%endif%} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}})</a></li>
|
||||
{% block localbreadcrumb %}{% endblock %}
|
||||
</ul>
|
||||
<script>
|
||||
@@ -25,10 +26,12 @@
|
||||
<!-- begin left sidebar container -->
|
||||
<div id="nav" class="span2">
|
||||
<ul class="nav nav-list well">
|
||||
{% if build.target_set.all.0.is_image %}
|
||||
<li class="nav-header">Images</li>
|
||||
{% for t in build.target_set.all|dictsort:"target" %}
|
||||
{% for t in build.get_sorted_target_list %}
|
||||
<li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<li class="nav-header">Build</li>
|
||||
<li><a href="{% url 'configuration' build.pk %}">Configuration</a></li>
|
||||
<li><a href="{% url 'tasks' build.pk %}">Tasks</a></li>
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
{% extends "basebuildpage.html" %}
|
||||
{% load humanize %}
|
||||
{% load projecttags %}
|
||||
{% block localbreadcrumb %}
|
||||
<li>Dashboard</li>
|
||||
{% endblock %}
|
||||
|
||||
{% block buildinfomain %}
|
||||
<!-- page title -->
|
||||
<div class="row-fluid span10">
|
||||
<div class="page-header">
|
||||
<h1>{{build.target_set.all|join:" "}} {{build.machine}}</h1>
|
||||
<h1>{{build.target_set.all|join:", "}} {{build.machine}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,13 +14,25 @@
|
||||
<div class="row-fluid span10 pull-right">
|
||||
<div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}">
|
||||
<div class="row-fluid lead">
|
||||
<span class="pull-left"><strong>{%if build.outcome == build.SUCCEEDED%}Completed{%elif build.outcome == build.FAILED%}Failed{%else%}{%endif%}</strong> {{build.completed_on|date:"d/m/y H:i"}} with </span>{%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}{% if build.errors_no %}
|
||||
<span class="span2"><i class="icon-minus-sign red"></i><strong><a href="#errors" class="error"> {{build.errors_no}} error{{build.errors_no|pluralize}}</a></strong></span>
|
||||
<span class="pull-left"><strong>
|
||||
{%if build.outcome == build.SUCCEEDED%}Completed{%elif build.outcome == build.FAILED%}Failed{%else%}{%endif%}
|
||||
</strong>
|
||||
{{build.completed_on|date:"d/m/y H:i"}}
|
||||
</span>
|
||||
{% if build.warnings_no or build.errors_no %}
|
||||
with
|
||||
{% endif %}
|
||||
{%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %}
|
||||
{% if build.errors_no %}
|
||||
<span > <i class="icon-minus-sign red"></i><strong><a href="#errors" class="error"> {{build.errors_no}} error{{build.errors_no|pluralize}}</a></strong></span>
|
||||
{% endif %}
|
||||
{% if build.warnings_no %}
|
||||
<span class="span2"><i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span>
|
||||
{% if build.errors_no %}
|
||||
and
|
||||
{% endif %}
|
||||
<span class="pull-right">Build time: <a href="build-time.html">{{ build.timespent|sectohms }}</a></span>
|
||||
<span > <i class="icon-warning-sign yellow"></i><strong><a href="#warnings" class="warning"> {{build.warnings_no}} warning{{build.warnings_no|pluralize}}</a></strong></span>
|
||||
{% endif %}
|
||||
<span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a></span>
|
||||
{%endif%}
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,10 +67,40 @@
|
||||
{%if build.outcome == build.SUCCEEDED%}
|
||||
<!-- built images -->
|
||||
<div class="row-fluid span10 pull-right">
|
||||
<h2>Images</h2>
|
||||
|
||||
<div class="well" style="background-color:transparent;">
|
||||
</div>
|
||||
{% if hasImages %}
|
||||
<h2>Images</h2>
|
||||
{% for target in targets %}
|
||||
{% if target.target.is_image %}
|
||||
<div class="well" style="background-color:transparent;">
|
||||
<h3><a href="{% url 'target' build.pk target.target.pk %}">{{target.target}}</a>
|
||||
</h3>
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Packages included</dt>
|
||||
<dd><a href="{% url 'packages' build.pk %}">{{target.npkg}}</a></dd>
|
||||
<dt>Total package size</dt>
|
||||
<dd>{{target.pkgsz|filtered_filesizeformat}}</dd>
|
||||
<dt>
|
||||
<i class="icon-question-sign get-help" title="The location in disk of the license manifest, a document listing all packages installed in your image and their licenses"></i>
|
||||
License manifest
|
||||
</dt>
|
||||
<dd><a href="{% url 'targetpackages' build.pk target.target.pk %}"><code>{{target.target.license_manifest_path}}</code></a></dd>
|
||||
<dt>
|
||||
<i class="icon-question-sign get-help" title="Image files are stored in <code style='background-color:transparent;color:#FFFFFF;font-weight:normal;border:none;'>/build/tmp/deploy/images/</code>"></i>
|
||||
Image files
|
||||
</dt>
|
||||
<dd>
|
||||
<ul>
|
||||
{% for i in target.imageFiles %}
|
||||
<li><strong>{{i.path}}</strong>
|
||||
({{i.size|filtered_filesizeformat}})</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{%else%}
|
||||
@@ -75,24 +114,32 @@
|
||||
<h4><a href="{%url 'configuration' build.pk%}">Configuration</a></h4>
|
||||
<dl>
|
||||
<dt>Machine</dt><dd>{{build.machine}}</dd>
|
||||
<dt>Distro</dt><dd></dd>
|
||||
<dt>Layers</dt>{% for i in build.layer_version_build.all %}<dd>{{i.layer.name}}</dd>{%endfor%}
|
||||
<dt>Distro</dt><dd>{{build.distro}}</dd>
|
||||
<dt>Layers</dt>{% for i in build.layer_version_build.all|dictsort:"layer.name" %}<dd>{{i.layer.name}}</dd>{%endfor%}
|
||||
</dl>
|
||||
</div>
|
||||
<div class="well span4" style="background-color:transparent;">
|
||||
<h4><a href="{%url 'tasks' build.pk%}">Tasks</a></h4>
|
||||
<dl>
|
||||
<dt>Total number of tasks</dt><dd>{{build.task_build.all.count}}</dd>
|
||||
<dt>Tasks executed</dt><dd>{% query build.task_build task_executed=1 order__gt=0 as exectask%}{{exectask.count}}</dd>
|
||||
<dt>Tasks prebuilt</dt><dd>{% query build.task_build task_executed=0 order__gt=0 as noexectask%}{{noexectask.count}}</dd>
|
||||
<dt>Reuse</dt><dd>{% query build.task_build order__gt=0 as texec %}{{noexectask.count|multiply:100|divide:texec.count}}%</dd>
|
||||
<dt>Total number of tasks</dt><dd><a href="{% url 'tasks' build.pk %}">{{build.task_build.all.count}}</a></dd>
|
||||
<dt>Tasks executed</dt><dd><a href="{% url 'tasks' build.pk %}?filter=task_executed%3A1&count=25&search=&page=1&orderby=order%3A%2B">{% query build.task_build task_executed=1 order__gt=0 as exectask%}{{exectask.count}}</a></dd>
|
||||
<dt>Tasks not executed</dt><dd><a href="{% url 'tasks' build.pk %}?filter=task_executed%3A0&count=25&search=&page=1&orderby=order%3A%2B">{% query build.task_build task_executed=0 order__gt=0 as noexectask%}{{noexectask.count}}</a></dd>
|
||||
<dt>Reuse</dt><dd>
|
||||
{% query build.task_build order__gt=0 as texec %}
|
||||
{% if noexectask.count|multiply:100|divide:texec.count < 0 %}
|
||||
0
|
||||
{% else %}
|
||||
{{noexectask.count|multiply:100|divide:texec.count}}
|
||||
{% endif %}
|
||||
%
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="well span4" style="background-color:transparent;">
|
||||
<h4><a href="{% url 'recipes' build.pk %}">Recipes</a> & <a href="{% url 'packages' build.pk %}">Packages</a></h4>
|
||||
<dl>
|
||||
<dt>Recipes used</dt><dd>{{recipecount}}</dd>
|
||||
<dt>Packages built</dt><dd>{{build.package_set.all.count}}</dd>
|
||||
<dt>Recipes built</dt><dd><a href="{% url 'recipes' build.pk %}">{{recipecount}}</a></dd>
|
||||
<dt>Packages built</dt><dd><a href="{% url 'packages' build.pk %}">{{build.package_set.all.count}}</a></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@ from django.db.models import Q, Sum
|
||||
from django.shortcuts import render, redirect
|
||||
from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable
|
||||
from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency
|
||||
from orm.models import Target_Installed_Package, Target_File
|
||||
from orm.models import Target_Installed_Package, Target_Image_File
|
||||
from django.views.decorators.cache import cache_control
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
from django.http import HttpResponseBadRequest
|
||||
@@ -350,18 +350,59 @@ def builds(request):
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
##
|
||||
# build dashboard for a single build, coming in as argument
|
||||
# Each build may contain multiple targets and each target
|
||||
# may generate multiple image files. display them all.
|
||||
#
|
||||
def builddashboard(request, build_id):
|
||||
template = "builddashboard.html"
|
||||
if Build.objects.filter(pk=build_id).count() == 0 :
|
||||
return redirect(builds)
|
||||
build = Build.objects.filter(pk = build_id)[0];
|
||||
layerVersionId = Layer_Version.objects.filter( build = build_id );
|
||||
recipeCount = Recipe.objects.filter( layer_version__id__in = layerVersionId ).count( );
|
||||
tgts = Target.objects.filter( build_id = build_id ).order_by( 'target' );
|
||||
|
||||
# set up custom target list with computed package and image data
|
||||
targets = [ ];
|
||||
ntargets = 0;
|
||||
hasImages = False;
|
||||
for t in tgts:
|
||||
elem = { };
|
||||
elem[ 'target' ] = t;
|
||||
if ( t.is_image ):
|
||||
hasImages = True;
|
||||
npkg = 0;
|
||||
pkgsz = 0;
|
||||
pid= 0;
|
||||
tp = Target_Installed_Package.objects.filter( target_id = t.id );
|
||||
package = None;
|
||||
for p in tp:
|
||||
pid = p.package_id;
|
||||
package = Package.objects.get( pk = p.package_id )
|
||||
pkgsz = pkgsz + package.size;
|
||||
npkg = npkg + 1;
|
||||
elem[ 'npkg' ] = npkg;
|
||||
elem[ 'pkgsz' ] = pkgsz;
|
||||
ti = Target_Image_File.objects.filter( target_id = t.id );
|
||||
imageFiles = [ ];
|
||||
for i in ti:
|
||||
imageFiles.append({ 'path': i.file_name, 'size' : i.file_size });
|
||||
elem[ 'imageFiles' ] = imageFiles;
|
||||
targets.append( elem );
|
||||
|
||||
context = {
|
||||
'build' : Build.objects.filter(pk=build_id)[0],
|
||||
'recipecount' : Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)).count(),
|
||||
'logmessages' : LogMessage.objects.filter(build=build_id),
|
||||
'build' : build,
|
||||
'hasImages' : hasImages,
|
||||
'ntargets' : ntargets,
|
||||
'targets' : targets,
|
||||
'recipecount' : recipeCount,
|
||||
'logmessages' : LogMessage.objects.filter(build=build_id),
|
||||
}
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
def task(request, build_id, task_id):
|
||||
template = "task.html"
|
||||
if Task.objects.filter(pk=task_id).count() == 0 :
|
||||
|
||||
Reference in New Issue
Block a user