summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/toastergui/api.py
diff options
context:
space:
mode:
authorElliot Smith <elliot.smith@intel.com>2016-06-29 15:41:56 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-08-11 00:09:26 +0100
commit952ffb3e1f4a00793e0c9c49bc0c8fb8729424c4 (patch)
tree604083d9477c9d3d2f51c714fe3b74ac8196f26c /bitbake/lib/toaster/toastergui/api.py
parentc471740f5ba023dccc992438c75f1534950d26af (diff)
downloadpoky-952ffb3e1f4a00793e0c9c49bc0c8fb8729424c4.tar.gz
bitbake: toaster: move most recent builds templating to client
The most recent builds area of the all builds and project builds table needs to update as a build progresses. It also needs additional functionality to show other states (e.g. recipe parsing, queued) which again needs to update on the client side. Rather than add to the existing mix of server-side templating with client-side DOM updating, translate all of the server-side templates to client-side ones (jsrender), and add logic which updates the most recent builds area as the state of a build changes. Add a JSON API for mostrecentbuilds, which returns the state of all "recent" builds. Fetch this via Ajax from the build dashboard (rather than fetching the ad hoc API as in the previous version). Then, as new states for builds are fetched via Ajax, determine whether the build state has changed completely, or whether the progress has just updated. If the state completely changed, re-render the template on the client side for that build. If only the progress changed, just update the progress bar. (NB this fixes the task progress bar so it works for the project builds and all builds pages.) In cases where the builds table needs to update as the result of a build finishing, reload the whole page. This work highlighted a variety of other issues, such as build requests not being able to change state as necessary. This was one part of the cause of the "cancelling build..." state being fragile and disappearing entirely when the page refreshed. The cancelling state now persists between page reloads, as the logic for determining whether a build is cancelling is now on the Build object itself. Note that jsrender is redistributed as part of Toaster, so a note was added to LICENSE to that effect. [YOCTO #9631] (Bitbake rev: c868ea036aa34b387a72ec5116a66b2cd863995b) Signed-off-by: Elliot Smith <elliot.smith@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/toastergui/api.py')
-rw-r--r--bitbake/lib/toaster/toastergui/api.py105
1 files changed, 104 insertions, 1 deletions
diff --git a/bitbake/lib/toaster/toastergui/api.py b/bitbake/lib/toaster/toastergui/api.py
index 414afce1d0..aa3cbd83b2 100644
--- a/bitbake/lib/toaster/toastergui/api.py
+++ b/bitbake/lib/toaster/toastergui/api.py
@@ -27,7 +27,10 @@ from bldcontrol import bbcontroller
27from django.http import HttpResponse, JsonResponse 27from django.http import HttpResponse, JsonResponse
28from django.views.generic import View 28from django.views.generic import View
29from django.core.urlresolvers import reverse 29from django.core.urlresolvers import reverse
30 30from django.core import serializers
31from django.utils import timezone
32from django.template.defaultfilters import date
33from toastergui.templatetags.projecttags import json, sectohms, get_tasks
31 34
32def error_response(error): 35def error_response(error):
33 return JsonResponse({"error": error}) 36 return JsonResponse({"error": error})
@@ -208,3 +211,103 @@ class XhrLayer(View):
208 "error": "ok", 211 "error": "ok",
209 "redirect": reverse('project', args=(kwargs['pid'],)) 212 "redirect": reverse('project', args=(kwargs['pid'],))
210 }) 213 })
214
215class MostRecentBuildsView(View):
216 def _was_yesterday_or_earlier(self, completed_on):
217 now = timezone.now()
218 delta = now - completed_on
219
220 if delta.days >= 1:
221 return True
222
223 return False
224
225 def get(self, request, *args, **kwargs):
226 """
227 Returns a list of builds in JSON format.
228 """
229 mrb_type = 'all'
230 project = None
231
232 project_id = request.GET.get('project_id', None)
233 if project_id:
234 try:
235 mrb_type = 'project'
236 project = Project.objects.get(pk=project_id)
237 except:
238 # if project lookup fails, assume no project
239 pass
240
241 recent_build_objs = Build.get_recent(project)
242 recent_builds = []
243
244 # for timezone conversion
245 tz = timezone.get_current_timezone()
246
247 for build_obj in recent_build_objs:
248 dashboard_url = reverse('builddashboard', args=(build_obj.pk,))
249 buildtime_url = reverse('buildtime', args=(build_obj.pk,))
250 rebuild_url = \
251 reverse('xhr_buildrequest', args=(build_obj.project.pk,))
252 cancel_url = \
253 reverse('xhr_buildrequest', args=(build_obj.project.pk,))
254
255 build = {}
256 build['id'] = build_obj.pk
257 build['dashboard_url'] = dashboard_url
258
259 tasks_complete_percentage = 0
260 if build_obj.outcome in (Build.SUCCEEDED, Build.FAILED):
261 tasks_complete_percentage = 100
262 elif build_obj.outcome == Build.IN_PROGRESS:
263 tasks_complete_percentage = build_obj.completeper()
264 build['tasks_complete_percentage'] = tasks_complete_percentage
265
266 build['state'] = build_obj.get_state()
267
268 build['errors'] = build_obj.errors.count()
269 build['dashboard_errors_url'] = dashboard_url + '#errors'
270
271 build['warnings'] = build_obj.warnings.count()
272 build['dashboard_warnings_url'] = dashboard_url + '#warnings'
273
274 build['buildtime'] = sectohms(build_obj.timespent_seconds)
275 build['buildtime_url'] = buildtime_url
276
277 build['rebuild_url'] = rebuild_url
278 build['cancel_url'] = cancel_url
279
280 build['is_default_project_build'] = build_obj.project.is_default
281
282 build['build_targets_json'] = \
283 json(get_tasks(build_obj.target_set.all()))
284
285 # convert completed_on time to user's timezone
286 completed_on = timezone.localtime(build_obj.completed_on)
287
288 completed_on_template = '%H:%M'
289 if self._was_yesterday_or_earlier(completed_on):
290 completed_on_template = '%d/%m/%Y ' + completed_on_template
291 build['completed_on'] = completed_on.strftime(completed_on_template)
292
293 targets = []
294 target_objs = build_obj.get_sorted_target_list()
295 for target_obj in target_objs:
296 if target_obj.task:
297 targets.append(target_obj.target + ':' + target_obj.task)
298 else:
299 targets.append(target_obj.target)
300 build['targets'] = ' '.join(targets)
301
302 # abbreviated form of the full target list
303 abbreviated_targets = ''
304 num_targets = len(targets)
305 if num_targets > 0:
306 abbreviated_targets = targets[0]
307 if num_targets > 1:
308 abbreviated_targets += (' +%s' % (num_targets - 1))
309 build['targets_abbreviated'] = abbreviated_targets
310
311 recent_builds.append(build)
312
313 return JsonResponse(recent_builds, safe=False)