aboutsummaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorElliot Smith <elliot.smith@intel.com>2016-01-15 13:00:55 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-01-15 16:30:00 +0000
commiteaae82a19acaf786b866043ea80107f28e8206b2 (patch)
tree4e5edd8d7f044755ae76ae67bd1d473431448a3c /bitbake
parent33b011c1589519db8176c9f5a4abb540698902e6 (diff)
downloadopenembedded-core-contrib-eaae82a19acaf786b866043ea80107f28e8206b2.tar.gz
bitbake: toastergui: convert project builds page to ToasterTable
Use the all builds ToasterTable as the basis for the project builds ToasterTable. [YOCTO #8738] (Bitbake rev: 87bcfb740dd2d9944e35a2a1f71cbf8ff3b266e9) Signed-off-by: Elliot Smith <elliot.smith@intel.com> Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projecttopbar.js9
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/table.js13
-rw-r--r--bitbake/lib/toaster/toastergui/tables.py184
-rw-r--r--bitbake/lib/toaster/toastergui/templates/baseprojectpage.html1
-rw-r--r--bitbake/lib/toaster/toastergui/templates/mrb_section.html2
-rw-r--r--bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html56
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py6
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py16
-rw-r--r--bitbake/lib/toaster/toastergui/widgets.py1
9 files changed, 239 insertions, 49 deletions
diff --git a/bitbake/lib/toaster/toastergui/static/js/projecttopbar.js b/bitbake/lib/toaster/toastergui/static/js/projecttopbar.js
index b6ad380c19..58a32a056e 100644
--- a/bitbake/lib/toaster/toastergui/static/js/projecttopbar.js
+++ b/bitbake/lib/toaster/toastergui/static/js/projecttopbar.js
@@ -7,7 +7,10 @@ function projectTopBarInit(ctx) {
var projectName = $("#project-name");
var projectNameFormToggle = $("#project-change-form-toggle");
var projectNameChangeCancel = $("#project-name-change-cancel");
+
+ // this doesn't exist for command-line builds
var newBuildTargetInput = $("#build-input");
+
var newBuildTargetBuildBtn = $("#build-button");
var selectedTarget;
@@ -42,6 +45,12 @@ function projectTopBarInit(ctx) {
$(this).parent().removeClass('active');
});
+ if (!newBuildTargetInput.length) {
+ return;
+ }
+
+ /* the following only applies for non-command-line projects */
+
/* Recipe build input functionality */
if (ctx.numProjectLayers > 0 && ctx.machine){
newBuildTargetInput.removeAttr("disabled");
diff --git a/bitbake/lib/toaster/toastergui/static/js/table.js b/bitbake/lib/toaster/toastergui/static/js/table.js
index afe16b5e1b..7ac4ed5859 100644
--- a/bitbake/lib/toaster/toastergui/static/js/table.js
+++ b/bitbake/lib/toaster/toastergui/static/js/table.js
@@ -33,6 +33,10 @@ function tableInit(ctx){
loadData(tableParams);
+ // clicking on this set of elements removes the search
+ var clearSearchElements = $('.remove-search-btn-'+ctx.tableName +
+ ', .show-all-'+ctx.tableName);
+
function loadData(tableParams){
$.ajax({
type: "GET",
@@ -62,9 +66,9 @@ function tableInit(ctx){
paginationBtns.html("");
if (tableParams.search)
- $('.remove-search-btn-'+ctx.tableName).show();
+ clearSearchElements.show();
else
- $('.remove-search-btn-'+ctx.tableName).hide();
+ clearSearchElements.hide();
$('.table-count-' + ctx.tableName).text(tableData.total);
tableTotal = tableData.total;
@@ -230,9 +234,8 @@ function tableInit(ctx){
} else {
/* Not orderable */
- header.addClass("muted");
header.css("font-weight", "normal");
- header.append(col.title+' ');
+ header.append('<span class="muted">' + col.title + '</span> ');
}
/* Setup the filter button */
@@ -665,7 +668,7 @@ function tableInit(ctx){
loadData(tableParams);
});
- $('.remove-search-btn-'+ctx.tableName).click(function(e){
+ clearSearchElements.click(function(e){
e.preventDefault();
tableParams.page = 1;
diff --git a/bitbake/lib/toaster/toastergui/tables.py b/bitbake/lib/toaster/toastergui/tables.py
index 58abe36b05..d0ed49625d 100644
--- a/bitbake/lib/toaster/toastergui/tables.py
+++ b/bitbake/lib/toaster/toastergui/tables.py
@@ -23,9 +23,11 @@ from toastergui.widgets import ToasterTable
from toastergui.querysetfilter import QuerysetFilter
from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project
from orm.models import CustomImageRecipe, Package, Build, LogMessage, Task
+from orm.models import ProjectTarget
from django.db.models import Q, Max, Count
from django.conf.urls import url
-from django.core.urlresolvers import reverse
+from django.core.urlresolvers import reverse, resolve
+from django.http import HttpResponse
from django.views.generic import TemplateView
import itertools
@@ -775,7 +777,7 @@ class ProjectsTable(ToasterTable):
'''
errors_template = '''
- {% if data.get_number_of_builds > 0 %}
+ {% if data.get_number_of_builds > 0 and data.get_last_errors > 0 %}
<a class="errors.count error"
href="{% url "builddashboard" data.get_last_build_id %}#errors">
{{data.get_last_errors}} error{{data.get_last_errors | pluralize}}
@@ -784,7 +786,7 @@ class ProjectsTable(ToasterTable):
'''
warnings_template = '''
- {% if data.get_number_of_builds > 0 %}
+ {% if data.get_number_of_builds > 0 and data.get_last_warnings > 0 %}
<a class="warnings.count warning"
href="{% url "builddashboard" data.get_last_build_id %}#warnings">
{{data.get_last_warnings}} warning{{data.get_last_warnings | pluralize}}
@@ -886,30 +888,45 @@ class BuildsTable(ToasterTable):
def __init__(self, *args, **kwargs):
super(BuildsTable, self).__init__(*args, **kwargs)
self.default_orderby = '-completed_on'
- self.title = 'All builds'
self.static_context_extra['Build'] = Build
self.static_context_extra['Task'] = Task
+ # attributes that are overridden in subclasses
+
+ # title for the page
+ self.title = ''
+
+ # 'project' or 'all'; determines how the mrb (most recent builds)
+ # section is displayed
+ self.mrb_type = ''
+
+ def get_builds(self):
+ """
+ overridden in ProjectBuildsTable to return builds for a
+ single project
+ """
+ return Build.objects.all()
+
def get_context_data(self, **kwargs):
context = super(BuildsTable, self).get_context_data(**kwargs)
# for the latest builds section
- queryset = Build.objects.all()
+ builds = self.get_builds()
finished_criteria = Q(outcome=Build.SUCCEEDED) | Q(outcome=Build.FAILED)
latest_builds = itertools.chain(
- queryset.filter(outcome=Build.IN_PROGRESS).order_by("-started_on"),
- queryset.filter(finished_criteria).order_by("-completed_on")[:3]
+ builds.filter(outcome=Build.IN_PROGRESS).order_by("-started_on"),
+ builds.filter(finished_criteria).order_by("-completed_on")[:3]
)
context['mru'] = list(latest_builds)
- context['mrb_type'] = 'all'
+ context['mrb_type'] = self.mrb_type
return context
def setup_queryset(self, *args, **kwargs):
- queryset = Build.objects.all()
+ queryset = self.get_builds()
# don't include in progress builds
queryset = queryset.exclude(outcome=Build.IN_PROGRESS)
@@ -949,7 +966,8 @@ class BuildsTable(ToasterTable):
{% if data.cooker_log_path %}
&nbsp;
<a href="{% url "build_artifact" data.id "cookerlog" data.id %}">
- <i class="icon-download-alt" title="Download build log"></i>
+ <i class="icon-download-alt get-help"
+ data-original-title="Download build log"></i>
</a>
{% endif %}
'''
@@ -1031,19 +1049,6 @@ class BuildsTable(ToasterTable):
{% endif %}
'''
- project_template = '''
- {% load project_url_tag %}
- <a href="{% project_url data.project %}">
- {{data.project.name}}
- </a>
- {% if data.project.is_default %}
- <i class="icon-question-sign get-help hover-help" title=""
- data-original-title="This project shows information about
- the builds you start from the command line while Toaster is
- running" style="visibility: hidden;"></i>
- {% endif %}
- '''
-
self.add_column(title='Outcome',
help_text='Final state of the build (successful \
or failed)',
@@ -1098,16 +1103,16 @@ class BuildsTable(ToasterTable):
help_text='The number of errors encountered during \
the build (if any)',
hideable=True,
- orderable=False,
- static_data_name='errors',
+ orderable=True,
+ static_data_name='errors_no',
static_data_template=errors_template)
self.add_column(title='Warnings',
help_text='The number of warnings encountered during \
the build (if any)',
hideable=True,
- orderable=False,
- static_data_name='warnings',
+ orderable=True,
+ static_data_name='warnings_no',
static_data_template=warnings_template)
self.add_column(title='Time',
@@ -1125,12 +1130,6 @@ class BuildsTable(ToasterTable):
static_data_name='image_files',
static_data_template=image_files_template)
- self.add_column(title='Project',
- hideable=True,
- orderable=False,
- static_data_name='project-name',
- static_data_template=project_template)
-
def setup_filters(self, *args, **kwargs):
# outcomes
outcome_filter = TableFilter(
@@ -1239,3 +1238,122 @@ class BuildsTable(ToasterTable):
failed_tasks_filter.add_action(with_failed_tasks_action)
failed_tasks_filter.add_action(without_failed_tasks_action)
self.add_filter(failed_tasks_filter)
+
+ def post(self, request, *args, **kwargs):
+ """ Process HTTP POSTs which make build requests """
+
+ project = Project.objects.get(pk=kwargs['pid'])
+
+ if 'buildCancel' in request.POST:
+ for i in request.POST['buildCancel'].strip().split(" "):
+ try:
+ br = BuildRequest.objects.select_for_update().get(project = project, pk = i, state__lte = BuildRequest.REQ_QUEUED)
+ br.state = BuildRequest.REQ_DELETED
+ br.save()
+ except BuildRequest.DoesNotExist:
+ pass
+
+ if 'buildDelete' in request.POST:
+ for i in request.POST['buildDelete'].strip().split(" "):
+ try:
+ BuildRequest.objects.select_for_update().get(project = project, pk = i, state__lte = BuildRequest.REQ_DELETED).delete()
+ except BuildRequest.DoesNotExist:
+ pass
+
+ if 'targets' in request.POST:
+ ProjectTarget.objects.filter(project = project).delete()
+ s = str(request.POST['targets'])
+ for t in s.translate(None, ";%|\"").split(" "):
+ if ":" in t:
+ target, task = t.split(":")
+ else:
+ target = t
+ task = ""
+ ProjectTarget.objects.create(project = project,
+ target = target,
+ task = task)
+ project.schedule_build()
+
+ # redirect back to builds page so any new builds in progress etc.
+ # are visible
+ response = HttpResponse()
+ response.status_code = 302
+ response['Location'] = request.build_absolute_uri()
+ return response
+
+class AllBuildsTable(BuildsTable):
+ """ Builds page for all builds """
+
+ def __init__(self, *args, **kwargs):
+ super(AllBuildsTable, self).__init__(*args, **kwargs)
+ self.title = 'All builds'
+ self.mrb_type = 'all'
+
+ def setup_columns(self, *args, **kwargs):
+ """
+ All builds page shows a column for the project
+ """
+
+ super(AllBuildsTable, self).setup_columns(*args, **kwargs)
+
+ project_template = '''
+ {% load project_url_tag %}
+ <a href="{% project_url data.project %}">
+ {{data.project.name}}
+ </a>
+ {% if data.project.is_default %}
+ <i class="icon-question-sign get-help hover-help" title=""
+ data-original-title="This project shows information about
+ the builds you start from the command line while Toaster is
+ running" style="visibility: hidden;"></i>
+ {% endif %}
+ '''
+
+ self.add_column(title='Project',
+ hideable=True,
+ orderable=True,
+ static_data_name='project',
+ static_data_template=project_template)
+
+class ProjectBuildsTable(BuildsTable):
+ """
+ Builds page for a single project; a BuildsTable, with the queryset
+ filtered by project
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(ProjectBuildsTable, self).__init__(*args, **kwargs)
+ self.title = 'All project builds'
+ self.mrb_type = 'project'
+
+ # set from the querystring
+ self.project_id = None
+
+ def setup_queryset(self, *args, **kwargs):
+ """
+ NOTE: self.project_id must be set before calling super(),
+ as it's used in setup_queryset()
+ """
+ self.project_id = kwargs['pid']
+ super(ProjectBuildsTable, self).setup_queryset(*args, **kwargs)
+
+ project = Project.objects.get(pk=self.project_id)
+ self.queryset = self.queryset.filter(project=project)
+
+ def get_context_data(self, **kwargs):
+ """
+ NOTE: self.project_id must be set before calling super(),
+ as it's used in get_context_data()
+ """
+ self.project_id = kwargs['pid']
+
+ context = super(ProjectBuildsTable, self).get_context_data(**kwargs)
+ context['project'] = Project.objects.get(pk=self.project_id)
+
+ return context
+
+ def get_builds(self):
+ """ override: only return builds for the relevant project """
+
+ project = Project.objects.get(pk=self.project_id)
+ return Build.objects.filter(project=project)
diff --git a/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html b/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html
index 1f45be462d..b143b78833 100644
--- a/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html
+++ b/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html
@@ -1,4 +1,5 @@
{% extends "base.html" %}
+
{% load projecttags %}
{% load humanize %}
diff --git a/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
index 52b3f1a7d3..2f4820c3e7 100644
--- a/bitbake/lib/toaster/toastergui/templates/mrb_section.html
+++ b/bitbake/lib/toaster/toastergui/templates/mrb_section.html
@@ -6,7 +6,7 @@
{%if mru and mru.count > 0%}
{%if mrb_type == 'project' %}
- <h2>
+ <h2 class="page-header">
Latest project builds
{% if project.is_default %}
diff --git a/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html b/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html
new file mode 100644
index 0000000000..6d7e10bac5
--- /dev/null
+++ b/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html
@@ -0,0 +1,56 @@
+{% extends 'base.html' %}
+
+{% load static %}
+
+{% block extraheadcontent %}
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.structure.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.theme.min.css' %}" type='text/css'>
+ <script src="{% static 'js/jquery-ui.min.js' %}">
+ </script>
+{% endblock %}
+
+{% block title %} {{title}} - {{project.name}} - Toaster {% endblock %}
+
+{% block pagecontent %}
+
+ {% include "projecttopbar.html" %}
+
+ <div class="row-fluid">
+ {% with mru=mru mrb_type=mrb_type %}
+ {% include 'mrb_section.html' %}
+ {% endwith %}
+
+ <h2 class="page-header top-air" data-role="page-title"></h2>
+
+ {% url 'projectbuilds' project.id as xhr_table_url %}
+ {% include 'toastertable.html' %}
+ </div>
+
+ <script>
+ $(document).ready(function () {
+ // title
+ var tableElt = $("#{{table_name}}");
+ var titleElt = $("[data-role='page-title']");
+
+ tableElt.on("table-done", function (e, total, tableParams) {
+ var title = "All project builds";
+
+ if (tableParams.search || tableParams.filter) {
+ if (total === 0) {
+ title = "No project builds found";
+ }
+ else if (total > 0) {
+ title = total + " project build" + (total > 1 ? 's' : '') + " found";
+ }
+ }
+
+ titleElt.text(title);
+ });
+
+ // highlight builds tab
+ $("#topbar-builds-tab").addClass("active")
+ });
+ </script>
+
+{% endblock %}
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py
index 707b7d5f20..c8c1c6a1fe 100644
--- a/bitbake/lib/toaster/toastergui/urls.py
+++ b/bitbake/lib/toaster/toastergui/urls.py
@@ -28,7 +28,7 @@ urlpatterns = patterns('toastergui.views',
url(r'^landing/$', 'landing', name='landing'),
url(r'^builds/$',
- tables.BuildsTable.as_view(template_name="builds-toastertable.html"),
+ tables.AllBuildsTable.as_view(template_name="builds-toastertable.html"),
name='all-builds'),
# build info navigation
@@ -83,7 +83,9 @@ urlpatterns = patterns('toastergui.views',
url(r'^project/(?P<pid>\d+)/$', 'project', name='project'),
url(r'^project/(?P<pid>\d+)/configuration$', 'projectconf', name='projectconf'),
- url(r'^project/(?P<pid>\d+)/builds/$', 'projectbuilds', name='projectbuilds'),
+ url(r'^project/(?P<pid>\d+)/builds/$',
+ tables.ProjectBuildsTable.as_view(template_name="projectbuilds-toastertable.html"),
+ name='projectbuilds'),
# the import layer is a project-specific functionality;
url(r'^project/(?P<pid>\d+)/importlayer$', 'importlayer', name='importlayer'),
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 295773fc66..fbae36c69c 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -91,6 +91,7 @@ def landing(request):
return render(request, 'landing.html', context)
+"""
# returns a list for most recent builds;
def _get_latest_builds(prj=None):
queryset = Build.objects.all()
@@ -101,8 +102,9 @@ def _get_latest_builds(prj=None):
return list(itertools.chain(
queryset.filter(outcome=Build.IN_PROGRESS).order_by("-started_on"),
queryset.filter(outcome__lt=Build.IN_PROGRESS).order_by("-started_on")[:3] ))
+"""
-
+"""
# a JSON-able dict of recent builds; for use in the Project page, xhr_ updates, and other places, as needed
def _project_recent_build_list(prj):
data = []
@@ -131,8 +133,7 @@ def _project_recent_build_list(prj):
data.append(d)
return data
-
-
+"""
def objtojson(obj):
from django.db.models.query import QuerySet
@@ -1915,6 +1916,7 @@ if True:
''' The exception raised on invalid POST requests '''
pass
+ """
# helper function, to be used on "all builds" and "project builds" pages
def _build_list_helper(request, queryset_all, redirect_page, pid=None):
default_orderby = 'completed_on:-'
@@ -2119,6 +2121,7 @@ if True:
# merge daterange values
context.update(context_date)
return context, pagesize, orderby
+ """
@@ -2256,7 +2259,7 @@ if True:
"completedbuilds": Build.objects.exclude(outcome = Build.IN_PROGRESS).filter(project_id = pid),
"prj" : {"name": prj.name, },
"buildrequests" : prj.build_set.filter(outcome=Build.IN_PROGRESS),
- "builds" : _project_recent_build_list(prj),
+ #"builds" : _project_recent_build_list(prj),
"layers" : map(lambda x: {
"id": x.layercommit.pk,
"orderid": x.pk,
@@ -2827,10 +2830,8 @@ if True:
# will set the GET parameters and redirect back to the
# all-builds or projectbuilds page as appropriate;
# TODO don't use exceptions to control program flow
- @_template_renderer('projectbuilds.html')
+ """
def projectbuilds(request, pid):
- prj = Project.objects.get(id = pid)
-
if request.method == "POST":
# process any build request
@@ -2880,6 +2881,7 @@ if True:
context['mru'] = _get_latest_builds(prj)
return context
+ """
def _file_name_for_artifact(b, artifact_type, artifact_id):
diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py
index 47de30d631..bc081b818b 100644
--- a/bitbake/lib/toaster/toastergui/widgets.py
+++ b/bitbake/lib/toaster/toastergui/widgets.py
@@ -61,7 +61,6 @@ class ToasterTable(TemplateView):
self.total_count = 0
self.static_context_extra = {}
- self.filter_actions = {}
self.empty_state = "Sorry - no data found"
self.default_orderby = ""