summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorMichael Wood <michael.g.wood@intel.com>2016-09-26 13:59:28 +0300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-09-30 16:52:21 +0100
commit4d0bc8d52130fcc62c0d239fd7e0c79bec188c88 (patch)
treef7ea393ff74e8cd46c2b47626154f70481c45ed1 /bitbake
parent0b17e6d32c0f3d39fb5e58c4ff1c25afe58ce4f3 (diff)
downloadpoky-4d0bc8d52130fcc62c0d239fd7e0c79bec188c88.tar.gz
bitbake: toaster: Clean up and convert to rest api project edit and get calls
Convert the project xhr calls into proper rest api and port the client side calls to use the new API. Fix all the pyflakes identified issues and clean up unused fields. Also remove the api and client side code for changing release on the fly as this is no longer supported. [YOCTO #9519] (Bitbake rev: 8b01767d6e787cdb09789116ebf57dfb70f521bc) Signed-off-by: Michael Wood <michael.g.wood@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/api.py161
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/libtoaster.js3
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/projectpage.js147
-rw-r--r--bitbake/lib/toaster/toastergui/static/js/tests/test.js7
-rw-r--r--bitbake/lib/toaster/toastergui/templates/base.html1
-rw-r--r--bitbake/lib/toaster/toastergui/urls.py4
-rwxr-xr-xbitbake/lib/toaster/toastergui/views.py131
7 files changed, 179 insertions, 275 deletions
diff --git a/bitbake/lib/toaster/toastergui/api.py b/bitbake/lib/toaster/toastergui/api.py
index be18090daf..8876409964 100644
--- a/bitbake/lib/toaster/toastergui/api.py
+++ b/bitbake/lib/toaster/toastergui/api.py
@@ -20,11 +20,13 @@
20 20
21import re 21import re
22import logging 22import logging
23from collections import Counter
23 24
24from orm.models import Project, ProjectTarget, Build, Layer_Version 25from orm.models import Project, ProjectTarget, Build, Layer_Version
25from orm.models import LayerVersionDependency, LayerSource, ProjectLayer 26from orm.models import LayerVersionDependency, LayerSource, ProjectLayer
26from orm.models import Recipe, CustomImageRecipe, CustomImagePackage 27from orm.models import Recipe, CustomImageRecipe, CustomImagePackage
27from orm.models import Layer, Target, Package, Package_Dependency 28from orm.models import Layer, Target, Package, Package_Dependency
29from orm.models import ProjectVariable
28from bldcontrol.models import BuildRequest 30from bldcontrol.models import BuildRequest
29from bldcontrol import bbcontroller 31from bldcontrol import bbcontroller
30 32
@@ -772,3 +774,162 @@ class XhrCustomRecipePackages(View):
772 except CustomImageRecipe.DoesNotExist: 774 except CustomImageRecipe.DoesNotExist:
773 return error_response("Tried to remove package that wasn't" 775 return error_response("Tried to remove package that wasn't"
774 " present") 776 " present")
777
778
779class XhrProject(View):
780 """ Create, delete or edit a project
781
782 Entry point: /xhr_project/<project_id>
783 """
784 def post(self, request, *args, **kwargs):
785 """
786 Edit project control
787
788 Args:
789 layerAdd = layer_version_id layer_version_id ...
790 layerDel = layer_version_id layer_version_id ...
791 projectName = new_project_name
792 machineName = new_machine_name
793
794 Returns:
795 {"error": "ok"}
796 or
797 {"error": <error message>}
798 """
799 try:
800 prj = Project.objects.get(pk=kwargs['project_id'])
801 except Project.DoesNotExist:
802 return error_response("No such project")
803
804 # Add layers
805 if 'layerAdd' in request.POST and len(request.POST['layerAdd']) > 0:
806 for layer_version_id in request.POST['layerAdd'].split(','):
807 try:
808 lv = Layer_Version.objects.get(pk=int(layer_version_id))
809 ProjectLayer.objects.get_or_create(project=prj,
810 layercommit=lv)
811 except Layer_Version.DoesNotExist:
812 return error_response("Layer version %s asked to add "
813 "doesn't exist" % layer_version_id)
814
815 # Remove layers
816 if 'layerDel' in request.POST and len(request.POST['layerDel']) > 0:
817 layer_version_ids = request.POST['layerDel'].split(',')
818 ProjectLayer.objects.filter(
819 project=prj,
820 layercommit_id__in=layer_version_ids).delete()
821
822 # Project name change
823 if 'projectName' in request.POST:
824 prj.name = request.POST['projectName']
825 prj.save()
826
827 # Machine name change
828 if 'machineName' in request.POST:
829 machinevar = prj.projectvariable_set.get(name="MACHINE")
830 machinevar.value = request.POST['machineName']
831 machinevar.save()
832
833 return JsonResponse({"error": "ok"})
834
835 def get(self, request, *args, **kwargs):
836 """
837 Returns:
838 json object representing the current project
839 or:
840 {"error": <error message>}
841 """
842
843 try:
844 project = Project.objects.get(pk=kwargs['project_id'])
845 except Project.DoesNotExist:
846 return error_response("Project %s does not exist" %
847 kwargs['project_id'])
848
849 # Create the frequently built targets list
850
851 freqtargets = Counter(Target.objects.filter(
852 Q(build__project=project),
853 ~Q(build__outcome=Build.IN_PROGRESS)
854 ).order_by("target").values_list("target", flat=True))
855
856 freqtargets = freqtargets.most_common(5)
857
858 # We now have the targets in order of frequency but if there are two
859 # with the same frequency then we need to make sure those are in
860 # alphabetical order without losing the frequency ordering
861
862 tmp = []
863 switch = None
864 for i, freqtartget in enumerate(freqtargets):
865 target, count = freqtartget
866 try:
867 target_next, count_next = freqtargets[i+1]
868 if count == count_next and target > target_next:
869 switch = target
870 continue
871 except IndexError:
872 pass
873
874 tmp.append(target)
875
876 if switch:
877 tmp.append(switch)
878 switch = None
879
880 freqtargets = tmp
881
882 layers = []
883 for layer in project.projectlayer_set.all():
884 layers.append({
885 "id": layer.layercommit.pk,
886 "name": layer.layercommit.layer.name,
887 "vcs_url": layer.layercommit.layer.vcs_url,
888 "local_source_dir": layer.layercommit.layer.local_source_dir,
889 "vcs_reference": layer.layercommit.get_vcs_reference(),
890 "url": layer.layercommit.layer.layer_index_url,
891 "layerdetailurl": layer.layercommit.get_detailspage_url(
892 project.pk),
893 "layersource": layer.layercommit.layer_source
894 })
895
896 data = {
897 "name": project.name,
898 "layers": layers,
899 "freqtargets": freqtargets,
900 }
901
902 if project.release is not None:
903 data['release'] = {
904 "id": project.release.pk,
905 "name": project.release.name,
906 "description": project.release.description
907 }
908
909 try:
910 data["machine"] = {"name":
911 project.projectvariable_set.get(
912 name="MACHINE").value}
913 except ProjectVariable.DoesNotExist:
914 data["machine"] = None
915 try:
916 data["distro"] = project.projectvariable_set.get(
917 name="DISTRO").value
918 except ProjectVariable.DoesNotExist:
919 data["distro"] = "-- not set yet"
920
921 data['error'] = "ok"
922
923 return JsonResponse(data)
924
925 def put(self, request, *args, **kwargs):
926 # TODO create new project api
927 return HttpResponse()
928
929 def delete(self, request, *args, **kwargs):
930 try:
931 Project.objects.get(kwargs['project_id']).delete()
932 except Project.DoesNotExist:
933 return error_response("Project %s does not exist" %
934 kwargs['project_id'])
935 return JsonResponse({"error": "ok"})
diff --git a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
index f56affd8ea..b2099a6048 100644
--- a/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
+++ b/bitbake/lib/toaster/toastergui/static/js/libtoaster.js
@@ -167,7 +167,6 @@ var libtoaster = (function () {
167 function _getProjectInfo(url, onsuccess, onfail){ 167 function _getProjectInfo(url, onsuccess, onfail){
168 $.ajax({ 168 $.ajax({
169 type: "GET", 169 type: "GET",
170 data : { format: "json" },
171 url: url, 170 url: url,
172 headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 171 headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
173 success: function (_data) { 172 success: function (_data) {
@@ -194,7 +193,7 @@ var libtoaster = (function () {
194 function _editCurrentProject(data, onSuccess, onFail){ 193 function _editCurrentProject(data, onSuccess, onFail){
195 $.ajax({ 194 $.ajax({
196 type: "POST", 195 type: "POST",
197 url: libtoaster.ctx.projectPageUrl + "?format=json", 196 url: libtoaster.ctx.xhrProjectUrl,
198 data: data, 197 data: data,
199 headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 198 headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
200 success: function (data) { 199 success: function (data) {
diff --git a/bitbake/lib/toaster/toastergui/static/js/projectpage.js b/bitbake/lib/toaster/toastergui/static/js/projectpage.js
index b75b3e1869..3bf3cbaf2b 100644
--- a/bitbake/lib/toaster/toastergui/static/js/projectpage.js
+++ b/bitbake/lib/toaster/toastergui/static/js/projectpage.js
@@ -27,11 +27,10 @@ function projectPageInit(ctx) {
27 27
28 var urlParams = libtoaster.parseUrlParams(); 28 var urlParams = libtoaster.parseUrlParams();
29 29
30 libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ 30 libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl, function(prjInfo){
31 updateProjectLayers(prjInfo.layers); 31 updateProjectLayers(prjInfo.layers);
32 updateFreqBuildRecipes(prjInfo.freqtargets); 32 updateFreqBuildRecipes(prjInfo.freqtargets);
33 updateProjectRelease(prjInfo.release); 33 updateProjectRelease(prjInfo.release);
34 updateProjectReleases(prjInfo.releases, prjInfo.release);
35 34
36 /* If we're receiving a machine set from the url and it's different from 35 /* If we're receiving a machine set from the url and it's different from
37 * our current machine then activate set machine sequence. 36 * our current machine then activate set machine sequence.
@@ -287,7 +286,9 @@ function projectPageInit(ctx) {
287 machineNameTitle.text(machineName); 286 machineNameTitle.text(machineName);
288 } 287 }
289 288
290 libtoaster.makeTypeahead(machineChangeInput, libtoaster.ctx.machinesTypeAheadUrl, { }, function(item){ 289 libtoaster.makeTypeahead(machineChangeInput,
290 libtoaster.ctx.machinesTypeAheadUrl,
291 { }, function(item){
291 currentMachineAddSelection = item.name; 292 currentMachineAddSelection = item.name;
292 machineChangeBtn.removeAttr("disabled"); 293 machineChangeBtn.removeAttr("disabled");
293 }); 294 });
@@ -324,146 +325,10 @@ function projectPageInit(ctx) {
324 releaseTitle.text(release.description); 325 releaseTitle.text(release.description);
325 } 326 }
326 327
327 function updateProjectReleases(releases, current){
328 for (var i in releases){
329 var releaseOption = $("<option></option>");
330 328
331 releaseOption.val(releases[i].id); 329 $("#delete-project-confirmed").click(function(e){
332 releaseOption.text(releases[i].description);
333 releaseOption.data('release', releases[i]);
334
335 if (releases[i].id == current.id)
336 releaseOption.attr("selected", "selected");
337
338 releaseForm.children("select").append(releaseOption);
339 }
340 }
341
342 releaseChangeFormToggle.click(function(){
343 releaseForm.slideDown();
344 releaseTitle.hide();
345 $(this).hide();
346 });
347
348 cancelReleaseChange.click(function(e){
349 e.preventDefault(); 330 e.preventDefault();
350 releaseForm.slideUp(function(){ 331
351 releaseTitle.show();
352 releaseChangeFormToggle.show();
353 });
354 });
355
356 function changeProjectRelease(release, layersToRm){
357 libtoaster.editCurrentProject({ projectVersion : release.id },
358 function(){
359 /* Success */
360 /* Update layers list with new layers */
361 layersInPrjList.addClass('muted');
362 libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl,
363 function(prjInfo){
364 layersInPrjList.children().remove();
365 updateProjectLayers(prjInfo.layers);
366 layersInPrjList.removeClass('muted');
367 releaseChangedNotification(release, prjInfo.layers, layersToRm);
368 });
369 updateProjectRelease(release);
370 cancelReleaseChange.click();
371 });
372 }
373
374 /* Create a notification to show the changes to the layer configuration
375 * caused by changing a release.
376 */
377
378 function releaseChangedNotification(release, layers, layersToRm){
379
380 var message;
381
382 if (layers.length === 0 && layersToRm.length === 0){
383 message = $('<span><span class="lead">You have changed the project release to: <strong><span id="notify-release-name"></span></strong>.');
384 message.find("#notify-release-name").text(release.description);
385 libtoaster.showChangeNotification(message);
386 return;
387 }
388
389 /* Create the whitespace separated list of layers removed */
390 var layersDelList = "";
391
392 layersToRm.map(function(layer, i){
393 layersDelList += layer.name;
394 if (layersToRm[i+1] !== undefined)
395 layersDelList += ', ';
396 });
397
398 message = $('<span><span class="lead">You have changed the project release to: <strong><span id="notify-release-name"></span></strong>. This has caused the following changes in your project layers:</span><ul id="notify-layers-changed-list"></ul></span>');
399
400 var changedList = message.find("#notify-layers-changed-list");
401
402 message.find("#notify-release-name").text(release.description);
403
404 /* Manually construct the list item for changed layers */
405 var li = '<li><strong>'+layers.length+'</strong> layers changed to the <strong>'+release.name+'</strong> release: ';
406 for (var i in layers){
407 li += '<a href='+layers[i].layerdetailurl+'>'+layers[i].name+'</a>';
408 if (i !== 0)
409 li += ', ';
410 }
411
412 changedList.append($(li));
413
414 /* Layers removed */
415 if (layersToRm && layersToRm.length > 0){
416 if (layersToRm.length == 1)
417 li = '<li><strong>1</strong> layer removed: '+layersToRm[0].name+'</li>';
418 else
419 li = '<li><strong>'+layersToRm.length+'</strong> layers deleted: '+layersDelList+'</li>';
420
421 changedList.append($(li));
422 }
423
424 libtoaster.showChangeNotification(message);
425 }
426
427 /* Show the modal dialog which gives the option to remove layers which
428 * aren't compatible with the proposed release
429 */
430 function showReleaseLayerChangeModal(release, layers){
431 var layersToRmList = releaseModal.find("#layers-to-remove-list");
432 layersToRmList.text("");
433
434 releaseModal.find(".proposed-release-change-name").text(release.description);
435 releaseModal.data("layers", layers);
436 releaseModal.data("release", release);
437
438 for (var i in layers){
439 layersToRmList.append($("<li></li>").text(layers[i].name));
440 }
441 releaseModal.modal('show');
442 }
443
444 $("#change-release-btn").click(function(e){
445 e.preventDefault();
446
447 var newRelease = releaseForm.find("option:selected").data('release');
448
449 $.getJSON(ctx.testReleaseChangeUrl,
450 { new_release_id: newRelease.id },
451 function(layers) {
452 if (layers.rows.length === 0){
453 /* No layers to change for this release */
454 changeProjectRelease(newRelease, []);
455 } else {
456 showReleaseLayerChangeModal(newRelease, layers.rows);
457 }
458 });
459 });
460
461 /* Release change modal accept */
462 $("#change-release-and-rm-layers").click(function(){
463 var layers = releaseModal.data("layers");
464 var release = releaseModal.data("release");
465
466 changeProjectRelease(release, layers);
467 }); 332 });
468 333
469} 334}
diff --git a/bitbake/lib/toaster/toastergui/static/js/tests/test.js b/bitbake/lib/toaster/toastergui/static/js/tests/test.js
index f8d566b3e3..d7953de447 100644
--- a/bitbake/lib/toaster/toastergui/static/js/tests/test.js
+++ b/bitbake/lib/toaster/toastergui/static/js/tests/test.js
@@ -42,9 +42,8 @@ QUnit.test("Layer alert notification", function(assert) {
42 42
43QUnit.test("Project info", function(assert){ 43QUnit.test("Project info", function(assert){
44 var done = assert.async(); 44 var done = assert.async();
45 libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ 45 libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl, function(prjInfo){
46 assert.ok(prjInfo.machine.name); 46 assert.ok(prjInfo.machine.name);
47 assert.ok(prjInfo.releases.length > 0);
48 assert.ok(prjInfo.layers.length > 0); 47 assert.ok(prjInfo.layers.length > 0);
49 assert.ok(prjInfo.freqtargets); 48 assert.ok(prjInfo.freqtargets);
50 assert.ok(prjInfo.release); 49 assert.ok(prjInfo.release);
@@ -82,11 +81,11 @@ QUnit.test("Add layer", function(assert){
82 }, 200); 81 }, 200);
83 82
84 /* Compare the number of layers before and after the add in the project */ 83 /* Compare the number of layers before and after the add in the project */
85 libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, function(prjInfo){ 84 libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl, function(prjInfo){
86 var origNumLayers = prjInfo.layers.length; 85 var origNumLayers = prjInfo.layers.length;
87 86
88 libtoaster.addRmLayer(layer, true, function(deps){ 87 libtoaster.addRmLayer(layer, true, function(deps){
89 libtoaster.getProjectInfo(libtoaster.ctx.projectPageUrl, 88 libtoaster.getProjectInfo(libtoaster.ctx.xhrProjectUrl,
90 function(prjInfo){ 89 function(prjInfo){
91 assert.ok(prjInfo.layers.length > origNumLayers, 90 assert.ok(prjInfo.layers.length > origNumLayers,
92 "Layer not added to project"); 91 "Layer not added to project");
diff --git a/bitbake/lib/toaster/toastergui/templates/base.html b/bitbake/lib/toaster/toastergui/templates/base.html
index 58491eba81..c1b1417a76 100644
--- a/bitbake/lib/toaster/toastergui/templates/base.html
+++ b/bitbake/lib/toaster/toastergui/templates/base.html
@@ -44,6 +44,7 @@
44 {% if project.id %} 44 {% if project.id %}
45 projectId : {{project.id}}, 45 projectId : {{project.id}},
46 projectPageUrl : {% url 'project' project.id as purl %}{{purl|json}}, 46 projectPageUrl : {% url 'project' project.id as purl %}{{purl|json}},
47 xhrProjectUrl : {% url 'xhr_project' project.id as pxurl %}{{pxurl|json}},
47 projectName : {{project.name|json}}, 48 projectName : {{project.name|json}},
48 recipesTypeAheadUrl: {% url 'xhr_recipestypeahead' project.id as paturl%}{{paturl|json}}, 49 recipesTypeAheadUrl: {% url 'xhr_recipestypeahead' project.id as paturl%}{{paturl|json}},
49 layersTypeAheadUrl: {% url 'xhr_layerstypeahead' project.id as paturl%}{{paturl|json}}, 50 layersTypeAheadUrl: {% url 'xhr_layerstypeahead' project.id as paturl%}{{paturl|json}},
diff --git a/bitbake/lib/toaster/toastergui/urls.py b/bitbake/lib/toaster/toastergui/urls.py
index 9509cd5928..1232611e2e 100644
--- a/bitbake/lib/toaster/toastergui/urls.py
+++ b/bitbake/lib/toaster/toastergui/urls.py
@@ -220,6 +220,10 @@ urlpatterns = patterns('toastergui.views',
220 api.XhrBuildRequest.as_view(), 220 api.XhrBuildRequest.as_view(),
221 name='xhr_buildrequest'), 221 name='xhr_buildrequest'),
222 222
223 url(r'xhr_project/(?P<project_id>\d+)$',
224 api.XhrProject.as_view(),
225 name='xhr_project'),
226
223 url(r'^mostrecentbuilds$', api.MostRecentBuildsView.as_view(), 227 url(r'^mostrecentbuilds$', api.MostRecentBuildsView.as_view(),
224 name='most_recent_builds'), 228 name='most_recent_builds'),
225 229
diff --git a/bitbake/lib/toaster/toastergui/views.py b/bitbake/lib/toaster/toastergui/views.py
index 365a1e88ff..2efb0fd56c 100755
--- a/bitbake/lib/toaster/toastergui/views.py
+++ b/bitbake/lib/toaster/toastergui/views.py
@@ -1361,136 +1361,11 @@ if True:
1361 1361
1362 raise Exception("Invalid HTTP method for this page") 1362 raise Exception("Invalid HTTP method for this page")
1363 1363
1364
1365
1366 # Shows the edit project page 1364 # Shows the edit project page
1367 @_template_renderer('project.html')
1368 def project(request, pid): 1365 def project(request, pid):
1369 prj = Project.objects.get(id = pid) 1366 project = Project.objects.get(pk=pid)
1370 1367 context = {"project": project}
1371 try: 1368 return render(request, "project.html", context)
1372 puser = User.objects.get(id = prj.user_id)
1373 except User.DoesNotExist:
1374 puser = None
1375
1376 # execute POST requests
1377 if request.method == "POST":
1378 # add layers
1379 if 'layerAdd' in request.POST and len(request.POST['layerAdd']) > 0:
1380 for lc in Layer_Version.objects.filter(pk__in=[i for i in request.POST['layerAdd'].split(",") if len(i) > 0]):
1381 ProjectLayer.objects.get_or_create(project = prj, layercommit = lc)
1382
1383 # remove layers
1384 if 'layerDel' in request.POST and len(request.POST['layerDel']) > 0:
1385 for t in request.POST['layerDel'].strip().split(" "):
1386 pt = ProjectLayer.objects.filter(project = prj, layercommit_id = int(t)).delete()
1387
1388 if 'projectName' in request.POST:
1389 prj.name = request.POST['projectName']
1390 prj.save();
1391
1392 if 'projectVersion' in request.POST:
1393 # If the release is the current project then return now
1394 if prj.release.pk == int(request.POST.get('projectVersion',-1)):
1395 return {}
1396
1397 prj.release = Release.objects.get(pk = request.POST['projectVersion'])
1398 # we need to change the bitbake version
1399 prj.bitbake_version = prj.release.bitbake_version
1400 prj.save()
1401 # we need to change the layers
1402 for project in prj.projectlayer_set.all():
1403 # find and add a similarly-named layer on the new branch
1404 try:
1405 layer_versions = prj.get_all_compatible_layer_versions()
1406 layer_versions = layer_versions.filter(layer__name = project.layercommit.layer.name)
1407 ProjectLayer.objects.get_or_create(project = prj, layercommit = layer_versions.first())
1408 except IndexError:
1409 pass
1410 finally:
1411 # get rid of the old entry
1412 project.delete()
1413
1414 if 'machineName' in request.POST:
1415 machinevar = prj.projectvariable_set.get(name="MACHINE")
1416 machinevar.value=request.POST['machineName']
1417 machinevar.save()
1418
1419
1420 # we use implicit knowledge of the current user's project to filter layer information, e.g.
1421 pid = prj.id
1422
1423 from collections import Counter
1424
1425 freqtargets = Counter(Target.objects.filter(
1426 Q(build__project=prj),
1427 ~Q(build__outcome=Build.IN_PROGRESS)
1428 ).order_by("target").values_list("target", flat=True))
1429
1430 freqtargets = freqtargets.most_common(5)
1431
1432 # We now have the targets in order of frequency but if there are two
1433 # with the same frequency then we need to make sure those are in
1434 # alphabetical order without losing the frequency ordering
1435
1436 tmp = []
1437 switch = None
1438 for i, freqtartget in enumerate(freqtargets):
1439 target, count = freqtartget
1440 try:
1441 target_next, count_next = freqtargets[i+1]
1442 if count == count_next and target > target_next:
1443 switch = target
1444 continue
1445 except IndexError:
1446 pass
1447
1448 tmp.append(target)
1449
1450 if switch:
1451 tmp.append(switch)
1452 switch = None
1453
1454 freqtargets = tmp
1455
1456 layers = [{"id": x.layercommit.pk, "orderid": x.pk, "name" : x.layercommit.layer.name,
1457 "vcs_url": x.layercommit.layer.vcs_url, "local_source_dir": x.layercommit.layer.local_source_dir, "vcs_reference" : x.layercommit.get_vcs_reference(),
1458 "url": x.layercommit.layer.layer_index_url, "layerdetailurl": x.layercommit.get_detailspage_url(prj.pk),
1459 "branch" : {"name" : x.layercommit.get_vcs_reference(),
1460 "layersource" : x.layercommit.layer_source }
1461 } for x in prj.projectlayer_set.all().order_by("id")]
1462
1463 context = {
1464 "project" : prj,
1465 "lvs_nos" : Layer_Version.objects.all().count(),
1466 "completedbuilds": Build.objects.exclude(outcome = Build.IN_PROGRESS).filter(project_id = pid),
1467 "prj" : {"name": prj.name, },
1468 "buildrequests" : prj.build_set.filter(outcome=Build.IN_PROGRESS),
1469 "builds" : Build.get_recent(prj),
1470 "layers" : layers,
1471 "targets" : [{"target" : x.target, "task" : x.task, "pk": x.pk} for x in prj.projecttarget_set.all()],
1472 "variables": [(x.name, x.value) for x in prj.projectvariable_set.all()],
1473 "freqtargets": freqtargets,
1474 "releases": [{"id": x.pk, "name": x.name, "description":x.description} for x in Release.objects.all()],
1475 "project_html": 1,
1476 "recipesTypeAheadUrl": reverse('xhr_recipestypeahead', args=(prj.pk,)),
1477 "projectBuildsUrl": reverse('projectbuilds', args=(prj.pk,)),
1478 }
1479
1480 if prj.release is not None:
1481 context['release'] = { "id": prj.release.pk, "name": prj.release.name, "description": prj.release.description}
1482
1483
1484 try:
1485 context["machine"] = {"name": prj.projectvariable_set.get(name="MACHINE").value}
1486 except ProjectVariable.DoesNotExist:
1487 context["machine"] = None
1488 try:
1489 context["distro"] = prj.projectvariable_set.get(name="DISTRO").value
1490 except ProjectVariable.DoesNotExist:
1491 context["distro"] = "-- not set yet"
1492
1493 return context
1494 1369
1495 def jsunittests(request): 1370 def jsunittests(request):
1496 """ Provides a page for the js unit tests """ 1371 """ Provides a page for the js unit tests """