mirror of
https://git.yoctoproject.org/poky
synced 2026-05-25 21:52:38 +02:00
This patch clones the Simple UI to provide the base code for the development of the Toaster GUI. The clone takes the place of the application that was reserved for Javascript MVC code. The templates used for Simple UI are renamed to start with an "simple_" to prevent name resolution conflict with the Toaster GUI templates. Minor changes are made to the settings.py and urls.py in the toaster main section to account for the newly enabled application. (Bitbake rev: e2fde84f16da017ba0d71aef6a1fa8e2b9255db4) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
281 lines
8.7 KiB
Python
281 lines
8.7 KiB
Python
#
|
|
# BitBake Toaster Implementation
|
|
#
|
|
# Copyright (C) 2013 Intel Corporation
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License version 2 as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along
|
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
import operator
|
|
|
|
from django.db.models import Q
|
|
from django.shortcuts import render
|
|
from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe, LogMessage, Variable
|
|
from orm.models import Task_Dependency, Recipe_Dependency, Package, Package_File, Package_Dependency
|
|
from orm.models import Target_Installed_Package
|
|
from django.views.decorators.cache import cache_control
|
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
|
|
|
|
def _build_page_range(paginator, index = 1):
|
|
try:
|
|
page = paginator.page(index)
|
|
except PageNotAnInteger:
|
|
page = paginator.page(1)
|
|
except EmptyPage:
|
|
page = paginator.page(paginator.num_pages)
|
|
|
|
page.page_range = [page.number]
|
|
crt_range = 0
|
|
for i in range(1,5):
|
|
if (page.number + i) <= paginator.num_pages:
|
|
page.page_range = page.page_range + [ page.number + i]
|
|
crt_range +=1
|
|
if (page.number - i) > 0:
|
|
page.page_range = [page.number -i] + page.page_range
|
|
crt_range +=1
|
|
if crt_range == 4:
|
|
break
|
|
return page
|
|
|
|
@cache_control(no_store=True)
|
|
def build(request):
|
|
template = 'simple_build.html'
|
|
logs = LogMessage.objects.all()
|
|
|
|
build_info = _build_page_range(Paginator(Build.objects.order_by("-id"), 10),request.GET.get('page', 1))
|
|
|
|
context = {'objects': build_info, 'logs': logs ,
|
|
'hideshowcols' : [
|
|
{'name': 'Output', 'order':10},
|
|
{'name': 'Log', 'order':11},
|
|
]}
|
|
|
|
return render(request, template, context)
|
|
|
|
|
|
def _find_task_revdep(task):
|
|
tp = []
|
|
for p in Task_Dependency.objects.filter(depends_on=task):
|
|
tp.append(p.task);
|
|
return tp
|
|
|
|
def _find_task_provider(task):
|
|
task_revdeps = _find_task_revdep(task)
|
|
for tr in task_revdeps:
|
|
if tr.outcome != Task.OUTCOME_COVERED:
|
|
return tr
|
|
for tr in task_revdeps:
|
|
trc = _find_task_provider(tr)
|
|
if trc is not None:
|
|
return trc
|
|
return None
|
|
|
|
def task(request, build_id):
|
|
template = 'simple_task.html'
|
|
|
|
tasks = _build_page_range(Paginator(Task.objects.filter(build=build_id), 100),request.GET.get('page', 1))
|
|
|
|
for t in tasks:
|
|
if t.outcome == Task.OUTCOME_COVERED:
|
|
t.provider = _find_task_provider(t)
|
|
|
|
context = {'build': Build.objects.filter(pk=build_id)[0], 'objects': tasks}
|
|
|
|
return render(request, template, context)
|
|
|
|
def configuration(request, build_id):
|
|
template = 'simple_configuration.html'
|
|
variables = _build_page_range(Paginator(Variable.objects.filter(build=build_id), 50), request.GET.get('page', 1))
|
|
context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : variables}
|
|
return render(request, template, context)
|
|
|
|
def bpackage(request, build_id):
|
|
template = 'simple_bpackage.html'
|
|
packages = Package.objects.filter(build = build_id)
|
|
context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages}
|
|
return render(request, template, context)
|
|
|
|
def bfile(request, build_id, package_id):
|
|
template = 'simple_bfile.html'
|
|
files = Package_File.objects.filter(package = package_id)
|
|
context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : files}
|
|
return render(request, template, context)
|
|
|
|
def tpackage(request, build_id, target_id):
|
|
template = 'simple_package.html'
|
|
packages = map(lambda x: x.package, list(Target_Installed_Package.objects.filter(target=target_id)))
|
|
context = {'build': Build.objects.filter(pk=build_id)[0], 'objects' : packages}
|
|
return render(request, template, context)
|
|
|
|
def layer(request):
|
|
template = 'simple_layer.html'
|
|
layer_info = Layer.objects.all()
|
|
|
|
for li in layer_info:
|
|
li.versions = Layer_Version.objects.filter(layer = li)
|
|
for liv in li.versions:
|
|
liv.count = Recipe.objects.filter(layer_version__id = liv.id).count()
|
|
|
|
context = {'objects': layer_info}
|
|
|
|
return render(request, template, context)
|
|
|
|
|
|
def layer_versions_recipes(request, layerversion_id):
|
|
template = 'simple_recipe.html'
|
|
recipes = Recipe.objects.filter(layer_version__id = layerversion_id)
|
|
|
|
context = {'objects': recipes,
|
|
'layer_version' : Layer_Version.objects.filter( id = layerversion_id )[0]
|
|
}
|
|
|
|
return render(request, template, context)
|
|
|
|
#### API
|
|
|
|
import json
|
|
from django.core import serializers
|
|
from django.http import HttpResponse, HttpResponseBadRequest
|
|
|
|
|
|
def model_explorer(request, model_name):
|
|
|
|
DESCENDING = 'desc'
|
|
response_data = {}
|
|
model_mapping = {
|
|
'build': Build,
|
|
'target': Target,
|
|
'task': Task,
|
|
'task_dependency': Task_Dependency,
|
|
'package': Package,
|
|
'layer': Layer,
|
|
'layerversion': Layer_Version,
|
|
'recipe': Recipe,
|
|
'recipe_dependency': Recipe_Dependency,
|
|
'package': Package,
|
|
'package_dependency': Package_Dependency,
|
|
'build_file': Package_File,
|
|
'variable': Variable,
|
|
'logmessage': LogMessage,
|
|
}
|
|
|
|
if model_name not in model_mapping.keys():
|
|
return HttpResponseBadRequest()
|
|
|
|
model = model_mapping[model_name]
|
|
|
|
try:
|
|
limit = int(request.GET.get('limit', 0))
|
|
except ValueError:
|
|
limit = 0
|
|
|
|
try:
|
|
offset = int(request.GET.get('offset', 0))
|
|
except ValueError:
|
|
offset = 0
|
|
|
|
ordering_string, invalid = _validate_input(request.GET.get('orderby', ''),
|
|
model)
|
|
if invalid:
|
|
return HttpResponseBadRequest()
|
|
|
|
filter_string, invalid = _validate_input(request.GET.get('filter', ''),
|
|
model)
|
|
if invalid:
|
|
return HttpResponseBadRequest()
|
|
|
|
search_term = request.GET.get('search', '')
|
|
|
|
if filter_string:
|
|
filter_terms = _get_filtering_terms(filter_string)
|
|
try:
|
|
queryset = model.objects.filter(**filter_terms)
|
|
except ValueError:
|
|
queryset = []
|
|
else:
|
|
queryset = model.objects.all()
|
|
|
|
if search_term:
|
|
queryset = _get_search_results(search_term, queryset, model)
|
|
|
|
if ordering_string and queryset:
|
|
column, order = ordering_string.split(':')
|
|
if order.lower() == DESCENDING:
|
|
queryset = queryset.order_by('-' + column)
|
|
else:
|
|
queryset = queryset.order_by(column)
|
|
|
|
if offset and limit:
|
|
queryset = queryset[offset:(offset+limit)]
|
|
elif offset:
|
|
queryset = queryset[offset:]
|
|
elif limit:
|
|
queryset = queryset[:limit]
|
|
|
|
if queryset:
|
|
response_data['count'] = queryset.count()
|
|
else:
|
|
response_data['count'] = 0
|
|
|
|
response_data['list'] = serializers.serialize('json', queryset)
|
|
|
|
return HttpResponse(json.dumps(response_data),
|
|
content_type='application/json')
|
|
|
|
def _get_filtering_terms(filter_string):
|
|
|
|
search_terms = filter_string.split(":")
|
|
keys = search_terms[0].split(',')
|
|
values = search_terms[1].split(',')
|
|
|
|
return dict(zip(keys, values))
|
|
|
|
def _validate_input(input, model):
|
|
|
|
invalid = 0
|
|
|
|
if input:
|
|
input_list = input.split(":")
|
|
|
|
# Check we have only one colon
|
|
if len(input_list) != 2:
|
|
invalid = 1
|
|
return None, invalid
|
|
|
|
# Check we have an equal number of terms both sides of the colon
|
|
if len(input_list[0].split(',')) != len(input_list[1].split(',')):
|
|
invalid = 1
|
|
return None, invalid
|
|
|
|
# Check we are looking for a valid field
|
|
valid_fields = model._meta.get_all_field_names()
|
|
for field in input_list[0].split(','):
|
|
if field not in valid_fields:
|
|
invalid = 1
|
|
return None, invalid
|
|
|
|
return input, invalid
|
|
|
|
def _get_search_results(search_term, queryset, model):
|
|
search_objects = []
|
|
for st in search_term.split(" "):
|
|
q_map = map(lambda x: Q(**{x+'__icontains': st}),
|
|
model.search_allowed_fields)
|
|
|
|
search_objects.append(reduce(operator.or_, q_map))
|
|
search_object = reduce(operator.and_, search_objects)
|
|
queryset = queryset.filter(search_object)
|
|
|
|
return queryset
|