diff options
author | Elliot Smith <elliot.smith@intel.com> | 2016-01-15 13:00:55 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-01-15 16:30:00 +0000 |
commit | eaae82a19acaf786b866043ea80107f28e8206b2 (patch) | |
tree | 4e5edd8d7f044755ae76ae67bd1d473431448a3c /bitbake/lib/toaster/toastergui/tables.py | |
parent | 33b011c1589519db8176c9f5a4abb540698902e6 (diff) | |
download | poky-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/lib/toaster/toastergui/tables.py')
-rw-r--r-- | bitbake/lib/toaster/toastergui/tables.py | 184 |
1 files changed, 151 insertions, 33 deletions
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 | |||
23 | from toastergui.querysetfilter import QuerysetFilter | 23 | from toastergui.querysetfilter import QuerysetFilter |
24 | from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project | 24 | from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project |
25 | from orm.models import CustomImageRecipe, Package, Build, LogMessage, Task | 25 | from orm.models import CustomImageRecipe, Package, Build, LogMessage, Task |
26 | from orm.models import ProjectTarget | ||
26 | from django.db.models import Q, Max, Count | 27 | from django.db.models import Q, Max, Count |
27 | from django.conf.urls import url | 28 | from django.conf.urls import url |
28 | from django.core.urlresolvers import reverse | 29 | from django.core.urlresolvers import reverse, resolve |
30 | from django.http import HttpResponse | ||
29 | from django.views.generic import TemplateView | 31 | from django.views.generic import TemplateView |
30 | import itertools | 32 | import itertools |
31 | 33 | ||
@@ -775,7 +777,7 @@ class ProjectsTable(ToasterTable): | |||
775 | ''' | 777 | ''' |
776 | 778 | ||
777 | errors_template = ''' | 779 | errors_template = ''' |
778 | {% if data.get_number_of_builds > 0 %} | 780 | {% if data.get_number_of_builds > 0 and data.get_last_errors > 0 %} |
779 | <a class="errors.count error" | 781 | <a class="errors.count error" |
780 | href="{% url "builddashboard" data.get_last_build_id %}#errors"> | 782 | href="{% url "builddashboard" data.get_last_build_id %}#errors"> |
781 | {{data.get_last_errors}} error{{data.get_last_errors | pluralize}} | 783 | {{data.get_last_errors}} error{{data.get_last_errors | pluralize}} |
@@ -784,7 +786,7 @@ class ProjectsTable(ToasterTable): | |||
784 | ''' | 786 | ''' |
785 | 787 | ||
786 | warnings_template = ''' | 788 | warnings_template = ''' |
787 | {% if data.get_number_of_builds > 0 %} | 789 | {% if data.get_number_of_builds > 0 and data.get_last_warnings > 0 %} |
788 | <a class="warnings.count warning" | 790 | <a class="warnings.count warning" |
789 | href="{% url "builddashboard" data.get_last_build_id %}#warnings"> | 791 | href="{% url "builddashboard" data.get_last_build_id %}#warnings"> |
790 | {{data.get_last_warnings}} warning{{data.get_last_warnings | pluralize}} | 792 | {{data.get_last_warnings}} warning{{data.get_last_warnings | pluralize}} |
@@ -886,30 +888,45 @@ class BuildsTable(ToasterTable): | |||
886 | def __init__(self, *args, **kwargs): | 888 | def __init__(self, *args, **kwargs): |
887 | super(BuildsTable, self).__init__(*args, **kwargs) | 889 | super(BuildsTable, self).__init__(*args, **kwargs) |
888 | self.default_orderby = '-completed_on' | 890 | self.default_orderby = '-completed_on' |
889 | self.title = 'All builds' | ||
890 | self.static_context_extra['Build'] = Build | 891 | self.static_context_extra['Build'] = Build |
891 | self.static_context_extra['Task'] = Task | 892 | self.static_context_extra['Task'] = Task |
892 | 893 | ||
894 | # attributes that are overridden in subclasses | ||
895 | |||
896 | # title for the page | ||
897 | self.title = '' | ||
898 | |||
899 | # 'project' or 'all'; determines how the mrb (most recent builds) | ||
900 | # section is displayed | ||
901 | self.mrb_type = '' | ||
902 | |||
903 | def get_builds(self): | ||
904 | """ | ||
905 | overridden in ProjectBuildsTable to return builds for a | ||
906 | single project | ||
907 | """ | ||
908 | return Build.objects.all() | ||
909 | |||
893 | def get_context_data(self, **kwargs): | 910 | def get_context_data(self, **kwargs): |
894 | context = super(BuildsTable, self).get_context_data(**kwargs) | 911 | context = super(BuildsTable, self).get_context_data(**kwargs) |
895 | 912 | ||
896 | # for the latest builds section | 913 | # for the latest builds section |
897 | queryset = Build.objects.all() | 914 | builds = self.get_builds() |
898 | 915 | ||
899 | finished_criteria = Q(outcome=Build.SUCCEEDED) | Q(outcome=Build.FAILED) | 916 | finished_criteria = Q(outcome=Build.SUCCEEDED) | Q(outcome=Build.FAILED) |
900 | 917 | ||
901 | latest_builds = itertools.chain( | 918 | latest_builds = itertools.chain( |
902 | queryset.filter(outcome=Build.IN_PROGRESS).order_by("-started_on"), | 919 | builds.filter(outcome=Build.IN_PROGRESS).order_by("-started_on"), |
903 | queryset.filter(finished_criteria).order_by("-completed_on")[:3] | 920 | builds.filter(finished_criteria).order_by("-completed_on")[:3] |
904 | ) | 921 | ) |
905 | 922 | ||
906 | context['mru'] = list(latest_builds) | 923 | context['mru'] = list(latest_builds) |
907 | context['mrb_type'] = 'all' | 924 | context['mrb_type'] = self.mrb_type |
908 | 925 | ||
909 | return context | 926 | return context |
910 | 927 | ||
911 | def setup_queryset(self, *args, **kwargs): | 928 | def setup_queryset(self, *args, **kwargs): |
912 | queryset = Build.objects.all() | 929 | queryset = self.get_builds() |
913 | 930 | ||
914 | # don't include in progress builds | 931 | # don't include in progress builds |
915 | queryset = queryset.exclude(outcome=Build.IN_PROGRESS) | 932 | queryset = queryset.exclude(outcome=Build.IN_PROGRESS) |
@@ -949,7 +966,8 @@ class BuildsTable(ToasterTable): | |||
949 | {% if data.cooker_log_path %} | 966 | {% if data.cooker_log_path %} |
950 | | 967 | |
951 | <a href="{% url "build_artifact" data.id "cookerlog" data.id %}"> | 968 | <a href="{% url "build_artifact" data.id "cookerlog" data.id %}"> |
952 | <i class="icon-download-alt" title="Download build log"></i> | 969 | <i class="icon-download-alt get-help" |
970 | data-original-title="Download build log"></i> | ||
953 | </a> | 971 | </a> |
954 | {% endif %} | 972 | {% endif %} |
955 | ''' | 973 | ''' |
@@ -1031,19 +1049,6 @@ class BuildsTable(ToasterTable): | |||
1031 | {% endif %} | 1049 | {% endif %} |
1032 | ''' | 1050 | ''' |
1033 | 1051 | ||
1034 | project_template = ''' | ||
1035 | {% load project_url_tag %} | ||
1036 | <a href="{% project_url data.project %}"> | ||
1037 | {{data.project.name}} | ||
1038 | </a> | ||
1039 | {% if data.project.is_default %} | ||
1040 | <i class="icon-question-sign get-help hover-help" title="" | ||
1041 | data-original-title="This project shows information about | ||
1042 | the builds you start from the command line while Toaster is | ||
1043 | running" style="visibility: hidden;"></i> | ||
1044 | {% endif %} | ||
1045 | ''' | ||
1046 | |||
1047 | self.add_column(title='Outcome', | 1052 | self.add_column(title='Outcome', |
1048 | help_text='Final state of the build (successful \ | 1053 | help_text='Final state of the build (successful \ |
1049 | or failed)', | 1054 | or failed)', |
@@ -1098,16 +1103,16 @@ class BuildsTable(ToasterTable): | |||
1098 | help_text='The number of errors encountered during \ | 1103 | help_text='The number of errors encountered during \ |
1099 | the build (if any)', | 1104 | the build (if any)', |
1100 | hideable=True, | 1105 | hideable=True, |
1101 | orderable=False, | 1106 | orderable=True, |
1102 | static_data_name='errors', | 1107 | static_data_name='errors_no', |
1103 | static_data_template=errors_template) | 1108 | static_data_template=errors_template) |
1104 | 1109 | ||
1105 | self.add_column(title='Warnings', | 1110 | self.add_column(title='Warnings', |
1106 | help_text='The number of warnings encountered during \ | 1111 | help_text='The number of warnings encountered during \ |
1107 | the build (if any)', | 1112 | the build (if any)', |
1108 | hideable=True, | 1113 | hideable=True, |
1109 | orderable=False, | 1114 | orderable=True, |
1110 | static_data_name='warnings', | 1115 | static_data_name='warnings_no', |
1111 | static_data_template=warnings_template) | 1116 | static_data_template=warnings_template) |
1112 | 1117 | ||
1113 | self.add_column(title='Time', | 1118 | self.add_column(title='Time', |
@@ -1125,12 +1130,6 @@ class BuildsTable(ToasterTable): | |||
1125 | static_data_name='image_files', | 1130 | static_data_name='image_files', |
1126 | static_data_template=image_files_template) | 1131 | static_data_template=image_files_template) |
1127 | 1132 | ||
1128 | self.add_column(title='Project', | ||
1129 | hideable=True, | ||
1130 | orderable=False, | ||
1131 | static_data_name='project-name', | ||
1132 | static_data_template=project_template) | ||
1133 | |||
1134 | def setup_filters(self, *args, **kwargs): | 1133 | def setup_filters(self, *args, **kwargs): |
1135 | # outcomes | 1134 | # outcomes |
1136 | outcome_filter = TableFilter( | 1135 | outcome_filter = TableFilter( |
@@ -1239,3 +1238,122 @@ class BuildsTable(ToasterTable): | |||
1239 | failed_tasks_filter.add_action(with_failed_tasks_action) | 1238 | failed_tasks_filter.add_action(with_failed_tasks_action) |
1240 | failed_tasks_filter.add_action(without_failed_tasks_action) | 1239 | failed_tasks_filter.add_action(without_failed_tasks_action) |
1241 | self.add_filter(failed_tasks_filter) | 1240 | self.add_filter(failed_tasks_filter) |
1241 | |||
1242 | def post(self, request, *args, **kwargs): | ||
1243 | """ Process HTTP POSTs which make build requests """ | ||
1244 | |||
1245 | project = Project.objects.get(pk=kwargs['pid']) | ||
1246 | |||
1247 | if 'buildCancel' in request.POST: | ||
1248 | for i in request.POST['buildCancel'].strip().split(" "): | ||
1249 | try: | ||
1250 | br = BuildRequest.objects.select_for_update().get(project = project, pk = i, state__lte = BuildRequest.REQ_QUEUED) | ||
1251 | br.state = BuildRequest.REQ_DELETED | ||
1252 | br.save() | ||
1253 | except BuildRequest.DoesNotExist: | ||
1254 | pass | ||
1255 | |||
1256 | if 'buildDelete' in request.POST: | ||
1257 | for i in request.POST['buildDelete'].strip().split(" "): | ||
1258 | try: | ||
1259 | BuildRequest.objects.select_for_update().get(project = project, pk = i, state__lte = BuildRequest.REQ_DELETED).delete() | ||
1260 | except BuildRequest.DoesNotExist: | ||
1261 | pass | ||
1262 | |||
1263 | if 'targets' in request.POST: | ||
1264 | ProjectTarget.objects.filter(project = project).delete() | ||
1265 | s = str(request.POST['targets']) | ||
1266 | for t in s.translate(None, ";%|\"").split(" "): | ||
1267 | if ":" in t: | ||
1268 | target, task = t.split(":") | ||
1269 | else: | ||
1270 | target = t | ||
1271 | task = "" | ||
1272 | ProjectTarget.objects.create(project = project, | ||
1273 | target = target, | ||
1274 | task = task) | ||
1275 | project.schedule_build() | ||
1276 | |||
1277 | # redirect back to builds page so any new builds in progress etc. | ||
1278 | # are visible | ||
1279 | response = HttpResponse() | ||
1280 | response.status_code = 302 | ||
1281 | response['Location'] = request.build_absolute_uri() | ||
1282 | return response | ||
1283 | |||
1284 | class AllBuildsTable(BuildsTable): | ||
1285 | """ Builds page for all builds """ | ||
1286 | |||
1287 | def __init__(self, *args, **kwargs): | ||
1288 | super(AllBuildsTable, self).__init__(*args, **kwargs) | ||
1289 | self.title = 'All builds' | ||
1290 | self.mrb_type = 'all' | ||
1291 | |||
1292 | def setup_columns(self, *args, **kwargs): | ||
1293 | """ | ||
1294 | All builds page shows a column for the project | ||
1295 | """ | ||
1296 | |||
1297 | super(AllBuildsTable, self).setup_columns(*args, **kwargs) | ||
1298 | |||
1299 | project_template = ''' | ||
1300 | {% load project_url_tag %} | ||
1301 | <a href="{% project_url data.project %}"> | ||
1302 | {{data.project.name}} | ||
1303 | </a> | ||
1304 | {% if data.project.is_default %} | ||
1305 | <i class="icon-question-sign get-help hover-help" title="" | ||
1306 | data-original-title="This project shows information about | ||
1307 | the builds you start from the command line while Toaster is | ||
1308 | running" style="visibility: hidden;"></i> | ||
1309 | {% endif %} | ||
1310 | ''' | ||
1311 | |||
1312 | self.add_column(title='Project', | ||
1313 | hideable=True, | ||
1314 | orderable=True, | ||
1315 | static_data_name='project', | ||
1316 | static_data_template=project_template) | ||
1317 | |||
1318 | class ProjectBuildsTable(BuildsTable): | ||
1319 | """ | ||
1320 | Builds page for a single project; a BuildsTable, with the queryset | ||
1321 | filtered by project | ||
1322 | """ | ||
1323 | |||
1324 | def __init__(self, *args, **kwargs): | ||
1325 | super(ProjectBuildsTable, self).__init__(*args, **kwargs) | ||
1326 | self.title = 'All project builds' | ||
1327 | self.mrb_type = 'project' | ||
1328 | |||
1329 | # set from the querystring | ||
1330 | self.project_id = None | ||
1331 | |||
1332 | def setup_queryset(self, *args, **kwargs): | ||
1333 | """ | ||
1334 | NOTE: self.project_id must be set before calling super(), | ||
1335 | as it's used in setup_queryset() | ||
1336 | """ | ||
1337 | self.project_id = kwargs['pid'] | ||
1338 | super(ProjectBuildsTable, self).setup_queryset(*args, **kwargs) | ||
1339 | |||
1340 | project = Project.objects.get(pk=self.project_id) | ||
1341 | self.queryset = self.queryset.filter(project=project) | ||
1342 | |||
1343 | def get_context_data(self, **kwargs): | ||
1344 | """ | ||
1345 | NOTE: self.project_id must be set before calling super(), | ||
1346 | as it's used in get_context_data() | ||
1347 | """ | ||
1348 | self.project_id = kwargs['pid'] | ||
1349 | |||
1350 | context = super(ProjectBuildsTable, self).get_context_data(**kwargs) | ||
1351 | context['project'] = Project.objects.get(pk=self.project_id) | ||
1352 | |||
1353 | return context | ||
1354 | |||
1355 | def get_builds(self): | ||
1356 | """ override: only return builds for the relevant project """ | ||
1357 | |||
1358 | project = Project.objects.get(pk=self.project_id) | ||
1359 | return Build.objects.filter(project=project) | ||