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 <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2018-02-14 11:54:48 +13:00
parent 26d2bd2f36
commit 09ef043f3f
4 changed files with 215 additions and 2 deletions

View File

@ -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<branch>[-\w]+)/$',
BBClassCheckListView.as_view(
template_name='layerindex/classchecklist.html'),
name='class_checklist'),
url(r'.*', page_not_found, kwargs={'exception': Exception("Page not Found")})
]

View File

@ -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

View File

@ -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 %}
<table><tbody>
{% for classitem in classes %}
<tr>
<td class="checkboxtd">
<input type="checkbox" class="filterclasscheckbox" value="{{ classitem.name }}" id="id_classcheckbox_{{classitem.name}}" />
</td>
<td><label for="id_classcheckbox_{{classitem.name}}">{{ classitem.name }}</label></td>
</tr>
{% endfor %}
</tbody></table>
{% endautoescape %}

View File

@ -87,7 +87,39 @@
</tr>
{% endfor %}
<tr><td><label class="checkbox"><input type="checkbox" name="compare" {% if compare %}checked{% endif %}></input>Show comparison</label></td></tr>
<tr><td><label class="checkbox"><input type="checkbox" name="reversed" {% if reversed %}checked{% endif %}></input>Reversed</label></td></tr>
<tr><td><label class="checkbox"><input type="checkbox" name="reversed" id="id_reversed" {% if reversed %}checked{% endif %}></input>Reversed</label></td></tr>
<tr id="id_reversed_fields">
<td>
Exclude classes
</td>
<td>
<div class="input-append">
<input class="input-large" id="id_excludeclasses_display" type="text" value="{{ excludeclasses_display }}" />
<a href="#excludeclassDialog" id="id_select_excludeclasses" role="button" class="btn" data-toggle="modal">...</a>
</div>
<input type="hidden" id="id_excludeclasses" name="excludeclasses" value="{{ excludeclasses|join:"," }}" />
<div id="excludeclassDialog" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="excludeclassDialogLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="excludeclassDialogLabel">Select classes to exclude</h3>
</div>
<div class="modal-body">
<div class="scrolling" id="id_excludeclassdialog_list">
</div>
<div class="buttonblock">
<button type="button" class="btn buttonblock-btn" id="id_excludeclassdialog_select_none">Select none</button>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" id="id_excludeclassdialog_ok" data-dismiss="modal" aria-hidden="true">OK</button>
<button class="btn" id="id_excludeclassdialog_cancel" data-dismiss="modal" aria-hidden="true">Cancel</button>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<button class="btn" type="submit">Search</button>
@ -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()
});