summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui/widgets.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/toastergui/widgets.py')
-rw-r--r--bitbake/lib/toaster/toastergui/widgets.py141
1 files changed, 125 insertions, 16 deletions
diff --git a/bitbake/lib/toaster/toastergui/widgets.py b/bitbake/lib/toaster/toastergui/widgets.py
index 005a5620db..026903d35d 100644
--- a/bitbake/lib/toaster/toastergui/widgets.py
+++ b/bitbake/lib/toaster/toastergui/widgets.py
@@ -22,23 +22,24 @@
22from django.views.generic import View, TemplateView 22from django.views.generic import View, TemplateView
23from django.views.decorators.cache import cache_control 23from django.views.decorators.cache import cache_control
24from django.shortcuts import HttpResponse 24from django.shortcuts import HttpResponse
25from django.http import HttpResponseBadRequest
26from django.core import serializers
27from django.core.cache import cache 25from django.core.cache import cache
28from django.core.paginator import Paginator, EmptyPage 26from django.core.paginator import Paginator, EmptyPage
29from django.db.models import Q 27from django.db.models import Q
30from orm.models import Project, ProjectLayer, Layer_Version 28from orm.models import Project, Build
31from django.template import Context, Template 29from django.template import Context, Template
32from django.template import VariableDoesNotExist 30from django.template import VariableDoesNotExist
33from django.template import TemplateSyntaxError 31from django.template import TemplateSyntaxError
34from django.core.serializers.json import DjangoJSONEncoder 32from django.core.serializers.json import DjangoJSONEncoder
35from django.core.exceptions import FieldError 33from django.core.exceptions import FieldError
36from django.conf.urls import url, patterns 34from django.utils import timezone
35from toastergui.templatetags.projecttags import sectohms, get_tasks
36from toastergui.templatetags.projecttags import json as template_json
37from django.http import JsonResponse
38from django.core.urlresolvers import reverse
37 39
38import types 40import types
39import json 41import json
40import collections 42import collections
41import operator
42import re 43import re
43 44
44try: 45try:
@@ -55,6 +56,7 @@ from toastergui.tablefilter import TableFilterMap
55class NoFieldOrDataName(Exception): 56class NoFieldOrDataName(Exception):
56 pass 57 pass
57 58
59
58class ToasterTable(TemplateView): 60class ToasterTable(TemplateView):
59 def __init__(self, *args, **kwargs): 61 def __init__(self, *args, **kwargs):
60 super(ToasterTable, self).__init__() 62 super(ToasterTable, self).__init__()
@@ -81,7 +83,7 @@ class ToasterTable(TemplateView):
81 def get_context_data(self, **kwargs): 83 def get_context_data(self, **kwargs):
82 context = super(ToasterTable, self).get_context_data(**kwargs) 84 context = super(ToasterTable, self).get_context_data(**kwargs)
83 context['title'] = self.title 85 context['title'] = self.title
84 context['table_name'] = type(self).__name__.lower() 86 context['table_name'] = type(self).__name__.lower()
85 context['empty_state'] = self.empty_state 87 context['empty_state'] = self.empty_state
86 88
87 return context 89 return context
@@ -406,7 +408,6 @@ class ToasterTable(TemplateView):
406 return data 408 return data
407 409
408 410
409
410class ToasterTypeAhead(View): 411class ToasterTypeAhead(View):
411 """ A typeahead mechanism to support the front end typeahead widgets """ 412 """ A typeahead mechanism to support the front end typeahead widgets """
412 MAX_RESULTS = 6 413 MAX_RESULTS = 6
@@ -427,34 +428,142 @@ class ToasterTypeAhead(View):
427 error = "ok" 428 error = "ok"
428 429
429 search_term = request.GET.get("search", None) 430 search_term = request.GET.get("search", None)
430 if search_term == None: 431 if search_term is None:
431 # We got no search value so return empty reponse 432 # We got no search value so return empty reponse
432 return response({'error' : error , 'results': []}) 433 return response({'error': error, 'results': []})
433 434
434 try: 435 try:
435 prj = Project.objects.get(pk=kwargs['pid']) 436 prj = Project.objects.get(pk=kwargs['pid'])
436 except KeyError: 437 except KeyError:
437 prj = None 438 prj = None
438 439
439 results = self.apply_search(search_term, prj, request)[:ToasterTypeAhead.MAX_RESULTS] 440 results = self.apply_search(search_term,
441 prj,
442 request)[:ToasterTypeAhead.MAX_RESULTS]
440 443
441 if len(results) > 0: 444 if len(results) > 0:
442 try: 445 try:
443 self.validate_fields(results[0]) 446 self.validate_fields(results[0])
444 except MissingFieldsException as e: 447 except self.MissingFieldsException as e:
445 error = e 448 error = e
446 449
447 data = { 'results' : results, 450 data = {'results': results,
448 'error' : error, 451 'error': error}
449 }
450 452
451 return response(data) 453 return response(data)
452 454
453 def validate_fields(self, result): 455 def validate_fields(self, result):
454 if 'name' in result == False or 'detail' in result == False: 456 if 'name' in result is False or 'detail' in result is False:
455 raise MissingFieldsException("name and detail are required fields") 457 raise self.MissingFieldsException(
458 "name and detail are required fields")
456 459
457 def apply_search(self, search_term, prj): 460 def apply_search(self, search_term, prj):
458 """ Override this function to implement search. Return an array of 461 """ Override this function to implement search. Return an array of
459 dictionaries with a minium of a name and detail field""" 462 dictionaries with a minium of a name and detail field"""
460 pass 463 pass
464
465
466class MostRecentBuildsView(View):
467 def _was_yesterday_or_earlier(self, completed_on):
468 now = timezone.now()
469 delta = now - completed_on
470
471 if delta.days >= 1:
472 return True
473
474 return False
475
476 def get(self, request, *args, **kwargs):
477 """
478 Returns a list of builds in JSON format.
479 """
480 project = None
481
482 project_id = request.GET.get('project_id', None)
483 if project_id:
484 try:
485 project = Project.objects.get(pk=project_id)
486 except:
487 # if project lookup fails, assume no project
488 pass
489
490 recent_build_objs = Build.get_recent(project)
491 recent_builds = []
492
493 for build_obj in recent_build_objs:
494 dashboard_url = reverse('builddashboard', args=(build_obj.pk,))
495 buildtime_url = reverse('buildtime', args=(build_obj.pk,))
496 rebuild_url = \
497 reverse('xhr_buildrequest', args=(build_obj.project.pk,))
498 cancel_url = \
499 reverse('xhr_buildrequest', args=(build_obj.project.pk,))
500
501 build = {}
502 build['id'] = build_obj.pk
503 build['dashboard_url'] = dashboard_url
504
505 buildrequest_id = None
506 if hasattr(build_obj, 'buildrequest'):
507 buildrequest_id = build_obj.buildrequest.pk
508 build['buildrequest_id'] = buildrequest_id
509
510 build['recipes_parsed_percentage'] = \
511 int((build_obj.recipes_parsed /
512 build_obj.recipes_to_parse) * 100)
513
514 tasks_complete_percentage = 0
515 if build_obj.outcome in (Build.SUCCEEDED, Build.FAILED):
516 tasks_complete_percentage = 100
517 elif build_obj.outcome == Build.IN_PROGRESS:
518 tasks_complete_percentage = build_obj.completeper()
519 build['tasks_complete_percentage'] = tasks_complete_percentage
520
521 build['state'] = build_obj.get_state()
522
523 build['errors'] = build_obj.errors.count()
524 build['dashboard_errors_url'] = dashboard_url + '#errors'
525
526 build['warnings'] = build_obj.warnings.count()
527 build['dashboard_warnings_url'] = dashboard_url + '#warnings'
528
529 build['buildtime'] = sectohms(build_obj.timespent_seconds)
530 build['buildtime_url'] = buildtime_url
531
532 build['rebuild_url'] = rebuild_url
533 build['cancel_url'] = cancel_url
534
535 build['is_default_project_build'] = build_obj.project.is_default
536
537 build['build_targets_json'] = \
538 template_json(get_tasks(build_obj.target_set.all()))
539
540 # convert completed_on time to user's timezone
541 completed_on = timezone.localtime(build_obj.completed_on)
542
543 completed_on_template = '%H:%M'
544 if self._was_yesterday_or_earlier(completed_on):
545 completed_on_template = '%d/%m/%Y ' + completed_on_template
546 build['completed_on'] = completed_on.strftime(
547 completed_on_template)
548
549 targets = []
550 target_objs = build_obj.get_sorted_target_list()
551 for target_obj in target_objs:
552 if target_obj.task:
553 targets.append(target_obj.target + ':' + target_obj.task)
554 else:
555 targets.append(target_obj.target)
556 build['targets'] = ' '.join(targets)
557
558 # abbreviated form of the full target list
559 abbreviated_targets = ''
560 num_targets = len(targets)
561 if num_targets > 0:
562 abbreviated_targets = targets[0]
563 if num_targets > 1:
564 abbreviated_targets += (' +%s' % (num_targets - 1))
565 build['targets_abbreviated'] = abbreviated_targets
566
567 recent_builds.append(build)
568
569 return JsonResponse(recent_builds, safe=False)