From 09ef043f3f55545330870f2d48e51df3cfbb4c0c Mon Sep 17 00:00:00 2001 From: Paul Eggleton Date: Wed, 14 Feb 2018 11:54:48 +1300 Subject: [PATCH] Support excluding inherited classes from other distro comparison reversed query When doing the reversed query it's often desirable to exclude recipes by inherited class, for example those that inherit the packagegroup, image and meta classes as they don't actually build anything and thus aren't going to match up with anything in the other distribution. Signed-off-by: Paul Eggleton --- layerindex/urls.py | 6 +- layerindex/views.py | 104 +++++++++++++++++++++++ templates/layerindex/classchecklist.html | 21 +++++ templates/layerindex/classicrecipes.html | 86 ++++++++++++++++++- 4 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 templates/layerindex/classchecklist.html diff --git a/layerindex/urls.py b/layerindex/urls.py index bfa7628..9a5d01c 100644 --- a/layerindex/urls.py +++ b/layerindex/urls.py @@ -8,7 +8,7 @@ from django.conf.urls import * from django.views.generic import TemplateView, DetailView, ListView, RedirectView from django.views.defaults import page_not_found from django.core.urlresolvers import reverse_lazy -from layerindex.views import LayerListView, LayerReviewListView, LayerReviewDetailView, RecipeSearchView, MachineSearchView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, HistoryListView, EditProfileFormView, AdvancedRecipeSearchView, BulkChangeView, BulkChangeSearchView, bulk_change_edit_view, bulk_change_patch_view, BulkChangeDeleteView, RecipeDetailView, RedirectParamsView, ClassicRecipeSearchView, ClassicRecipeDetailView, ClassicRecipeStatsView, LayerUpdateDetailView, UpdateListView, UpdateDetailView, StatsView, publish_view, LayerCheckListView +from layerindex.views import LayerListView, LayerReviewListView, LayerReviewDetailView, RecipeSearchView, MachineSearchView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, HistoryListView, EditProfileFormView, AdvancedRecipeSearchView, BulkChangeView, BulkChangeSearchView, bulk_change_edit_view, bulk_change_patch_view, BulkChangeDeleteView, RecipeDetailView, RedirectParamsView, ClassicRecipeSearchView, ClassicRecipeDetailView, ClassicRecipeStatsView, LayerUpdateDetailView, UpdateListView, UpdateDetailView, StatsView, publish_view, LayerCheckListView, BBClassCheckListView from layerindex.models import LayerItem, Recipe, RecipeChangeset from rest_framework import routers from . import restviews @@ -154,5 +154,9 @@ urlpatterns = [ LayerCheckListView.as_view( template_name='layerindex/layerchecklist.html'), name='layer_checklist'), + url(r'^ajax/classchecklist/(?P[-\w]+)/$', + BBClassCheckListView.as_view( + template_name='layerindex/classchecklist.html'), + name='class_checklist'), url(r'.*', page_not_found, kwargs={'exception': Exception("Page not Found")}) ] diff --git a/layerindex/views.py b/layerindex/views.py index f2274f8..93eae8e 100644 --- a/layerindex/views.py +++ b/layerindex/views.py @@ -947,6 +947,98 @@ class LayerCheckListView(ListView): _check_url_branch(self.kwargs) return LayerBranch.objects.filter(branch__name=self.kwargs['branch']).filter(layer__status__in=['P', 'X']).order_by('layer__name') +class BBClassCheckListView(ListView): + context_object_name = 'classes' + + def get_queryset(self): + _check_url_branch(self.kwargs) + nonrecipe_classes = ['archiver', + 'base', + 'buildhistory', + 'bugzilla', + 'buildstats', + 'buildstats-summary', + 'ccache', + 'chrpath', + 'copyleft_compliance', + 'copyleft_filter', + 'cve-check', + 'debian', + 'devshell', + 'devtool-source', + 'distrodata', + 'extrausers', + 'icecc', + 'image-buildinfo', + 'image-container', + 'image-combined-dbg', + 'image-live', + 'image-mklibs', + 'image-prelink', + 'image_types', + 'image_types_wic', + 'insane', + 'license', + 'license_image', + 'live-vm-common', + 'logging', + 'metadata_scm', + 'migrate_localcount', + 'mirrors', + 'multilib', + 'multilib_global', + 'multilib_header', + 'oelint', + 'own-mirrors', + 'package', + 'package_deb', + 'package_ipk', + 'package_rpm', + 'package_tar', + 'packagedata', + 'packagefeed-stability', + 'patch', + 'primport', + 'prexport', + 'recipe_sanity', + 'remove-libtool', + 'report-error', + 'reproducible_build', + 'reproducible_build_simple', + 'rm_work', + 'rm_work_and_downloads', + 'rootfs-postcommands', + 'rootfs_deb', + 'rootfs_ipk', + 'rootfs_rpm', + 'rootfsdebugfiles', + 'sanity', + 'sign_ipk', + 'sign_package_feed', + 'sign_rpm', + 'siteconfig', + 'siteinfo', + 'spdx', + 'sstate', + 'staging', + 'syslinux', + 'systemd-boot', + 'terminal', + 'testexport', + 'testimage', + 'testimage-auto', + 'testsdk', + 'tinderclient', + 'toaster', + 'toolchain-scripts', + 'toolchain-scripts-base', + 'uninative', + 'useradd-staticids', + 'utility-tasks', + 'utils', + ] + return BBClass.objects.filter(layerbranch__branch__name=self.kwargs['branch']).filter(layerbranch__layer__name=settings.CORE_LAYER_NAME).exclude(name__in=nonrecipe_classes).order_by('name') + class ClassicRecipeSearchView(RecipeSearchView): def render_to_response(self, context, **kwargs): @@ -1028,6 +1120,10 @@ class ClassicRecipeSearchView(RecipeSearchView): init_rqs = Recipe.objects.filter(layerbranch__branch__name='master') if layer_ids: init_rqs = init_rqs.filter(layerbranch__layer__id__in=layer_ids) + excludeclasses_param = self.request.GET.get('excludeclasses', '') + if excludeclasses_param: + for inherit in excludeclasses_param.split(','): + init_rqs = init_rqs.exclude(inherits=inherit).exclude(inherits__startswith=inherit + ' ').exclude(inherits__endswith=' ' + inherit).exclude(inherits__contains=' %s ' % inherit) all_values = [] if filtered: if isinstance(qs, list): @@ -1078,6 +1174,14 @@ class ClassicRecipeSearchView(RecipeSearchView): layer_ids = [] context['selectedlayers_display'] = ' (any)' context['selectedlayers'] = layer_ids + + excludeclasses_param = self.request.GET.get('excludeclasses', '') + if excludeclasses_param: + context['excludeclasses_display'] = excludeclasses_param + context['excludeclasses'] = excludeclasses_param.split(',') + else: + context['excludeclasses_display'] = ' (none)' + context['excludeclasses'] = [] return context diff --git a/templates/layerindex/classchecklist.html b/templates/layerindex/classchecklist.html new file mode 100644 index 0000000..a3b1b6b --- /dev/null +++ b/templates/layerindex/classchecklist.html @@ -0,0 +1,21 @@ +{% comment %} + + layerindex-web - class check list AJAX template + + Copyright (C) 2018 Intel Corporation + Licensed under the MIT license, see COPYING.MIT for details + +{% endcomment %} + +{% autoescape on %} + + {% for classitem in classes %} + + + + + {% endfor %} +
+ +
+{% endautoescape %} diff --git a/templates/layerindex/classicrecipes.html b/templates/layerindex/classicrecipes.html index c22bb19..7a07216 100644 --- a/templates/layerindex/classicrecipes.html +++ b/templates/layerindex/classicrecipes.html @@ -87,7 +87,39 @@ {% endfor %} - + + + + + Exclude classes + + +
+ + ... +
+ + + + + + @@ -215,6 +247,17 @@ else $('#id_selectedlayers_display').val(' (any)') } + update_excludeclasses_display = function() { + classnames = []; + $('.filterclasscheckbox:checked').each(function() { + classnames.push($(this).attr('value')); + }); + if(classnames.length) + $('#id_excludeclasses_display').val(classnames) + else + $('#id_excludeclasses_display').val(' (none)'); + $('#id_excludeclasses').val(classnames) + } update_filters_enabled = function() { if( $('#id_reversed').is(":checked") ) { $('#id_reversed_fields').show() @@ -254,8 +297,40 @@ }); } } + select_excludeclass_checkboxes = function() { + $('.filterclasscheckbox').attr('checked', false); + excludeclasses = $('#id_excludeclasses').val().split(','); + for(i in excludeclasses) { + $('#id_classcheckbox_' + excludeclasses[i]).attr('checked', true); + } + } + setup_excludeclass_list = function() { + if( $.trim($('#id_excludeclassdialog_list').html()) ) { + select_excludeclass_checkboxes() + } + else { + $('#id_excludeclassdialog_list').html('Loading...'); + $('#id_excludeclassdialog_ok').prop('disabled', true) + $('#id_excludeclassdialog_ok').addClass('disabled') + $.ajax({ + url: '{% url 'class_checklist' 'master' %}', + dataType: 'html', + success: function( resp ) { + $('#id_excludeclassdialog_list').html(resp); + select_excludeclass_checkboxes() + $('#id_excludeclassdialog_ok').prop('disabled', false) + $('#id_excludeclassdialog_ok').removeClass('disabled') + }, + error: function( req, status, err ) { + $('#id_excludeclassdialog_list').html(err); + console.log( 'something went wrong', status, err ); + } + }); + } + } $(document).ready(function() { $('#id_selectedlayers_display').prop('readonly', true) + $('#id_excludeclasses_display').prop('readonly', true) update_filters_enabled() $('[data-toggle="tooltip"]').tooltip(); firstfield = $("#search-form input:text").first() @@ -274,6 +349,15 @@ $('#id_select_layers').click(function (e) { setup_layer_list() }); + $('#id_excludeclassdialog_select_none').click(function (e) { + $('.filterclasscheckbox').attr('checked', false); + }); + $('#id_excludeclassdialog_ok').click(function (e) { + update_excludeclasses_display() + }); + $('#id_select_excludeclasses').click(function (e) { + setup_excludeclass_list() + }); $('#id_reversed').click(function (e) { update_filters_enabled() });