diff options
| -rw-r--r-- | bitbake/lib/toaster/orm/models.py | 5 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/basebuildpage.html | 7 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/templates/builddashboard.html | 87 | ||||
| -rw-r--r-- | bitbake/lib/toaster/toastergui/views.py | 49 |
4 files changed, 122 insertions, 26 deletions
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py index 30599088e5..4975433acd 100644 --- a/bitbake/lib/toaster/orm/models.py +++ b/bitbake/lib/toaster/orm/models.py | |||
| @@ -50,6 +50,11 @@ class Build(models.Model): | |||
| 50 | build_name = models.CharField(max_length=100) | 50 | build_name = models.CharField(max_length=100) |
| 51 | bitbake_version = models.CharField(max_length=50) | 51 | bitbake_version = models.CharField(max_length=50) |
| 52 | 52 | ||
| 53 | def get_sorted_target_list(self): | ||
| 54 | tgts = Target.objects.filter(build_id = self.id).order_by( 'target' ); | ||
| 55 | return( tgts ); | ||
| 56 | |||
| 57 | |||
| 53 | @python_2_unicode_compatible | 58 | @python_2_unicode_compatible |
| 54 | class Target(models.Model): | 59 | class Target(models.Model): |
| 55 | search_allowed_fields = ['target', 'file_name'] | 60 | search_allowed_fields = ['target', 'file_name'] |
diff --git a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html index 636fca28dd..0ce5dbd27f 100644 --- a/bitbake/lib/toaster/toastergui/templates/basebuildpage.html +++ b/bitbake/lib/toaster/toastergui/templates/basebuildpage.html | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | {% extends "base.html" %} | 1 | {% extends "base.html" %} |
| 2 | {% load projecttags %} | ||
| 2 | {% load humanize %} | 3 | {% load humanize %} |
| 3 | {% block pagecontent %} | 4 | {% block pagecontent %} |
| 4 | 5 | ||
| @@ -8,7 +9,7 @@ | |||
| 8 | <div class="section"> | 9 | <div class="section"> |
| 9 | <ul class="breadcrumb" id="breadcrumb"> | 10 | <ul class="breadcrumb" id="breadcrumb"> |
| 10 | <li><a href="{% url 'all-builds' %}">All builds</a></li> | 11 | <li><a href="{% url 'all-builds' %}">All builds</a></li> |
| 11 | <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> | 12 | <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> |
| 12 | {% block localbreadcrumb %}{% endblock %} | 13 | {% block localbreadcrumb %}{% endblock %} |
| 13 | </ul> | 14 | </ul> |
| 14 | <script> | 15 | <script> |
| @@ -25,10 +26,12 @@ | |||
| 25 | <!-- begin left sidebar container --> | 26 | <!-- begin left sidebar container --> |
| 26 | <div id="nav" class="span2"> | 27 | <div id="nav" class="span2"> |
| 27 | <ul class="nav nav-list well"> | 28 | <ul class="nav nav-list well"> |
| 29 | {% if build.target_set.all.0.is_image %} | ||
| 28 | <li class="nav-header">Images</li> | 30 | <li class="nav-header">Images</li> |
| 29 | {% for t in build.target_set.all|dictsort:"target" %} | 31 | {% for t in build.get_sorted_target_list %} |
| 30 | <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> | 32 | <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> |
| 31 | {% endfor %} | 33 | {% endfor %} |
| 34 | {% endif %} | ||
| 32 | <li class="nav-header">Build</li> | 35 | <li class="nav-header">Build</li> |
| 33 | <li><a href="{% url 'configuration' build.pk %}">Configuration</a></li> | 36 | <li><a href="{% url 'configuration' build.pk %}">Configuration</a></li> |
| 34 | <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li> | 37 | <li><a href="{% url 'tasks' build.pk %}">Tasks</a></li> |
diff --git a/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/bitbake/lib/toaster/toastergui/templates/builddashboard.html index 763a28d1bf..9d91f4031f 100644 --- a/bitbake/lib/toaster/toastergui/templates/builddashboard.html +++ b/bitbake/lib/toaster/toastergui/templates/builddashboard.html | |||
| @@ -1,15 +1,12 @@ | |||
| 1 | {% extends "basebuildpage.html" %} | 1 | {% extends "basebuildpage.html" %} |
| 2 | {% load humanize %} | 2 | {% load humanize %} |
| 3 | {% load projecttags %} | 3 | {% load projecttags %} |
| 4 | {% block localbreadcrumb %} | ||
| 5 | <li>Dashboard</li> | ||
| 6 | {% endblock %} | ||
| 7 | 4 | ||
| 8 | {% block buildinfomain %} | 5 | {% block buildinfomain %} |
| 9 | <!-- page title --> | 6 | <!-- page title --> |
| 10 | <div class="row-fluid span10"> | 7 | <div class="row-fluid span10"> |
| 11 | <div class="page-header"> | 8 | <div class="page-header"> |
| 12 | <h1>{{build.target_set.all|join:" "}} {{build.machine}}</h1> | 9 | <h1>{{build.target_set.all|join:", "}} {{build.machine}}</h1> |
| 13 | </div> | 10 | </div> |
| 14 | </div> | 11 | </div> |
| 15 | 12 | ||
| @@ -17,13 +14,25 @@ | |||
| 17 | <div class="row-fluid span10 pull-right"> | 14 | <div class="row-fluid span10 pull-right"> |
| 18 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> | 15 | <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-error{%else%}alert-info{%endif%}"> |
| 19 | <div class="row-fluid lead"> | 16 | <div class="row-fluid lead"> |
| 20 | <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 %} | 17 | <span class="pull-left"><strong> |
| 21 | <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> | 18 | {%if build.outcome == build.SUCCEEDED%}Completed{%elif build.outcome == build.FAILED%}Failed{%else%}{%endif%} |
| 19 | </strong> | ||
| 20 | {{build.completed_on|date:"d/m/y H:i"}} | ||
| 21 | </span> | ||
| 22 | {% if build.warnings_no or build.errors_no %} | ||
| 23 | with | ||
| 24 | {% endif %} | ||
| 25 | {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} | ||
| 26 | {% if build.errors_no %} | ||
| 27 | <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> | ||
| 22 | {% endif %} | 28 | {% endif %} |
| 23 | {% if build.warnings_no %} | 29 | {% if build.warnings_no %} |
| 24 | <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> | 30 | {% if build.errors_no %} |
| 31 | and | ||
| 32 | {% endif %} | ||
| 33 | <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> | ||
| 25 | {% endif %} | 34 | {% endif %} |
| 26 | <span class="pull-right">Build time: <a href="build-time.html">{{ build.timespent|sectohms }}</a></span> | 35 | <span class="pull-right">Build time: <a href="{% url 'buildtime' build.pk %}">{{ build.timespent|sectohms }}</a></span> |
| 27 | {%endif%} | 36 | {%endif%} |
| 28 | </div> | 37 | </div> |
| 29 | </div> | 38 | </div> |
| @@ -58,10 +67,40 @@ | |||
| 58 | {%if build.outcome == build.SUCCEEDED%} | 67 | {%if build.outcome == build.SUCCEEDED%} |
| 59 | <!-- built images --> | 68 | <!-- built images --> |
| 60 | <div class="row-fluid span10 pull-right"> | 69 | <div class="row-fluid span10 pull-right"> |
| 61 | <h2>Images</h2> | 70 | {% if hasImages %} |
| 62 | 71 | <h2>Images</h2> | |
| 63 | <div class="well" style="background-color:transparent;"> | 72 | {% for target in targets %} |
| 64 | </div> | 73 | {% if target.target.is_image %} |
| 74 | <div class="well" style="background-color:transparent;"> | ||
| 75 | <h3><a href="{% url 'target' build.pk target.target.pk %}">{{target.target}}</a> | ||
| 76 | </h3> | ||
| 77 | <dl class="dl-horizontal"> | ||
| 78 | <dt>Packages included</dt> | ||
| 79 | <dd><a href="{% url 'packages' build.pk %}">{{target.npkg}}</a></dd> | ||
| 80 | <dt>Total package size</dt> | ||
| 81 | <dd>{{target.pkgsz|filtered_filesizeformat}}</dd> | ||
| 82 | <dt> | ||
| 83 | <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> | ||
| 84 | License manifest | ||
| 85 | </dt> | ||
| 86 | <dd><a href="{% url 'targetpackages' build.pk target.target.pk %}"><code>{{target.target.license_manifest_path}}</code></a></dd> | ||
| 87 | <dt> | ||
| 88 | <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> | ||
| 89 | Image files | ||
| 90 | </dt> | ||
| 91 | <dd> | ||
| 92 | <ul> | ||
| 93 | {% for i in target.imageFiles %} | ||
| 94 | <li><strong>{{i.path}}</strong> | ||
| 95 | ({{i.size|filtered_filesizeformat}})</li> | ||
| 96 | {% endfor %} | ||
| 97 | </ul> | ||
| 98 | </dd> | ||
| 99 | </dl> | ||
| 100 | </div> | ||
| 101 | {% endif %} | ||
| 102 | {% endfor %} | ||
| 103 | {% endif %} | ||
| 65 | </div> | 104 | </div> |
| 66 | 105 | ||
| 67 | {%else%} | 106 | {%else%} |
| @@ -75,24 +114,32 @@ | |||
| 75 | <h4><a href="{%url 'configuration' build.pk%}">Configuration</a></h4> | 114 | <h4><a href="{%url 'configuration' build.pk%}">Configuration</a></h4> |
| 76 | <dl> | 115 | <dl> |
| 77 | <dt>Machine</dt><dd>{{build.machine}}</dd> | 116 | <dt>Machine</dt><dd>{{build.machine}}</dd> |
| 78 | <dt>Distro</dt><dd></dd> | 117 | <dt>Distro</dt><dd>{{build.distro}}</dd> |
| 79 | <dt>Layers</dt>{% for i in build.layer_version_build.all %}<dd>{{i.layer.name}}</dd>{%endfor%} | 118 | <dt>Layers</dt>{% for i in build.layer_version_build.all|dictsort:"layer.name" %}<dd>{{i.layer.name}}</dd>{%endfor%} |
| 80 | </dl> | 119 | </dl> |
| 81 | </div> | 120 | </div> |
| 82 | <div class="well span4" style="background-color:transparent;"> | 121 | <div class="well span4" style="background-color:transparent;"> |
| 83 | <h4><a href="{%url 'tasks' build.pk%}">Tasks</a></h4> | 122 | <h4><a href="{%url 'tasks' build.pk%}">Tasks</a></h4> |
| 84 | <dl> | 123 | <dl> |
| 85 | <dt>Total number of tasks</dt><dd>{{build.task_build.all.count}}</dd> | 124 | <dt>Total number of tasks</dt><dd><a href="{% url 'tasks' build.pk %}">{{build.task_build.all.count}}</a></dd> |
| 86 | <dt>Tasks executed</dt><dd>{% query build.task_build task_executed=1 order__gt=0 as exectask%}{{exectask.count}}</dd> | 125 | <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> |
| 87 | <dt>Tasks prebuilt</dt><dd>{% query build.task_build task_executed=0 order__gt=0 as noexectask%}{{noexectask.count}}</dd> | 126 | <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> |
| 88 | <dt>Reuse</dt><dd>{% query build.task_build order__gt=0 as texec %}{{noexectask.count|multiply:100|divide:texec.count}}%</dd> | 127 | <dt>Reuse</dt><dd> |
| 128 | {% query build.task_build order__gt=0 as texec %} | ||
| 129 | {% if noexectask.count|multiply:100|divide:texec.count < 0 %} | ||
| 130 | 0 | ||
| 131 | {% else %} | ||
| 132 | {{noexectask.count|multiply:100|divide:texec.count}} | ||
| 133 | {% endif %} | ||
| 134 | % | ||
| 135 | </dd> | ||
| 89 | </dl> | 136 | </dl> |
| 90 | </div> | 137 | </div> |
| 91 | <div class="well span4" style="background-color:transparent;"> | 138 | <div class="well span4" style="background-color:transparent;"> |
| 92 | <h4><a href="{% url 'recipes' build.pk %}">Recipes</a> & <a href="{% url 'packages' build.pk %}">Packages</a></h4> | 139 | <h4><a href="{% url 'recipes' build.pk %}">Recipes</a> & <a href="{% url 'packages' build.pk %}">Packages</a></h4> |
| 93 | <dl> | 140 | <dl> |
| 94 | <dt>Recipes used</dt><dd>{{recipecount}}</dd> | 141 | <dt>Recipes built</dt><dd><a href="{% url 'recipes' build.pk %}">{{recipecount}}</a></dd> |
| 95 | <dt>Packages built</dt><dd>{{build.package_set.all.count}}</dd> | 142 | <dt>Packages built</dt><dd><a href="{% url 'packages' build.pk %}">{{build.package_set.all.count}}</a></dd> |
| 96 | </dl> | 143 | </dl> |
| 97 | </div> | 144 | </div> |
| 98 | </div> | 145 | </div> |
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py index d1234fe804..4f31ddb4bf 100644 --- a/bitbake/lib/toaster/toastergui/views.py +++ b/bitbake/lib/toaster/toastergui/views.py | |||
| @@ -25,7 +25,7 @@ from django.db.models import Q, Sum | |||
| 25 | from django.shortcuts import render, redirect | 25 | from django.shortcuts import render, redirect |
| 26 | from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable | 26 | from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable |
| 27 | from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency | 27 | from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency |
| 28 | from orm.models import Target_Installed_Package, Target_File | 28 | from orm.models import Target_Installed_Package, Target_Image_File |
| 29 | from django.views.decorators.cache import cache_control | 29 | from django.views.decorators.cache import cache_control |
| 30 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger | 30 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger |
| 31 | from django.http import HttpResponseBadRequest | 31 | from django.http import HttpResponseBadRequest |
| @@ -350,18 +350,59 @@ def builds(request): | |||
| 350 | return render(request, template, context) | 350 | return render(request, template, context) |
| 351 | 351 | ||
| 352 | 352 | ||
| 353 | ## | ||
| 353 | # build dashboard for a single build, coming in as argument | 354 | # build dashboard for a single build, coming in as argument |
| 355 | # Each build may contain multiple targets and each target | ||
| 356 | # may generate multiple image files. display them all. | ||
| 357 | # | ||
| 354 | def builddashboard(request, build_id): | 358 | def builddashboard(request, build_id): |
| 355 | template = "builddashboard.html" | 359 | template = "builddashboard.html" |
| 356 | if Build.objects.filter(pk=build_id).count() == 0 : | 360 | if Build.objects.filter(pk=build_id).count() == 0 : |
| 357 | return redirect(builds) | 361 | return redirect(builds) |
| 362 | build = Build.objects.filter(pk = build_id)[0]; | ||
| 363 | layerVersionId = Layer_Version.objects.filter( build = build_id ); | ||
| 364 | recipeCount = Recipe.objects.filter( layer_version__id__in = layerVersionId ).count( ); | ||
| 365 | tgts = Target.objects.filter( build_id = build_id ).order_by( 'target' ); | ||
| 366 | |||
| 367 | # set up custom target list with computed package and image data | ||
| 368 | targets = [ ]; | ||
| 369 | ntargets = 0; | ||
| 370 | hasImages = False; | ||
| 371 | for t in tgts: | ||
| 372 | elem = { }; | ||
| 373 | elem[ 'target' ] = t; | ||
| 374 | if ( t.is_image ): | ||
| 375 | hasImages = True; | ||
| 376 | npkg = 0; | ||
| 377 | pkgsz = 0; | ||
| 378 | pid= 0; | ||
| 379 | tp = Target_Installed_Package.objects.filter( target_id = t.id ); | ||
| 380 | package = None; | ||
| 381 | for p in tp: | ||
| 382 | pid = p.package_id; | ||
| 383 | package = Package.objects.get( pk = p.package_id ) | ||
| 384 | pkgsz = pkgsz + package.size; | ||
| 385 | npkg = npkg + 1; | ||
| 386 | elem[ 'npkg' ] = npkg; | ||
| 387 | elem[ 'pkgsz' ] = pkgsz; | ||
| 388 | ti = Target_Image_File.objects.filter( target_id = t.id ); | ||
| 389 | imageFiles = [ ]; | ||
| 390 | for i in ti: | ||
| 391 | imageFiles.append({ 'path': i.file_name, 'size' : i.file_size }); | ||
| 392 | elem[ 'imageFiles' ] = imageFiles; | ||
| 393 | targets.append( elem ); | ||
| 394 | |||
| 358 | context = { | 395 | context = { |
| 359 | 'build' : Build.objects.filter(pk=build_id)[0], | 396 | 'build' : build, |
| 360 | 'recipecount' : Recipe.objects.filter(layer_version__id__in=Layer_Version.objects.filter(build=build_id)).count(), | 397 | 'hasImages' : hasImages, |
| 361 | 'logmessages' : LogMessage.objects.filter(build=build_id), | 398 | 'ntargets' : ntargets, |
| 399 | 'targets' : targets, | ||
| 400 | 'recipecount' : recipeCount, | ||
| 401 | 'logmessages' : LogMessage.objects.filter(build=build_id), | ||
| 362 | } | 402 | } |
| 363 | return render(request, template, context) | 403 | return render(request, template, context) |
| 364 | 404 | ||
| 405 | |||
| 365 | def task(request, build_id, task_id): | 406 | def task(request, build_id, task_id): |
| 366 | template = "task.html" | 407 | template = "task.html" |
| 367 | if Task.objects.filter(pk=task_id).count() == 0 : | 408 | if Task.objects.filter(pk=task_id).count() == 0 : |
