bitbake: toaster: implement the configuration pagedreyna/configure-detail-view
Update the configuration page with the file list pop-up, implement the file and description filters. [YOCTO #4259] (Bitbake rev: 54a767809960b66b2fe2d3bc46aa9c7e040c4ae3) Signed-off-by: David Reyna <David.Reyna@windriver.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
parent
31d4bf8484
commit
4717749fd6
|
@ -48,6 +48,59 @@ function reload_params(params) {
|
|||
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
//show or hide selected columns on load
|
||||
$("input:checkbox").each(function(){
|
||||
var selectedType = $(this).val();
|
||||
if($(this).is(":checked")){
|
||||
$("."+selectedType).show();
|
||||
}
|
||||
else{
|
||||
$("."+selectedType).hide();
|
||||
}
|
||||
});
|
||||
//edit columns functionality (show / hide table columns)
|
||||
$("input:checkbox").change();
|
||||
$("input:checkbox").change(function(){
|
||||
var selectedType = $(this).val();
|
||||
if($(this).is(":checked")){
|
||||
$("."+selectedType).show();
|
||||
}
|
||||
else{
|
||||
$("."+selectedType).hide();
|
||||
}
|
||||
});
|
||||
//turn edit columns dropdown into a multi-select menu
|
||||
$('.dropdown-menu input, .dropdown-menu label').click(function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
//show help information inside modal dialogs
|
||||
$("#filter-variables i").tooltip({ html: true, delay: {show: 500} });
|
||||
//show applied filter tooltip
|
||||
$('.filtered').tooltip({container:'body', placement:'bottom', delay:{hide:1500}, html:true});
|
||||
//hide the applied filter tooltip when you click the filter button
|
||||
$('.btn-primary').on('click', function () {
|
||||
$('.tooltip').hide();
|
||||
});
|
||||
|
||||
$('.full-variable, .full-variable-hide').hide();
|
||||
$('.full-variable-show').click(function(){
|
||||
$('.full-variable').slideDown(function(){
|
||||
$('.full-variable-hide').show();
|
||||
});
|
||||
$(this).hide();
|
||||
});
|
||||
$('.full-variable-hide').click(function(){
|
||||
$(this).hide();
|
||||
$('.full-variable').slideUp(function(){
|
||||
$('.full-variable-show').show();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="height: 100%">
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
<li>Configuration</li>
|
||||
{% endblock %}
|
||||
|
||||
{% load projecttags %}
|
||||
|
||||
{% block buildinfomain %}
|
||||
<!-- page title -->
|
||||
<div class="row-fluid span10">
|
||||
|
@ -22,15 +24,19 @@
|
|||
<div id="summary" class="tab-pane active">
|
||||
<h3>Build configuration</h3>
|
||||
<dl class="dl-horizontal">
|
||||
<dt>BitBake version</dt><dd>1.19.1</dd>
|
||||
<dt>Build system</dt><dd>x86_64-linux</dd>
|
||||
<dt>Host distribution</dt><dd>Ubuntu-12.04</dd>
|
||||
<dt>Target system</dt><dd>i586-poky-linux</dd>
|
||||
<dt><i class="icon-question-sign get-help" data-toggle="tooltip" title="Specifies the target device for which the image is built"></i> Machine</dt><dd>atom-pc</dd>
|
||||
<dt><i class="icon-question-sign get-help" data-toggle="tooltip" title="The short name of the distribution"></i> Distro</dt><dd>poky</dd>
|
||||
<dt>Distro version</dt><dd>1.4+snapshot-20130718</dd>
|
||||
<dt>Tune features</dt><dd>m32 i586</dd>
|
||||
<dt>Target(s)</dt><dd>core-image-sato</dd>
|
||||
{%if BB_VERSION %}<dt>BitBake version</dt><dd>{{BB_VERSION}}</dd> {% endif %}
|
||||
{%if BUILD_SYS %}<dt>Build system</dt><dd>{{BUILD_SYS}}</dd> {% endif %}
|
||||
{%if NATIVELSBSTRING %}<dt>Host distribution</dt><dd>{{NATIVELSBSTRING}}</dd> {% endif %}
|
||||
{%if TARGET_SYS %}<dt>Target system</dt><dd>{{TARGET_SYS}}</dd> {% endif %}
|
||||
{%if MACHINE %}<dt>Machine</dt><dd>{{MACHINE}}</dd> {% endif %}
|
||||
{%if DISTRO %}<dt>Distro</dt><dd>{{DISTRO}}</dd> {% endif %}
|
||||
{%if DISTRO_VERSION %}<dt>Distro version</dt><dd>{{DISTRO_VERSION}}</dd> {% endif %}
|
||||
{%if TUNE_FEATURES %}<dt>Tune features</dt><dd>{{TUNE_FEATURES}}</dd> {% endif %}
|
||||
{%if TARGET_FPU %}<dt>Target FPU</dt><dd>{{TARGET_FPU}}</dd> {% endif %}
|
||||
{%if targets.all %}<dt>Target(s)</dt>
|
||||
<dd> <ul> {% for target in targets.all %}
|
||||
<li>{{target.target}}{%if forloop.counter > 1 %}<br>{% endif %}</li>
|
||||
{% endfor %} </ul> </dd> {% endif %}
|
||||
</dl>
|
||||
<h3>Layers</h3>
|
||||
<div class="span9" style="margin-left:0px;">
|
||||
|
@ -45,7 +51,13 @@
|
|||
</thead>
|
||||
<tbody>{% for lv in build.layer_version_build.all %}
|
||||
<tr>
|
||||
<td>{{lv.layer.name}}<a href="{{lv.layer.layer_index_url}}" target="_blank"> <i class="icon-share get-info"></i></a></td><td>{{lv.branch}}</td><td class="layer_commit"><a data-content="{{lv.commit}}" title="" href="#" class="btn" data-original-title="">{{lv.commit|slice:":8"}}...</a></td><td>{{lv.layer.local_path}}</td>
|
||||
<td>{{lv.layer.name}}</td>
|
||||
<td>{{lv.branch}}</td>
|
||||
<td> <a class="btn" data-content="<ul class='unstyled'>
|
||||
<li>{{lv.commit}}</li> </ul>">
|
||||
{{lv.commit|truncatechars:13}}
|
||||
</a></td>
|
||||
<td>{{lv.layer.local_path}}</td>
|
||||
</tr>{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -3,38 +3,110 @@
|
|||
<li>Configuration</li>
|
||||
{% endblock %}
|
||||
|
||||
{% load projecttags %}
|
||||
|
||||
{% block buildinfomain %}
|
||||
<!-- page title -->
|
||||
<div class="row-fluid span10">
|
||||
<div class="page-header">
|
||||
<h1>Configuration</h1>
|
||||
<h1>
|
||||
{% if request.GET.filter or request.GET.search and objects.count > 0 %}
|
||||
{{objects.paginator.count}} variable{{objects.paginator.count|pluralize}} found
|
||||
{%elif objects.paginator.count == 0%}
|
||||
No variables
|
||||
{%else%}
|
||||
Configuration
|
||||
{%endif%}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- configuration table -->
|
||||
<div class="row-fluid pull-right span10" id="navTab">
|
||||
<ul class="nav nav-pills">
|
||||
<ul class="nav nav-pills">
|
||||
<li class=""><a href="{% url 'configuration' build.id %}">Summary</a></li>
|
||||
<li class="active"><a href="#" >BitBake variables</a></li>
|
||||
</ul>
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- variables -->
|
||||
<div id="variables" class="tab-pane">
|
||||
{% include "basetable_top.html" %}
|
||||
{% include "basetable_top.html" %}
|
||||
|
||||
{% for variable in objects %}
|
||||
<tr class="data">
|
||||
<td class="variable">{{variable.variable_name}}</td>
|
||||
<td class="variable_value">{{variable.variable_value}}</td>
|
||||
<td class="file">{% for vh in variable.vhistory_set.all %}{{vh.operation}} in {{vh.file_name}}:{{vh.line_number}}<br/>{%endfor%}</td>
|
||||
<td class="description">{% if variable.description %}{{variable.description}}{% endif %}</td>
|
||||
{% for variable in objects %}
|
||||
<tr class="data">
|
||||
<td class="variable_name"><a data-toggle="modal" href="#variable-{{variable.pk}}">{{variable.variable_name}}</a></td>
|
||||
<td class="variable_value"><a data-toggle="modal" href="#variable-{{variable.pk}}">{{variable.variable_value|truncatechars:153}}</a></td>
|
||||
<td class="file"><a data-toggle="modal" href="#variable-{{variable.pk}}">
|
||||
{% if variable.vhistory.all %} {% autoescape off %}
|
||||
{{variable.vhistory.all | filter_setin_files:file_filter }}
|
||||
{% endautoescape %} {% endif %}
|
||||
</a></td>
|
||||
<td class="description">
|
||||
{% if variable.description %}
|
||||
{{variable.description}}
|
||||
<a href="http://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-{{variable.variable_name|variable_parent_name}}" target="_blank">
|
||||
<i class="icon-share get-info"></i></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% include "basetable_bottom.html" %}
|
||||
</div> <!-- endvariables -->
|
||||
|
||||
</div> <!-- endvariables -->
|
||||
<!-- file list popups -->
|
||||
{% for variable in objects %}
|
||||
{% if variable.vhistory.count %}
|
||||
<div id="variable-{{variable.pk}}" class="modal hide fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
|
||||
<h3>History of {{variable.variable_name}}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{% if variable.variable_value %}
|
||||
{% if variable.variable_value|length < 570 %}
|
||||
<h4>{{variable.variable_name}} value is:</h4>
|
||||
<p>
|
||||
{{variable.variable_value}}
|
||||
</p>
|
||||
{% else %}
|
||||
<h4>{{variable.variable_name}} value is:</h4>
|
||||
<p>
|
||||
<span>{{variable.variable_value|string_slice:':570'}}
|
||||
<span class="full-variable"> {{variable.variable_value|string_slice:'570:'}}
|
||||
</span>
|
||||
<a class="btn btn-mini full-variable-show">...</a>
|
||||
</span>
|
||||
</p>
|
||||
<a class="btn btn-mini full-variable-hide">Collapse variable value<i class="icon-caret-up"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="alert alert-info">The value of <strong>{{variable.variable_name}}</strong> is an empty string</div>
|
||||
{% endif %}
|
||||
<h4>The value was set in the following configuration files:</h4>
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order</th>
|
||||
<th>Configuration file</th>
|
||||
<th>Operation</th>
|
||||
<th>Line number</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for vh in variable.vhistory.all %}
|
||||
<tr>
|
||||
<td>{{forloop.counter}}</td><td>{{vh.file_name}}</td><td>{{vh.operation}}</td><td>{{vh.line_number}}</td>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</div> <!-- buildinfomain -->
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -129,3 +129,62 @@ def check_filter_status(options, filter):
|
|||
if filter == option[1]:
|
||||
return ""
|
||||
return "checked"
|
||||
|
||||
@register.filter
|
||||
def variable_parent_name(value):
|
||||
""" filter extended variable names to the parent name
|
||||
"""
|
||||
value=re.sub('_\$.*', '', value)
|
||||
return re.sub('_[a-z].*', '', value)
|
||||
|
||||
@register.filter
|
||||
def filter_setin_files(file_list,matchstr):
|
||||
""" filter/search the 'set in' file lists. Note
|
||||
that this output is not autoescaped to allow
|
||||
the <p> marks, but this is safe as the data
|
||||
is file paths
|
||||
"""
|
||||
|
||||
# no filters, show last file (if any)
|
||||
if matchstr == ":":
|
||||
if file_list:
|
||||
return file_list[len(file_list)-1].file_name
|
||||
else:
|
||||
return ''
|
||||
|
||||
search, filter = matchstr.partition(':')[::2]
|
||||
htmlstr=""
|
||||
# match only filters
|
||||
if search == '':
|
||||
for i in range(len(file_list)):
|
||||
if file_list[i].file_name.find(filter) >= 0:
|
||||
htmlstr += file_list[i].file_name + "<p>"
|
||||
return htmlstr
|
||||
|
||||
# match only search string, plus always last file
|
||||
if filter == "":
|
||||
for i in range(len(file_list)-1):
|
||||
if file_list[i].file_name.find(search) >= 0:
|
||||
htmlstr += file_list[i].file_name + "<p>"
|
||||
htmlstr += file_list[len(file_list)-1].file_name
|
||||
return htmlstr
|
||||
|
||||
# match filter or search string
|
||||
for i in range(len(file_list)):
|
||||
if (file_list[i].file_name.find(filter) >= 0) or (file_list[i].file_name.find(search) >= 0):
|
||||
htmlstr += file_list[i].file_name + "<p>"
|
||||
return htmlstr
|
||||
|
||||
|
||||
@register.filter
|
||||
def string_slice(strvar,slicevar):
|
||||
""" slice a string with |string_slice:'[first]:[last]'
|
||||
"""
|
||||
first,last= slicevar.partition(':')[::2]
|
||||
if first=='':
|
||||
return strvar[:int(last)]
|
||||
elif last=='':
|
||||
return strvar[int(first):]
|
||||
else:
|
||||
return strvar[int(first):int(last)]
|
||||
|
||||
|
|
|
@ -733,59 +733,118 @@ def recipes(request, build_id):
|
|||
|
||||
def configuration(request, build_id):
|
||||
template = 'configuration.html'
|
||||
context = {'build': Build.objects.filter(pk=build_id)[0]}
|
||||
|
||||
variables = Variable.objects.filter(build=build_id)
|
||||
BB_VERSION=variables.filter(variable_name='BB_VERSION')[0].variable_value
|
||||
BUILD_SYS=variables.filter(variable_name='BUILD_SYS')[0].variable_value
|
||||
NATIVELSBSTRING=variables.filter(variable_name='NATIVELSBSTRING')[0].variable_value
|
||||
TARGET_SYS=variables.filter(variable_name='TARGET_SYS')[0].variable_value
|
||||
MACHINE=variables.filter(variable_name='MACHINE')[0].variable_value
|
||||
DISTRO=variables.filter(variable_name='DISTRO')[0].variable_value
|
||||
DISTRO_VERSION=variables.filter(variable_name='DISTRO_VERSION')[0].variable_value
|
||||
TUNE_FEATURES=variables.filter(variable_name='TUNE_FEATURES')[0].variable_value
|
||||
TARGET_FPU=variables.filter(variable_name='TARGET_FPU')[0].variable_value
|
||||
|
||||
targets = Target.objects.filter(build=build_id)
|
||||
|
||||
context = {
|
||||
'objectname': 'configuration',
|
||||
'object_search_display':'variables',
|
||||
'filter_search_display':'variables',
|
||||
'build': Build.objects.filter(pk=build_id)[0],
|
||||
'BB_VERSION':BB_VERSION,
|
||||
'BUILD_SYS':BUILD_SYS,
|
||||
'NATIVELSBSTRING':NATIVELSBSTRING,
|
||||
'TARGET_SYS':TARGET_SYS,
|
||||
'MACHINE':MACHINE,
|
||||
'DISTRO':DISTRO,
|
||||
'DISTRO_VERSION':DISTRO_VERSION,
|
||||
'TUNE_FEATURES':TUNE_FEATURES,
|
||||
'TARGET_FPU':TARGET_FPU,
|
||||
'targets':targets,
|
||||
}
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
def configvars(request, build_id):
|
||||
template = 'configvars.html'
|
||||
mandatory_parameters = { 'count': 100, 'page' : 1};
|
||||
mandatory_parameters = { 'count': 100, 'page' : 1, 'orderby':'variable_name:+', 'filter':'description__regex:.+'};
|
||||
retval = _verify_parameters( request.GET, mandatory_parameters )
|
||||
if retval:
|
||||
return _redirect_parameters( 'configvars', request.GET, mandatory_parameters, build_id = build_id)
|
||||
|
||||
(filter_string, search_term, ordering_string) = _search_tuple(request, Variable)
|
||||
queryset = Variable.objects.filter(build=build_id)
|
||||
queryset = Variable.objects.filter(build=build_id).exclude(variable_name__istartswith='B_').exclude(variable_name__istartswith='do_')
|
||||
queryset = _get_queryset(Variable, queryset, filter_string, search_term, ordering_string)
|
||||
# remove duplicate records from multiple search hits in the VariableHistory table
|
||||
queryset = queryset.distinct()
|
||||
# remove records where the value is empty AND there are no history files
|
||||
queryset = queryset.exclude(variable_value='',vhistory__file_name__isnull=True)
|
||||
|
||||
variables = _build_page_range(Paginator(queryset, request.GET.get('count', 50)), request.GET.get('page', 1))
|
||||
|
||||
file_filter= search_term + ":"
|
||||
if filter_string.find('conf/local.conf') > 0:
|
||||
file_filter += 'conf/local.conf'
|
||||
if filter_string.find('conf/machine/') > 0:
|
||||
file_filter += 'conf/machine/'
|
||||
if filter_string.find('conf/distro/') > 0:
|
||||
file_filter += 'conf/distro/'
|
||||
if filter_string.find('/bitbake.conf') > 0:
|
||||
file_filter += '/bitbake.conf'
|
||||
|
||||
context = {
|
||||
'objectname': 'configvars',
|
||||
'object_search_display':'variables',
|
||||
'filter_search_display':'variables',
|
||||
'file_filter': file_filter,
|
||||
'build': Build.objects.filter(pk=build_id)[0],
|
||||
'objects' : variables,
|
||||
# Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns
|
||||
'tablecols' : [
|
||||
{'name': 'Variable ',
|
||||
'qhelp': "Base variable expanded name",
|
||||
'clclass' : 'variable',
|
||||
'qhelp': "BitBake is a generic task executor that considers a list of tasks with dependencies and handles metadata that consists of variables in a certain format that get passed to the tasks",
|
||||
'dclass' : "span3",
|
||||
'orderfield': _get_toggle_order(request, "variable_name"),
|
||||
'ordericon':_get_toggle_order_icon(request, "variable_name"),
|
||||
},
|
||||
{'name': 'Value ',
|
||||
'qhelp': "The value assigned to the variable",
|
||||
'clclass': 'variable_value',
|
||||
'dclass': "span4",
|
||||
'orderfield': _get_toggle_order(request, "variable_value"),
|
||||
'ordericon':_get_toggle_order_icon(request, "variable_value"),
|
||||
},
|
||||
{'name': 'Configuration file(s) ',
|
||||
'qhelp': "The configuration file(s) that touched the variable value",
|
||||
'clclass': 'file',
|
||||
{'name': 'Set in file',
|
||||
'qhelp': "The last configuration file that touched the variable value",
|
||||
'clclass': 'file', 'hidden' : 0,
|
||||
'dclass': "span6",
|
||||
'orderfield': _get_toggle_order(request, "variable_vhistory__file_name"),
|
||||
'filter' : { 'class': 'file', 'label' : 'Show only', 'options' : {
|
||||
}
|
||||
}
|
||||
'orderfield': _get_toggle_order(request, "vhistory__file_name"),
|
||||
'ordericon':_get_toggle_order_icon(request, "vhistory__file_name"),
|
||||
'filter' : {
|
||||
'class' : 'vhistory__file_name',
|
||||
'label': 'Show:',
|
||||
'options' : [
|
||||
('Local configuration variables', 'vhistory__file_name__contains:conf/local.conf'),
|
||||
('Machine configuration variables', 'vhistory__file_name__contains:conf/machine/'),
|
||||
('Distro configuration variables', 'vhistory__file_name__contains:conf/distro/'),
|
||||
('Layer configuration variables', 'vhistory__file_name__contains:conf/layer.conf'),
|
||||
('bitbake.conf variables', 'vhistory__file_name__contains:/bitbake.conf'),
|
||||
]
|
||||
},
|
||||
},
|
||||
{'name': 'Description ',
|
||||
'qhelp': "A brief explanation of a variable",
|
||||
'clclass': 'description',
|
||||
'qhelp': "A brief explanation of the variable",
|
||||
'clclass': 'description', 'hidden' : 0,
|
||||
'dclass': "span5",
|
||||
'orderfield': _get_toggle_order(request, "description"),
|
||||
'filter' : { 'class' : 'description', 'label' : 'No', 'options' : {
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
'filter' : {
|
||||
'class' : 'description',
|
||||
'label': 'Show:',
|
||||
'options' : [
|
||||
('Variables with description', 'description__regex:.+'),
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return render(request, template, context)
|
||||
|
|
Loading…
Reference in New Issue