1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# BitBake Toaster Implementation 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# Copyright (C) 2013 Intel Corporation 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun 9*4882a593Smuzhiyunimport re 10*4882a593Smuzhiyun 11*4882a593Smuzhiyunfrom django.db.models import F, Q, Sum 12*4882a593Smuzhiyunfrom django.db import IntegrityError 13*4882a593Smuzhiyunfrom django.shortcuts import render, redirect, get_object_or_404 14*4882a593Smuzhiyunfrom django.utils.http import urlencode 15*4882a593Smuzhiyunfrom orm.models import Build, Target, Task, Layer, Layer_Version, Recipe 16*4882a593Smuzhiyunfrom orm.models import LogMessage, Variable, Package_Dependency, Package 17*4882a593Smuzhiyunfrom orm.models import Task_Dependency, Package_File 18*4882a593Smuzhiyunfrom orm.models import Target_Installed_Package, Target_File 19*4882a593Smuzhiyunfrom orm.models import TargetKernelFile, TargetSDKFile, Target_Image_File 20*4882a593Smuzhiyunfrom orm.models import BitbakeVersion, CustomImageRecipe 21*4882a593Smuzhiyun 22*4882a593Smuzhiyunfrom django.urls import reverse, resolve 23*4882a593Smuzhiyunfrom django.core.exceptions import ObjectDoesNotExist 24*4882a593Smuzhiyunfrom django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 25*4882a593Smuzhiyunfrom django.http import HttpResponseNotFound, JsonResponse 26*4882a593Smuzhiyunfrom django.utils import timezone 27*4882a593Smuzhiyunfrom datetime import timedelta, datetime 28*4882a593Smuzhiyunfrom toastergui.templatetags.projecttags import json as jsonfilter 29*4882a593Smuzhiyunfrom decimal import Decimal 30*4882a593Smuzhiyunimport json 31*4882a593Smuzhiyunimport os 32*4882a593Smuzhiyunfrom os.path import dirname 33*4882a593Smuzhiyunimport mimetypes 34*4882a593Smuzhiyun 35*4882a593Smuzhiyunimport logging 36*4882a593Smuzhiyun 37*4882a593Smuzhiyunlogger = logging.getLogger("toaster") 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun# Project creation and managed build enable 40*4882a593Smuzhiyunproject_enable = ('1' == os.environ.get('TOASTER_BUILDSERVER')) 41*4882a593Smuzhiyunis_project_specific = ('1' == os.environ.get('TOASTER_PROJECTSPECIFIC')) 42*4882a593Smuzhiyun 43*4882a593Smuzhiyunclass MimeTypeFinder(object): 44*4882a593Smuzhiyun # setting this to False enables additional non-standard mimetypes 45*4882a593Smuzhiyun # to be included in the guess 46*4882a593Smuzhiyun _strict = False 47*4882a593Smuzhiyun 48*4882a593Smuzhiyun # returns the mimetype for a file path as a string, 49*4882a593Smuzhiyun # or 'application/octet-stream' if the type couldn't be guessed 50*4882a593Smuzhiyun @classmethod 51*4882a593Smuzhiyun def get_mimetype(self, path): 52*4882a593Smuzhiyun guess = mimetypes.guess_type(path, self._strict) 53*4882a593Smuzhiyun guessed_type = guess[0] 54*4882a593Smuzhiyun if guessed_type is None: 55*4882a593Smuzhiyun guessed_type = 'application/octet-stream' 56*4882a593Smuzhiyun return guessed_type 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun# single point to add global values into the context before rendering 59*4882a593Smuzhiyundef toaster_render(request, page, context): 60*4882a593Smuzhiyun context['project_enable'] = project_enable 61*4882a593Smuzhiyun context['project_specific'] = is_project_specific 62*4882a593Smuzhiyun return render(request, page, context) 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun# all new sessions should come through the landing page; 66*4882a593Smuzhiyun# determine in which mode we are running in, and redirect appropriately 67*4882a593Smuzhiyundef landing(request): 68*4882a593Smuzhiyun # in build mode, we redirect to the command-line builds page 69*4882a593Smuzhiyun # if there are any builds for the default (cli builds) project 70*4882a593Smuzhiyun default_project = Project.objects.get_or_create_default_project() 71*4882a593Smuzhiyun default_project_builds = Build.objects.filter(project = default_project) 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun # we only redirect to projects page if there is a user-generated project 74*4882a593Smuzhiyun num_builds = Build.objects.all().count() 75*4882a593Smuzhiyun user_projects = Project.objects.filter(is_default = False) 76*4882a593Smuzhiyun has_user_project = user_projects.count() > 0 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun if num_builds == 0 and has_user_project: 79*4882a593Smuzhiyun return redirect(reverse('all-projects'), permanent = False) 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun if num_builds > 0: 82*4882a593Smuzhiyun return redirect(reverse('all-builds'), permanent = False) 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun context = {'lvs_nos' : Layer_Version.objects.all().count()} 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun return toaster_render(request, 'landing.html', context) 87*4882a593Smuzhiyun 88*4882a593Smuzhiyundef objtojson(obj): 89*4882a593Smuzhiyun from django.db.models.query import QuerySet 90*4882a593Smuzhiyun from django.db.models import Model 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun if isinstance(obj, datetime): 93*4882a593Smuzhiyun return obj.isoformat() 94*4882a593Smuzhiyun elif isinstance(obj, timedelta): 95*4882a593Smuzhiyun return obj.total_seconds() 96*4882a593Smuzhiyun elif isinstance(obj, QuerySet) or isinstance(obj, set): 97*4882a593Smuzhiyun return list(obj) 98*4882a593Smuzhiyun elif isinstance(obj, Decimal): 99*4882a593Smuzhiyun return str(obj) 100*4882a593Smuzhiyun elif type(obj).__name__ == "RelatedManager": 101*4882a593Smuzhiyun return [x.pk for x in obj.all()] 102*4882a593Smuzhiyun elif hasattr( obj, '__dict__') and isinstance(obj, Model): 103*4882a593Smuzhiyun d = obj.__dict__ 104*4882a593Smuzhiyun nd = dict(d) 105*4882a593Smuzhiyun for di in d.keys(): 106*4882a593Smuzhiyun if di.startswith("_"): 107*4882a593Smuzhiyun del nd[di] 108*4882a593Smuzhiyun elif isinstance(d[di], Model): 109*4882a593Smuzhiyun nd[di] = d[di].pk 110*4882a593Smuzhiyun elif isinstance(d[di], int) and hasattr(obj, "get_%s_display" % di): 111*4882a593Smuzhiyun nd[di] = getattr(obj, "get_%s_display" % di)() 112*4882a593Smuzhiyun return nd 113*4882a593Smuzhiyun elif isinstance( obj, type(lambda x:x)): 114*4882a593Smuzhiyun import inspect 115*4882a593Smuzhiyun return inspect.getsourcelines(obj)[0] 116*4882a593Smuzhiyun else: 117*4882a593Smuzhiyun raise TypeError("Unserializable object %s (%s) of type %s" % ( obj, dir(obj), type(obj))) 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun 120*4882a593Smuzhiyundef _lv_to_dict(prj, x = None): 121*4882a593Smuzhiyun if x is None: 122*4882a593Smuzhiyun def wrapper(x): 123*4882a593Smuzhiyun return _lv_to_dict(prj, x) 124*4882a593Smuzhiyun return wrapper 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun return {"id": x.pk, 127*4882a593Smuzhiyun "name": x.layer.name, 128*4882a593Smuzhiyun "tooltip": "%s | %s" % (x.layer.vcs_url,x.get_vcs_reference()), 129*4882a593Smuzhiyun "detail": "(%s" % x.layer.vcs_url + (")" if x.release is None else " | "+x.get_vcs_reference()+")"), 130*4882a593Smuzhiyun "giturl": x.layer.vcs_url, 131*4882a593Smuzhiyun "layerdetailurl" : reverse('layerdetails', args=(prj.id,x.pk)), 132*4882a593Smuzhiyun "revision" : x.get_vcs_reference(), 133*4882a593Smuzhiyun } 134*4882a593Smuzhiyun 135*4882a593Smuzhiyun 136*4882a593Smuzhiyundef _build_page_range(paginator, index = 1): 137*4882a593Smuzhiyun try: 138*4882a593Smuzhiyun page = paginator.page(index) 139*4882a593Smuzhiyun except PageNotAnInteger: 140*4882a593Smuzhiyun page = paginator.page(1) 141*4882a593Smuzhiyun except EmptyPage: 142*4882a593Smuzhiyun page = paginator.page(paginator.num_pages) 143*4882a593Smuzhiyun 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun page.page_range = [page.number] 146*4882a593Smuzhiyun crt_range = 0 147*4882a593Smuzhiyun for i in range(1,5): 148*4882a593Smuzhiyun if (page.number + i) <= paginator.num_pages: 149*4882a593Smuzhiyun page.page_range = page.page_range + [ page.number + i] 150*4882a593Smuzhiyun crt_range +=1 151*4882a593Smuzhiyun if (page.number - i) > 0: 152*4882a593Smuzhiyun page.page_range = [page.number -i] + page.page_range 153*4882a593Smuzhiyun crt_range +=1 154*4882a593Smuzhiyun if crt_range == 4: 155*4882a593Smuzhiyun break 156*4882a593Smuzhiyun return page 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun 159*4882a593Smuzhiyundef _verify_parameters(g, mandatory_parameters): 160*4882a593Smuzhiyun miss = [] 161*4882a593Smuzhiyun for mp in mandatory_parameters: 162*4882a593Smuzhiyun if not mp in g: 163*4882a593Smuzhiyun miss.append(mp) 164*4882a593Smuzhiyun if len(miss): 165*4882a593Smuzhiyun return miss 166*4882a593Smuzhiyun return None 167*4882a593Smuzhiyun 168*4882a593Smuzhiyundef _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs): 169*4882a593Smuzhiyun try: 170*4882a593Smuzhiyun from urllib import unquote, urlencode 171*4882a593Smuzhiyun except ImportError: 172*4882a593Smuzhiyun from urllib.parse import unquote, urlencode 173*4882a593Smuzhiyun url = reverse(view, kwargs=kwargs) 174*4882a593Smuzhiyun params = {} 175*4882a593Smuzhiyun for i in g: 176*4882a593Smuzhiyun params[i] = g[i] 177*4882a593Smuzhiyun for i in mandatory_parameters: 178*4882a593Smuzhiyun if not i in params: 179*4882a593Smuzhiyun params[i] = unquote(str(mandatory_parameters[i])) 180*4882a593Smuzhiyun 181*4882a593Smuzhiyun return redirect(url + "?%s" % urlencode(params), permanent = False, **kwargs) 182*4882a593Smuzhiyun 183*4882a593Smuzhiyunclass RedirectException(Exception): 184*4882a593Smuzhiyun def __init__(self, view, g, mandatory_parameters, *args, **kwargs): 185*4882a593Smuzhiyun super(RedirectException, self).__init__() 186*4882a593Smuzhiyun self.view = view 187*4882a593Smuzhiyun self.g = g 188*4882a593Smuzhiyun self.mandatory_parameters = mandatory_parameters 189*4882a593Smuzhiyun self.oargs = args 190*4882a593Smuzhiyun self.okwargs = kwargs 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun def get_redirect_response(self): 193*4882a593Smuzhiyun return _redirect_parameters(self.view, self.g, self.mandatory_parameters, self.oargs, **self.okwargs) 194*4882a593Smuzhiyun 195*4882a593SmuzhiyunFIELD_SEPARATOR = ":" 196*4882a593SmuzhiyunAND_VALUE_SEPARATOR = "!" 197*4882a593SmuzhiyunOR_VALUE_SEPARATOR = "|" 198*4882a593SmuzhiyunDESCENDING = "-" 199*4882a593Smuzhiyun 200*4882a593Smuzhiyundef __get_q_for_val(name, value): 201*4882a593Smuzhiyun if "OR" in value or "AND" in value: 202*4882a593Smuzhiyun result = None 203*4882a593Smuzhiyun for x in value.split("OR"): 204*4882a593Smuzhiyun x = __get_q_for_val(name, x) 205*4882a593Smuzhiyun result = result | x if result else x 206*4882a593Smuzhiyun return result 207*4882a593Smuzhiyun if "AND" in value: 208*4882a593Smuzhiyun result = None 209*4882a593Smuzhiyun for x in value.split("AND"): 210*4882a593Smuzhiyun x = __get_q_for_val(name, x) 211*4882a593Smuzhiyun result = result & x if result else x 212*4882a593Smuzhiyun return result 213*4882a593Smuzhiyun if value.startswith("NOT"): 214*4882a593Smuzhiyun value = value[3:] 215*4882a593Smuzhiyun if value == 'None': 216*4882a593Smuzhiyun value = None 217*4882a593Smuzhiyun kwargs = { name : value } 218*4882a593Smuzhiyun return ~Q(**kwargs) 219*4882a593Smuzhiyun else: 220*4882a593Smuzhiyun if value == 'None': 221*4882a593Smuzhiyun value = None 222*4882a593Smuzhiyun kwargs = { name : value } 223*4882a593Smuzhiyun return Q(**kwargs) 224*4882a593Smuzhiyun 225*4882a593Smuzhiyundef _get_filtering_query(filter_string): 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun search_terms = filter_string.split(FIELD_SEPARATOR) 228*4882a593Smuzhiyun and_keys = search_terms[0].split(AND_VALUE_SEPARATOR) 229*4882a593Smuzhiyun and_values = search_terms[1].split(AND_VALUE_SEPARATOR) 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun and_query = None 232*4882a593Smuzhiyun for kv in zip(and_keys, and_values): 233*4882a593Smuzhiyun or_keys = kv[0].split(OR_VALUE_SEPARATOR) 234*4882a593Smuzhiyun or_values = kv[1].split(OR_VALUE_SEPARATOR) 235*4882a593Smuzhiyun query = None 236*4882a593Smuzhiyun for key, val in zip(or_keys, or_values): 237*4882a593Smuzhiyun x = __get_q_for_val(key, val) 238*4882a593Smuzhiyun query = query | x if query else x 239*4882a593Smuzhiyun 240*4882a593Smuzhiyun and_query = and_query & query if and_query else query 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun return and_query 243*4882a593Smuzhiyun 244*4882a593Smuzhiyundef _get_toggle_order(request, orderkey, toggle_reverse = False): 245*4882a593Smuzhiyun if toggle_reverse: 246*4882a593Smuzhiyun return "%s:+" % orderkey if request.GET.get('orderby', "") == "%s:-" % orderkey else "%s:-" % orderkey 247*4882a593Smuzhiyun else: 248*4882a593Smuzhiyun return "%s:-" % orderkey if request.GET.get('orderby', "") == "%s:+" % orderkey else "%s:+" % orderkey 249*4882a593Smuzhiyun 250*4882a593Smuzhiyundef _get_toggle_order_icon(request, orderkey): 251*4882a593Smuzhiyun if request.GET.get('orderby', "") == "%s:+"%orderkey: 252*4882a593Smuzhiyun return "down" 253*4882a593Smuzhiyun elif request.GET.get('orderby', "") == "%s:-"%orderkey: 254*4882a593Smuzhiyun return "up" 255*4882a593Smuzhiyun else: 256*4882a593Smuzhiyun return None 257*4882a593Smuzhiyun 258*4882a593Smuzhiyun# we check that the input comes in a valid form that we can recognize 259*4882a593Smuzhiyundef _validate_input(field_input, model): 260*4882a593Smuzhiyun 261*4882a593Smuzhiyun invalid = None 262*4882a593Smuzhiyun 263*4882a593Smuzhiyun if field_input: 264*4882a593Smuzhiyun field_input_list = field_input.split(FIELD_SEPARATOR) 265*4882a593Smuzhiyun 266*4882a593Smuzhiyun # Check we have only one colon 267*4882a593Smuzhiyun if len(field_input_list) != 2: 268*4882a593Smuzhiyun invalid = "We have an invalid number of separators: " + field_input + " -> " + str(field_input_list) 269*4882a593Smuzhiyun return None, invalid 270*4882a593Smuzhiyun 271*4882a593Smuzhiyun # Check we have an equal number of terms both sides of the colon 272*4882a593Smuzhiyun if len(field_input_list[0].split(AND_VALUE_SEPARATOR)) != len(field_input_list[1].split(AND_VALUE_SEPARATOR)): 273*4882a593Smuzhiyun invalid = "Not all arg names got values" 274*4882a593Smuzhiyun return None, invalid + str(field_input_list) 275*4882a593Smuzhiyun 276*4882a593Smuzhiyun # Check we are looking for a valid field 277*4882a593Smuzhiyun valid_fields = [f.name for f in model._meta.get_fields()] 278*4882a593Smuzhiyun for field in field_input_list[0].split(AND_VALUE_SEPARATOR): 279*4882a593Smuzhiyun if True in [field.startswith(x) for x in valid_fields]: 280*4882a593Smuzhiyun break 281*4882a593Smuzhiyun else: 282*4882a593Smuzhiyun return None, (field, valid_fields) 283*4882a593Smuzhiyun 284*4882a593Smuzhiyun return field_input, invalid 285*4882a593Smuzhiyun 286*4882a593Smuzhiyun# uses search_allowed_fields in orm/models.py to create a search query 287*4882a593Smuzhiyun# for these fields with the supplied input text 288*4882a593Smuzhiyundef _get_search_results(search_term, queryset, model): 289*4882a593Smuzhiyun search_object = None 290*4882a593Smuzhiyun for st in search_term.split(" "): 291*4882a593Smuzhiyun queries = None 292*4882a593Smuzhiyun for field in model.search_allowed_fields: 293*4882a593Smuzhiyun query = Q(**{field + '__icontains': st}) 294*4882a593Smuzhiyun queries = queries | query if queries else query 295*4882a593Smuzhiyun 296*4882a593Smuzhiyun search_object = search_object & queries if search_object else queries 297*4882a593Smuzhiyun queryset = queryset.filter(search_object) 298*4882a593Smuzhiyun 299*4882a593Smuzhiyun return queryset 300*4882a593Smuzhiyun 301*4882a593Smuzhiyun 302*4882a593Smuzhiyun# function to extract the search/filter/ordering parameters from the request 303*4882a593Smuzhiyun# it uses the request and the model to validate input for the filter and orderby values 304*4882a593Smuzhiyundef _search_tuple(request, model): 305*4882a593Smuzhiyun ordering_string, invalid = _validate_input(request.GET.get('orderby', ''), model) 306*4882a593Smuzhiyun if invalid: 307*4882a593Smuzhiyun raise BaseException("Invalid ordering model:" + str(model) + str(invalid)) 308*4882a593Smuzhiyun 309*4882a593Smuzhiyun filter_string, invalid = _validate_input(request.GET.get('filter', ''), model) 310*4882a593Smuzhiyun if invalid: 311*4882a593Smuzhiyun raise BaseException("Invalid filter " + str(invalid)) 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun search_term = request.GET.get('search', '') 314*4882a593Smuzhiyun return (filter_string, search_term, ordering_string) 315*4882a593Smuzhiyun 316*4882a593Smuzhiyun 317*4882a593Smuzhiyun# returns a lazy-evaluated queryset for a filter/search/order combination 318*4882a593Smuzhiyundef _get_queryset(model, queryset, filter_string, search_term, ordering_string, ordering_secondary=''): 319*4882a593Smuzhiyun if filter_string: 320*4882a593Smuzhiyun filter_query = _get_filtering_query(filter_string) 321*4882a593Smuzhiyun queryset = queryset.filter(filter_query) 322*4882a593Smuzhiyun else: 323*4882a593Smuzhiyun queryset = queryset.all() 324*4882a593Smuzhiyun 325*4882a593Smuzhiyun if search_term: 326*4882a593Smuzhiyun queryset = _get_search_results(search_term, queryset, model) 327*4882a593Smuzhiyun 328*4882a593Smuzhiyun if ordering_string: 329*4882a593Smuzhiyun column, order = ordering_string.split(':') 330*4882a593Smuzhiyun if column == re.sub('-','',ordering_secondary): 331*4882a593Smuzhiyun ordering_secondary='' 332*4882a593Smuzhiyun if order.lower() == DESCENDING: 333*4882a593Smuzhiyun column = '-' + column 334*4882a593Smuzhiyun if ordering_secondary: 335*4882a593Smuzhiyun queryset = queryset.order_by(column, ordering_secondary) 336*4882a593Smuzhiyun else: 337*4882a593Smuzhiyun queryset = queryset.order_by(column) 338*4882a593Smuzhiyun 339*4882a593Smuzhiyun # insure only distinct records (e.g. from multiple search hits) are returned 340*4882a593Smuzhiyun return queryset.distinct() 341*4882a593Smuzhiyun 342*4882a593Smuzhiyun# returns the value of entries per page and the name of the applied sorting field. 343*4882a593Smuzhiyun# if the value is given explicitly as a GET parameter it will be the first selected, 344*4882a593Smuzhiyun# otherwise the cookie value will be used. 345*4882a593Smuzhiyundef _get_parameters_values(request, default_count, default_order): 346*4882a593Smuzhiyun current_url = resolve(request.path_info).url_name 347*4882a593Smuzhiyun pagesize = request.GET.get('count', request.session.get('%s_count' % current_url, default_count)) 348*4882a593Smuzhiyun orderby = request.GET.get('orderby', request.session.get('%s_orderby' % current_url, default_order)) 349*4882a593Smuzhiyun return (pagesize, orderby) 350*4882a593Smuzhiyun 351*4882a593Smuzhiyun 352*4882a593Smuzhiyun# set cookies for parameters. this is usefull in case parameters are set 353*4882a593Smuzhiyun# manually from the GET values of the link 354*4882a593Smuzhiyundef _set_parameters_values(pagesize, orderby, request): 355*4882a593Smuzhiyun from django.urls import resolve 356*4882a593Smuzhiyun current_url = resolve(request.path_info).url_name 357*4882a593Smuzhiyun request.session['%s_count' % current_url] = pagesize 358*4882a593Smuzhiyun request.session['%s_orderby' % current_url] =orderby 359*4882a593Smuzhiyun 360*4882a593Smuzhiyun# date range: normalize GUI's dd/mm/yyyy to date object 361*4882a593Smuzhiyundef _normalize_input_date(date_str,default): 362*4882a593Smuzhiyun date_str=re.sub('/', '-', date_str) 363*4882a593Smuzhiyun # accept dd/mm/yyyy to d/m/yy 364*4882a593Smuzhiyun try: 365*4882a593Smuzhiyun date_in = datetime.strptime(date_str, "%d-%m-%Y") 366*4882a593Smuzhiyun except ValueError: 367*4882a593Smuzhiyun # courtesy try with two digit year 368*4882a593Smuzhiyun try: 369*4882a593Smuzhiyun date_in = datetime.strptime(date_str, "%d-%m-%y") 370*4882a593Smuzhiyun except ValueError: 371*4882a593Smuzhiyun return default 372*4882a593Smuzhiyun date_in = date_in.replace(tzinfo=default.tzinfo) 373*4882a593Smuzhiyun return date_in 374*4882a593Smuzhiyun 375*4882a593Smuzhiyun# convert and normalize any received date range filter, for example: 376*4882a593Smuzhiyun# "completed_on__gte!completed_on__lt:01/03/2015!02/03/2015_daterange" to 377*4882a593Smuzhiyun# "completed_on__gte!completed_on__lt:2015-03-01!2015-03-02" 378*4882a593Smuzhiyundef _modify_date_range_filter(filter_string): 379*4882a593Smuzhiyun # was the date range radio button selected? 380*4882a593Smuzhiyun if 0 > filter_string.find('_daterange'): 381*4882a593Smuzhiyun return filter_string,'' 382*4882a593Smuzhiyun # normalize GUI dates to database format 383*4882a593Smuzhiyun filter_string = filter_string.replace('_daterange','').replace(':','!'); 384*4882a593Smuzhiyun filter_list = filter_string.split('!'); 385*4882a593Smuzhiyun if 4 != len(filter_list): 386*4882a593Smuzhiyun return filter_string 387*4882a593Smuzhiyun today = timezone.localtime(timezone.now()) 388*4882a593Smuzhiyun date_id = filter_list[1] 389*4882a593Smuzhiyun date_from = _normalize_input_date(filter_list[2],today) 390*4882a593Smuzhiyun date_to = _normalize_input_date(filter_list[3],today) 391*4882a593Smuzhiyun # swap dates if manually set dates are out of order 392*4882a593Smuzhiyun if date_to < date_from: 393*4882a593Smuzhiyun date_to,date_from = date_from,date_to 394*4882a593Smuzhiyun # convert to strings, make 'date_to' inclusive by moving to begining of next day 395*4882a593Smuzhiyun date_from_str = date_from.strftime("%Y-%m-%d") 396*4882a593Smuzhiyun date_to_str = (date_to+timedelta(days=1)).strftime("%Y-%m-%d") 397*4882a593Smuzhiyun filter_string=filter_list[0]+'!'+filter_list[1]+':'+date_from_str+'!'+date_to_str 398*4882a593Smuzhiyun daterange_selected = re.sub('__.*','', date_id) 399*4882a593Smuzhiyun return filter_string,daterange_selected 400*4882a593Smuzhiyun 401*4882a593Smuzhiyundef _add_daterange_context(queryset_all, request, daterange_list): 402*4882a593Smuzhiyun # calculate the exact begining of local today and yesterday 403*4882a593Smuzhiyun today_begin = timezone.localtime(timezone.now()) 404*4882a593Smuzhiyun yesterday_begin = today_begin - timedelta(days=1) 405*4882a593Smuzhiyun # add daterange persistent 406*4882a593Smuzhiyun context_date = {} 407*4882a593Smuzhiyun context_date['last_date_from'] = request.GET.get('last_date_from',timezone.localtime(timezone.now()).strftime("%d/%m/%Y")) 408*4882a593Smuzhiyun context_date['last_date_to' ] = request.GET.get('last_date_to' ,context_date['last_date_from']) 409*4882a593Smuzhiyun # calculate the date ranges, avoid second sort for 'created' 410*4882a593Smuzhiyun # fetch the respective max range from the database 411*4882a593Smuzhiyun context_date['daterange_filter']='' 412*4882a593Smuzhiyun for key in daterange_list: 413*4882a593Smuzhiyun queryset_key = queryset_all.order_by(key) 414*4882a593Smuzhiyun try: 415*4882a593Smuzhiyun context_date['dateMin_'+key]=timezone.localtime(getattr(queryset_key.first(),key)).strftime("%d/%m/%Y") 416*4882a593Smuzhiyun except AttributeError: 417*4882a593Smuzhiyun context_date['dateMin_'+key]=timezone.localtime(timezone.now()) 418*4882a593Smuzhiyun try: 419*4882a593Smuzhiyun context_date['dateMax_'+key]=timezone.localtime(getattr(queryset_key.last(),key)).strftime("%d/%m/%Y") 420*4882a593Smuzhiyun except AttributeError: 421*4882a593Smuzhiyun context_date['dateMax_'+key]=timezone.localtime(timezone.now()) 422*4882a593Smuzhiyun return context_date,today_begin,yesterday_begin 423*4882a593Smuzhiyun 424*4882a593Smuzhiyun 425*4882a593Smuzhiyun## 426*4882a593Smuzhiyun# build dashboard for a single build, coming in as argument 427*4882a593Smuzhiyun# Each build may contain multiple targets and each target 428*4882a593Smuzhiyun# may generate multiple image files. display them all. 429*4882a593Smuzhiyun# 430*4882a593Smuzhiyundef builddashboard( request, build_id ): 431*4882a593Smuzhiyun template = "builddashboard.html" 432*4882a593Smuzhiyun if Build.objects.filter( pk=build_id ).count( ) == 0 : 433*4882a593Smuzhiyun return redirect( builds ) 434*4882a593Smuzhiyun build = Build.objects.get( pk = build_id ); 435*4882a593Smuzhiyun layerVersionId = Layer_Version.objects.filter( build = build_id ); 436*4882a593Smuzhiyun recipeCount = Recipe.objects.filter( layer_version__id__in = layerVersionId ).count( ); 437*4882a593Smuzhiyun tgts = Target.objects.filter( build_id = build_id ).order_by( 'target' ); 438*4882a593Smuzhiyun 439*4882a593Smuzhiyun # set up custom target list with computed package and image data 440*4882a593Smuzhiyun targets = [] 441*4882a593Smuzhiyun ntargets = 0 442*4882a593Smuzhiyun 443*4882a593Smuzhiyun # True if at least one target for this build has an SDK artifact 444*4882a593Smuzhiyun # or image file 445*4882a593Smuzhiyun has_artifacts = False 446*4882a593Smuzhiyun 447*4882a593Smuzhiyun for t in tgts: 448*4882a593Smuzhiyun elem = {} 449*4882a593Smuzhiyun elem['target'] = t 450*4882a593Smuzhiyun 451*4882a593Smuzhiyun target_has_images = False 452*4882a593Smuzhiyun image_files = [] 453*4882a593Smuzhiyun 454*4882a593Smuzhiyun npkg = 0 455*4882a593Smuzhiyun pkgsz = 0 456*4882a593Smuzhiyun package = None 457*4882a593Smuzhiyun # Chunk the query to avoid "too many SQL variables" error 458*4882a593Smuzhiyun package_set = t.target_installed_package_set.all() 459*4882a593Smuzhiyun package_set_len = len(package_set) 460*4882a593Smuzhiyun for ps_start in range(0,package_set_len,500): 461*4882a593Smuzhiyun ps_stop = min(ps_start+500,package_set_len) 462*4882a593Smuzhiyun for package in Package.objects.filter(id__in = [x.package_id for x in package_set[ps_start:ps_stop]]): 463*4882a593Smuzhiyun pkgsz = pkgsz + package.size 464*4882a593Smuzhiyun if package.installed_name: 465*4882a593Smuzhiyun npkg = npkg + 1 466*4882a593Smuzhiyun elem['npkg'] = npkg 467*4882a593Smuzhiyun elem['pkgsz'] = pkgsz 468*4882a593Smuzhiyun ti = Target_Image_File.objects.filter(target_id = t.id) 469*4882a593Smuzhiyun for i in ti: 470*4882a593Smuzhiyun ndx = i.file_name.rfind('/') 471*4882a593Smuzhiyun if ndx < 0: 472*4882a593Smuzhiyun ndx = 0; 473*4882a593Smuzhiyun f = i.file_name[ndx + 1:] 474*4882a593Smuzhiyun image_files.append({ 475*4882a593Smuzhiyun 'id': i.id, 476*4882a593Smuzhiyun 'path': f, 477*4882a593Smuzhiyun 'size': i.file_size, 478*4882a593Smuzhiyun 'suffix': i.suffix 479*4882a593Smuzhiyun }) 480*4882a593Smuzhiyun if len(image_files) > 0: 481*4882a593Smuzhiyun target_has_images = True 482*4882a593Smuzhiyun elem['targetHasImages'] = target_has_images 483*4882a593Smuzhiyun 484*4882a593Smuzhiyun elem['imageFiles'] = image_files 485*4882a593Smuzhiyun elem['target_kernel_artifacts'] = t.targetkernelfile_set.all() 486*4882a593Smuzhiyun 487*4882a593Smuzhiyun target_sdk_files = t.targetsdkfile_set.all() 488*4882a593Smuzhiyun target_sdk_artifacts_count = target_sdk_files.count() 489*4882a593Smuzhiyun elem['target_sdk_artifacts_count'] = target_sdk_artifacts_count 490*4882a593Smuzhiyun elem['target_sdk_artifacts'] = target_sdk_files 491*4882a593Smuzhiyun 492*4882a593Smuzhiyun if target_has_images or target_sdk_artifacts_count > 0: 493*4882a593Smuzhiyun has_artifacts = True 494*4882a593Smuzhiyun 495*4882a593Smuzhiyun targets.append(elem) 496*4882a593Smuzhiyun 497*4882a593Smuzhiyun ## 498*4882a593Smuzhiyun # how many packages in this build - ignore anonymous ones 499*4882a593Smuzhiyun # 500*4882a593Smuzhiyun 501*4882a593Smuzhiyun packageCount = 0 502*4882a593Smuzhiyun packages = Package.objects.filter( build_id = build_id ) 503*4882a593Smuzhiyun for p in packages: 504*4882a593Smuzhiyun if ( p.installed_name ): 505*4882a593Smuzhiyun packageCount = packageCount + 1 506*4882a593Smuzhiyun 507*4882a593Smuzhiyun logmessages = list(LogMessage.objects.filter( build = build_id )) 508*4882a593Smuzhiyun 509*4882a593Smuzhiyun context = { 510*4882a593Smuzhiyun 'build' : build, 511*4882a593Smuzhiyun 'project' : build.project, 512*4882a593Smuzhiyun 'hasArtifacts' : has_artifacts, 513*4882a593Smuzhiyun 'ntargets' : ntargets, 514*4882a593Smuzhiyun 'targets' : targets, 515*4882a593Smuzhiyun 'recipecount' : recipeCount, 516*4882a593Smuzhiyun 'packagecount' : packageCount, 517*4882a593Smuzhiyun 'logmessages' : logmessages, 518*4882a593Smuzhiyun } 519*4882a593Smuzhiyun return toaster_render( request, template, context ) 520*4882a593Smuzhiyun 521*4882a593Smuzhiyun 522*4882a593Smuzhiyun 523*4882a593Smuzhiyundef generateCoveredList2( revlist = None ): 524*4882a593Smuzhiyun if not revlist: 525*4882a593Smuzhiyun revlist = [] 526*4882a593Smuzhiyun covered_list = [ x for x in revlist if x.outcome == Task.OUTCOME_COVERED ] 527*4882a593Smuzhiyun while len(covered_list): 528*4882a593Smuzhiyun revlist = [ x for x in revlist if x.outcome != Task.OUTCOME_COVERED ] 529*4882a593Smuzhiyun if len(revlist) > 0: 530*4882a593Smuzhiyun return revlist 531*4882a593Smuzhiyun 532*4882a593Smuzhiyun newlist = _find_task_revdep_list(covered_list) 533*4882a593Smuzhiyun 534*4882a593Smuzhiyun revlist = list(set(revlist + newlist)) 535*4882a593Smuzhiyun covered_list = [ x for x in revlist if x.outcome == Task.OUTCOME_COVERED ] 536*4882a593Smuzhiyun return revlist 537*4882a593Smuzhiyun 538*4882a593Smuzhiyundef task( request, build_id, task_id ): 539*4882a593Smuzhiyun template = "task.html" 540*4882a593Smuzhiyun tasks_list = Task.objects.filter( pk=task_id ) 541*4882a593Smuzhiyun if tasks_list.count( ) == 0: 542*4882a593Smuzhiyun return redirect( builds ) 543*4882a593Smuzhiyun task_object = tasks_list[ 0 ]; 544*4882a593Smuzhiyun dependencies = sorted( 545*4882a593Smuzhiyun _find_task_dep( task_object ), 546*4882a593Smuzhiyun key=lambda t:'%s_%s %s'%(t.recipe.name, t.recipe.version, t.task_name)) 547*4882a593Smuzhiyun reverse_dependencies = sorted( 548*4882a593Smuzhiyun _find_task_revdep( task_object ), 549*4882a593Smuzhiyun key=lambda t:'%s_%s %s'%( t.recipe.name, t.recipe.version, t.task_name )) 550*4882a593Smuzhiyun coveredBy = ''; 551*4882a593Smuzhiyun if ( task_object.outcome == Task.OUTCOME_COVERED ): 552*4882a593Smuzhiyun# _list = generateCoveredList( task ) 553*4882a593Smuzhiyun coveredBy = sorted(generateCoveredList2( _find_task_revdep( task_object ) ), key = lambda x: x.recipe.name) 554*4882a593Smuzhiyun log_head = '' 555*4882a593Smuzhiyun log_body = '' 556*4882a593Smuzhiyun if task_object.outcome == task_object.OUTCOME_FAILED: 557*4882a593Smuzhiyun pass 558*4882a593Smuzhiyun 559*4882a593Smuzhiyun uri_list= [ ] 560*4882a593Smuzhiyun variables = Variable.objects.filter(build=build_id) 561*4882a593Smuzhiyun v=variables.filter(variable_name='SSTATE_DIR') 562*4882a593Smuzhiyun if v.count() > 0: 563*4882a593Smuzhiyun uri_list.append(v[0].variable_value) 564*4882a593Smuzhiyun v=variables.filter(variable_name='SSTATE_MIRRORS') 565*4882a593Smuzhiyun if (v.count() > 0): 566*4882a593Smuzhiyun for mirror in v[0].variable_value.split('\\n'): 567*4882a593Smuzhiyun s=re.sub('.* ','',mirror.strip(' \t\n\r')) 568*4882a593Smuzhiyun if len(s): 569*4882a593Smuzhiyun uri_list.append(s) 570*4882a593Smuzhiyun 571*4882a593Smuzhiyun context = { 572*4882a593Smuzhiyun 'build' : Build.objects.filter( pk = build_id )[ 0 ], 573*4882a593Smuzhiyun 'object' : task_object, 574*4882a593Smuzhiyun 'task' : task_object, 575*4882a593Smuzhiyun 'covered_by' : coveredBy, 576*4882a593Smuzhiyun 'deps' : dependencies, 577*4882a593Smuzhiyun 'rdeps' : reverse_dependencies, 578*4882a593Smuzhiyun 'log_head' : log_head, 579*4882a593Smuzhiyun 'log_body' : log_body, 580*4882a593Smuzhiyun 'showing_matches' : False, 581*4882a593Smuzhiyun 'uri_list' : uri_list, 582*4882a593Smuzhiyun 'task_in_tasks_table_pg': int(task_object.order / 25) + 1 583*4882a593Smuzhiyun } 584*4882a593Smuzhiyun if request.GET.get( 'show_matches', "" ): 585*4882a593Smuzhiyun context[ 'showing_matches' ] = True 586*4882a593Smuzhiyun context[ 'matching_tasks' ] = Task.objects.filter( 587*4882a593Smuzhiyun sstate_checksum=task_object.sstate_checksum ).filter( 588*4882a593Smuzhiyun build__completed_on__lt=task_object.build.completed_on).exclude( 589*4882a593Smuzhiyun order__isnull=True).exclude(outcome=Task.OUTCOME_NA).order_by('-build__completed_on') 590*4882a593Smuzhiyun 591*4882a593Smuzhiyun return toaster_render( request, template, context ) 592*4882a593Smuzhiyun 593*4882a593Smuzhiyundef recipe(request, build_id, recipe_id, active_tab="1"): 594*4882a593Smuzhiyun template = "recipe.html" 595*4882a593Smuzhiyun if Recipe.objects.filter(pk=recipe_id).count() == 0 : 596*4882a593Smuzhiyun return redirect(builds) 597*4882a593Smuzhiyun 598*4882a593Smuzhiyun recipe_object = Recipe.objects.get(pk=recipe_id) 599*4882a593Smuzhiyun layer_version = Layer_Version.objects.get(pk=recipe_object.layer_version_id) 600*4882a593Smuzhiyun layer = Layer.objects.get(pk=layer_version.layer_id) 601*4882a593Smuzhiyun tasks_list = Task.objects.filter(recipe_id = recipe_id, build_id = build_id).exclude(order__isnull=True).exclude(task_name__endswith='_setscene').exclude(outcome=Task.OUTCOME_NA) 602*4882a593Smuzhiyun package_count = Package.objects.filter(recipe_id = recipe_id).filter(build_id = build_id).filter(size__gte=0).count() 603*4882a593Smuzhiyun 604*4882a593Smuzhiyun if active_tab != '1' and active_tab != '3' and active_tab != '4' : 605*4882a593Smuzhiyun active_tab = '1' 606*4882a593Smuzhiyun tab_states = {'1': '', '3': '', '4': ''} 607*4882a593Smuzhiyun tab_states[active_tab] = 'active' 608*4882a593Smuzhiyun 609*4882a593Smuzhiyun context = { 610*4882a593Smuzhiyun 'build' : Build.objects.get(pk=build_id), 611*4882a593Smuzhiyun 'object' : recipe_object, 612*4882a593Smuzhiyun 'layer_version' : layer_version, 613*4882a593Smuzhiyun 'layer' : layer, 614*4882a593Smuzhiyun 'tasks' : tasks_list, 615*4882a593Smuzhiyun 'package_count' : package_count, 616*4882a593Smuzhiyun 'tab_states' : tab_states, 617*4882a593Smuzhiyun } 618*4882a593Smuzhiyun return toaster_render(request, template, context) 619*4882a593Smuzhiyun 620*4882a593Smuzhiyundef recipe_packages(request, build_id, recipe_id): 621*4882a593Smuzhiyun template = "recipe_packages.html" 622*4882a593Smuzhiyun if Recipe.objects.filter(pk=recipe_id).count() == 0 : 623*4882a593Smuzhiyun return redirect(builds) 624*4882a593Smuzhiyun 625*4882a593Smuzhiyun (pagesize, orderby) = _get_parameters_values(request, 10, 'name:+') 626*4882a593Smuzhiyun mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': orderby } 627*4882a593Smuzhiyun retval = _verify_parameters( request.GET, mandatory_parameters ) 628*4882a593Smuzhiyun if retval: 629*4882a593Smuzhiyun return _redirect_parameters( 'recipe_packages', request.GET, mandatory_parameters, build_id = build_id, recipe_id = recipe_id) 630*4882a593Smuzhiyun (filter_string, search_term, ordering_string) = _search_tuple(request, Package) 631*4882a593Smuzhiyun 632*4882a593Smuzhiyun recipe_object = Recipe.objects.get(pk=recipe_id) 633*4882a593Smuzhiyun queryset = Package.objects.filter(recipe_id = recipe_id).filter(build_id = build_id).filter(size__gte=0) 634*4882a593Smuzhiyun package_count = queryset.count() 635*4882a593Smuzhiyun queryset = _get_queryset(Package, queryset, filter_string, search_term, ordering_string, 'name') 636*4882a593Smuzhiyun 637*4882a593Smuzhiyun packages = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1)) 638*4882a593Smuzhiyun 639*4882a593Smuzhiyun context = { 640*4882a593Smuzhiyun 'build' : Build.objects.get(pk=build_id), 641*4882a593Smuzhiyun 'recipe' : recipe_object, 642*4882a593Smuzhiyun 'objects' : packages, 643*4882a593Smuzhiyun 'object_count' : package_count, 644*4882a593Smuzhiyun 'tablecols':[ 645*4882a593Smuzhiyun { 646*4882a593Smuzhiyun 'name':'Package', 647*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request,"name"), 648*4882a593Smuzhiyun 'ordericon': _get_toggle_order_icon(request,"name"), 649*4882a593Smuzhiyun 'orderkey': "name", 650*4882a593Smuzhiyun }, 651*4882a593Smuzhiyun { 652*4882a593Smuzhiyun 'name':'Version', 653*4882a593Smuzhiyun }, 654*4882a593Smuzhiyun { 655*4882a593Smuzhiyun 'name':'Size', 656*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request,"size", True), 657*4882a593Smuzhiyun 'ordericon': _get_toggle_order_icon(request,"size"), 658*4882a593Smuzhiyun 'orderkey': 'size', 659*4882a593Smuzhiyun 'dclass': 'sizecol span2', 660*4882a593Smuzhiyun }, 661*4882a593Smuzhiyun ] 662*4882a593Smuzhiyun } 663*4882a593Smuzhiyun response = toaster_render(request, template, context) 664*4882a593Smuzhiyun _set_parameters_values(pagesize, orderby, request) 665*4882a593Smuzhiyun return response 666*4882a593Smuzhiyun 667*4882a593Smuzhiyunfrom django.http import HttpResponse 668*4882a593Smuzhiyundef xhr_dirinfo(request, build_id, target_id): 669*4882a593Smuzhiyun top = request.GET.get('start', '/') 670*4882a593Smuzhiyun return HttpResponse(_get_dir_entries(build_id, target_id, top), content_type = "application/json") 671*4882a593Smuzhiyun 672*4882a593Smuzhiyunfrom django.utils.functional import Promise 673*4882a593Smuzhiyunfrom django.utils.encoding import force_text 674*4882a593Smuzhiyunclass LazyEncoder(json.JSONEncoder): 675*4882a593Smuzhiyun def default(self, obj): 676*4882a593Smuzhiyun if isinstance(obj, Promise): 677*4882a593Smuzhiyun return force_text(obj) 678*4882a593Smuzhiyun return super(LazyEncoder, self).default(obj) 679*4882a593Smuzhiyun 680*4882a593Smuzhiyunfrom toastergui.templatetags.projecttags import filtered_filesizeformat 681*4882a593Smuzhiyunimport os 682*4882a593Smuzhiyundef _get_dir_entries(build_id, target_id, start): 683*4882a593Smuzhiyun node_str = { 684*4882a593Smuzhiyun Target_File.ITYPE_REGULAR : '-', 685*4882a593Smuzhiyun Target_File.ITYPE_DIRECTORY : 'd', 686*4882a593Smuzhiyun Target_File.ITYPE_SYMLINK : 'l', 687*4882a593Smuzhiyun Target_File.ITYPE_SOCKET : 's', 688*4882a593Smuzhiyun Target_File.ITYPE_FIFO : 'p', 689*4882a593Smuzhiyun Target_File.ITYPE_CHARACTER : 'c', 690*4882a593Smuzhiyun Target_File.ITYPE_BLOCK : 'b', 691*4882a593Smuzhiyun } 692*4882a593Smuzhiyun response = [] 693*4882a593Smuzhiyun objects = Target_File.objects.filter(target__exact=target_id, directory__path=start) 694*4882a593Smuzhiyun target_packages = Target_Installed_Package.objects.filter(target__exact=target_id).values_list('package_id', flat=True) 695*4882a593Smuzhiyun for o in objects: 696*4882a593Smuzhiyun # exclude root inode '/' 697*4882a593Smuzhiyun if o.path == '/': 698*4882a593Smuzhiyun continue 699*4882a593Smuzhiyun try: 700*4882a593Smuzhiyun entry = {} 701*4882a593Smuzhiyun entry['parent'] = start 702*4882a593Smuzhiyun entry['name'] = os.path.basename(o.path) 703*4882a593Smuzhiyun entry['fullpath'] = o.path 704*4882a593Smuzhiyun 705*4882a593Smuzhiyun # set defaults, not all dentries have packages 706*4882a593Smuzhiyun entry['installed_package'] = None 707*4882a593Smuzhiyun entry['package_id'] = None 708*4882a593Smuzhiyun entry['package'] = None 709*4882a593Smuzhiyun entry['link_to'] = None 710*4882a593Smuzhiyun if o.inodetype == Target_File.ITYPE_DIRECTORY: 711*4882a593Smuzhiyun entry['isdir'] = 1 712*4882a593Smuzhiyun # is there content in directory 713*4882a593Smuzhiyun entry['childcount'] = Target_File.objects.filter(target__exact=target_id, directory__path=o.path).all().count() 714*4882a593Smuzhiyun else: 715*4882a593Smuzhiyun entry['isdir'] = 0 716*4882a593Smuzhiyun 717*4882a593Smuzhiyun # resolve the file to get the package from the resolved file 718*4882a593Smuzhiyun resolved_id = o.sym_target_id 719*4882a593Smuzhiyun resolved_path = o.path 720*4882a593Smuzhiyun if target_packages.count(): 721*4882a593Smuzhiyun while resolved_id != "" and resolved_id is not None: 722*4882a593Smuzhiyun tf = Target_File.objects.get(pk=resolved_id) 723*4882a593Smuzhiyun resolved_path = tf.path 724*4882a593Smuzhiyun resolved_id = tf.sym_target_id 725*4882a593Smuzhiyun 726*4882a593Smuzhiyun thisfile=Package_File.objects.all().filter(path__exact=resolved_path, package_id__in=target_packages) 727*4882a593Smuzhiyun if thisfile.count(): 728*4882a593Smuzhiyun p = Package.objects.get(pk=thisfile[0].package_id) 729*4882a593Smuzhiyun entry['installed_package'] = p.installed_name 730*4882a593Smuzhiyun entry['package_id'] = str(p.id) 731*4882a593Smuzhiyun entry['package'] = p.name 732*4882a593Smuzhiyun # don't use resolved path from above, show immediate link-to 733*4882a593Smuzhiyun if o.sym_target_id != "" and o.sym_target_id is not None: 734*4882a593Smuzhiyun entry['link_to'] = Target_File.objects.get(pk=o.sym_target_id).path 735*4882a593Smuzhiyun entry['size'] = filtered_filesizeformat(o.size) 736*4882a593Smuzhiyun if entry['link_to'] is not None: 737*4882a593Smuzhiyun entry['permission'] = node_str[o.inodetype] + o.permission 738*4882a593Smuzhiyun else: 739*4882a593Smuzhiyun entry['permission'] = node_str[o.inodetype] + o.permission 740*4882a593Smuzhiyun entry['owner'] = o.owner 741*4882a593Smuzhiyun entry['group'] = o.group 742*4882a593Smuzhiyun response.append(entry) 743*4882a593Smuzhiyun 744*4882a593Smuzhiyun except Exception as e: 745*4882a593Smuzhiyun print("Exception ", e) 746*4882a593Smuzhiyun traceback.print_exc() 747*4882a593Smuzhiyun 748*4882a593Smuzhiyun # sort by directories first, then by name 749*4882a593Smuzhiyun rsorted = sorted(response, key=lambda entry : entry['name']) 750*4882a593Smuzhiyun rsorted = sorted(rsorted, key=lambda entry : entry['isdir'], reverse=True) 751*4882a593Smuzhiyun return json.dumps(rsorted, cls=LazyEncoder).replace('</', '<\\/') 752*4882a593Smuzhiyun 753*4882a593Smuzhiyundef dirinfo(request, build_id, target_id, file_path=None): 754*4882a593Smuzhiyun template = "dirinfo.html" 755*4882a593Smuzhiyun objects = _get_dir_entries(build_id, target_id, '/') 756*4882a593Smuzhiyun packages_sum = Package.objects.filter(id__in=Target_Installed_Package.objects.filter(target_id=target_id).values('package_id')).aggregate(Sum('installed_size')) 757*4882a593Smuzhiyun dir_list = None 758*4882a593Smuzhiyun if file_path is not None: 759*4882a593Smuzhiyun """ 760*4882a593Smuzhiyun Link from the included package detail file list page and is 761*4882a593Smuzhiyun requesting opening the dir info to a specific file path. 762*4882a593Smuzhiyun Provide the list of directories to expand and the full path to 763*4882a593Smuzhiyun highlight in the page. 764*4882a593Smuzhiyun """ 765*4882a593Smuzhiyun # Aassume target's path separator matches host's, that is, os.sep 766*4882a593Smuzhiyun sep = os.sep 767*4882a593Smuzhiyun dir_list = [] 768*4882a593Smuzhiyun head = file_path 769*4882a593Smuzhiyun while head != sep: 770*4882a593Smuzhiyun (head, tail) = os.path.split(head) 771*4882a593Smuzhiyun if head != sep: 772*4882a593Smuzhiyun dir_list.insert(0, head) 773*4882a593Smuzhiyun 774*4882a593Smuzhiyun build = Build.objects.get(pk=build_id) 775*4882a593Smuzhiyun 776*4882a593Smuzhiyun context = { 'build': build, 777*4882a593Smuzhiyun 'project': build.project, 778*4882a593Smuzhiyun 'target': Target.objects.get(pk=target_id), 779*4882a593Smuzhiyun 'packages_sum': packages_sum['installed_size__sum'], 780*4882a593Smuzhiyun 'objects': objects, 781*4882a593Smuzhiyun 'dir_list': dir_list, 782*4882a593Smuzhiyun 'file_path': file_path, 783*4882a593Smuzhiyun } 784*4882a593Smuzhiyun return toaster_render(request, template, context) 785*4882a593Smuzhiyun 786*4882a593Smuzhiyundef _find_task_dep(task_object): 787*4882a593Smuzhiyun tdeps = Task_Dependency.objects.filter(task=task_object).filter(depends_on__order__gt=0) 788*4882a593Smuzhiyun tdeps = tdeps.exclude(depends_on__outcome=Task.OUTCOME_NA).select_related("depends_on") 789*4882a593Smuzhiyun return [x.depends_on for x in tdeps] 790*4882a593Smuzhiyun 791*4882a593Smuzhiyundef _find_task_revdep(task_object): 792*4882a593Smuzhiyun tdeps = Task_Dependency.objects.filter(depends_on=task_object).filter(task__order__gt=0) 793*4882a593Smuzhiyun tdeps = tdeps.exclude(task__outcome = Task.OUTCOME_NA).select_related("task", "task__recipe", "task__build") 794*4882a593Smuzhiyun 795*4882a593Smuzhiyun # exclude self-dependencies to prevent infinite dependency loop 796*4882a593Smuzhiyun # in generateCoveredList2() 797*4882a593Smuzhiyun tdeps = tdeps.exclude(task=task_object) 798*4882a593Smuzhiyun 799*4882a593Smuzhiyun return [tdep.task for tdep in tdeps] 800*4882a593Smuzhiyun 801*4882a593Smuzhiyundef _find_task_revdep_list(tasklist): 802*4882a593Smuzhiyun tdeps = Task_Dependency.objects.filter(depends_on__in=tasklist).filter(task__order__gt=0) 803*4882a593Smuzhiyun tdeps = tdeps.exclude(task__outcome=Task.OUTCOME_NA).select_related("task", "task__recipe", "task__build") 804*4882a593Smuzhiyun 805*4882a593Smuzhiyun # exclude self-dependencies to prevent infinite dependency loop 806*4882a593Smuzhiyun # in generateCoveredList2() 807*4882a593Smuzhiyun tdeps = tdeps.exclude(task=F('depends_on')) 808*4882a593Smuzhiyun 809*4882a593Smuzhiyun return [tdep.task for tdep in tdeps] 810*4882a593Smuzhiyun 811*4882a593Smuzhiyundef _find_task_provider(task_object): 812*4882a593Smuzhiyun task_revdeps = _find_task_revdep(task_object) 813*4882a593Smuzhiyun for tr in task_revdeps: 814*4882a593Smuzhiyun if tr.outcome != Task.OUTCOME_COVERED: 815*4882a593Smuzhiyun return tr 816*4882a593Smuzhiyun for tr in task_revdeps: 817*4882a593Smuzhiyun trc = _find_task_provider(tr) 818*4882a593Smuzhiyun if trc is not None: 819*4882a593Smuzhiyun return trc 820*4882a593Smuzhiyun return None 821*4882a593Smuzhiyun 822*4882a593Smuzhiyundef configuration(request, build_id): 823*4882a593Smuzhiyun template = 'configuration.html' 824*4882a593Smuzhiyun 825*4882a593Smuzhiyun var_names = ('BB_VERSION', 'BUILD_SYS', 'NATIVELSBSTRING', 'TARGET_SYS', 826*4882a593Smuzhiyun 'MACHINE', 'DISTRO', 'DISTRO_VERSION', 'TUNE_FEATURES', 'TARGET_FPU') 827*4882a593Smuzhiyun context = dict(Variable.objects.filter(build=build_id, variable_name__in=var_names)\ 828*4882a593Smuzhiyun .values_list('variable_name', 'variable_value')) 829*4882a593Smuzhiyun build = Build.objects.get(pk=build_id) 830*4882a593Smuzhiyun context.update({'objectname': 'configuration', 831*4882a593Smuzhiyun 'object_search_display':'variables', 832*4882a593Smuzhiyun 'filter_search_display':'variables', 833*4882a593Smuzhiyun 'build': build, 834*4882a593Smuzhiyun 'project': build.project, 835*4882a593Smuzhiyun 'targets': Target.objects.filter(build=build_id)}) 836*4882a593Smuzhiyun return toaster_render(request, template, context) 837*4882a593Smuzhiyun 838*4882a593Smuzhiyun 839*4882a593Smuzhiyundef configvars(request, build_id): 840*4882a593Smuzhiyun template = 'configvars.html' 841*4882a593Smuzhiyun (pagesize, orderby) = _get_parameters_values(request, 100, 'variable_name:+') 842*4882a593Smuzhiyun mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby, 'filter' : 'description__regex:.+' } 843*4882a593Smuzhiyun retval = _verify_parameters( request.GET, mandatory_parameters ) 844*4882a593Smuzhiyun (filter_string, search_term, ordering_string) = _search_tuple(request, Variable) 845*4882a593Smuzhiyun if retval: 846*4882a593Smuzhiyun # if new search, clear the default filter 847*4882a593Smuzhiyun if search_term and len(search_term): 848*4882a593Smuzhiyun mandatory_parameters['filter']='' 849*4882a593Smuzhiyun return _redirect_parameters( 'configvars', request.GET, mandatory_parameters, build_id = build_id) 850*4882a593Smuzhiyun 851*4882a593Smuzhiyun queryset = Variable.objects.filter(build=build_id).exclude(variable_name__istartswith='B_').exclude(variable_name__istartswith='do_') 852*4882a593Smuzhiyun queryset_with_search = _get_queryset(Variable, queryset, None, search_term, ordering_string, 'variable_name').exclude(variable_value='',vhistory__file_name__isnull=True) 853*4882a593Smuzhiyun queryset = _get_queryset(Variable, queryset, filter_string, search_term, ordering_string, 'variable_name') 854*4882a593Smuzhiyun # remove records where the value is empty AND there are no history files 855*4882a593Smuzhiyun queryset = queryset.exclude(variable_value='',vhistory__file_name__isnull=True) 856*4882a593Smuzhiyun 857*4882a593Smuzhiyun variables = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1)) 858*4882a593Smuzhiyun 859*4882a593Smuzhiyun # show all matching files (not just the last one) 860*4882a593Smuzhiyun file_filter= search_term + ":" 861*4882a593Smuzhiyun if filter_string.find('/conf/') > 0: 862*4882a593Smuzhiyun file_filter += 'conf/(local|bblayers).conf' 863*4882a593Smuzhiyun if filter_string.find('conf/machine/') > 0: 864*4882a593Smuzhiyun file_filter += 'conf/machine/' 865*4882a593Smuzhiyun if filter_string.find('conf/distro/') > 0: 866*4882a593Smuzhiyun file_filter += 'conf/distro/' 867*4882a593Smuzhiyun if filter_string.find('/bitbake.conf') > 0: 868*4882a593Smuzhiyun file_filter += '/bitbake.conf' 869*4882a593Smuzhiyun build_dir=re.sub("/tmp/log/.*","",Build.objects.get(pk=build_id).cooker_log_path) 870*4882a593Smuzhiyun 871*4882a593Smuzhiyun build = Build.objects.get(pk=build_id) 872*4882a593Smuzhiyun 873*4882a593Smuzhiyun context = { 874*4882a593Smuzhiyun 'objectname': 'configvars', 875*4882a593Smuzhiyun 'object_search_display':'BitBake variables', 876*4882a593Smuzhiyun 'filter_search_display':'variables', 877*4882a593Smuzhiyun 'file_filter': file_filter, 878*4882a593Smuzhiyun 'build': build, 879*4882a593Smuzhiyun 'project': build.project, 880*4882a593Smuzhiyun 'objects' : variables, 881*4882a593Smuzhiyun 'total_count':queryset_with_search.count(), 882*4882a593Smuzhiyun 'default_orderby' : 'variable_name:+', 883*4882a593Smuzhiyun 'search_term':search_term, 884*4882a593Smuzhiyun # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns 885*4882a593Smuzhiyun 'tablecols' : [ 886*4882a593Smuzhiyun {'name': 'Variable', 887*4882a593Smuzhiyun '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", 888*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request, "variable_name"), 889*4882a593Smuzhiyun 'ordericon':_get_toggle_order_icon(request, "variable_name"), 890*4882a593Smuzhiyun }, 891*4882a593Smuzhiyun {'name': 'Value', 892*4882a593Smuzhiyun 'qhelp': "The value assigned to the variable", 893*4882a593Smuzhiyun }, 894*4882a593Smuzhiyun {'name': 'Set in file', 895*4882a593Smuzhiyun 'qhelp': "The last configuration file that touched the variable value", 896*4882a593Smuzhiyun 'clclass': 'file', 'hidden' : 0, 897*4882a593Smuzhiyun 'orderkey' : 'vhistory__file_name', 898*4882a593Smuzhiyun 'filter' : { 899*4882a593Smuzhiyun 'class' : 'vhistory__file_name', 900*4882a593Smuzhiyun 'label': 'Show:', 901*4882a593Smuzhiyun 'options' : [ 902*4882a593Smuzhiyun ('Local configuration variables', 'vhistory__file_name__contains:'+build_dir+'/conf/',queryset_with_search.filter(vhistory__file_name__contains=build_dir+'/conf/').count(), 'Select this filter to see variables set by the <code>local.conf</code> and <code>bblayers.conf</code> configuration files inside the <code>/build/conf/</code> directory'), 903*4882a593Smuzhiyun ('Machine configuration variables', 'vhistory__file_name__contains:conf/machine/',queryset_with_search.filter(vhistory__file_name__contains='conf/machine').count(), 'Select this filter to see variables set by the configuration file(s) inside your layers <code>/conf/machine/</code> directory'), 904*4882a593Smuzhiyun ('Distro configuration variables', 'vhistory__file_name__contains:conf/distro/',queryset_with_search.filter(vhistory__file_name__contains='conf/distro').count(), 'Select this filter to see variables set by the configuration file(s) inside your layers <code>/conf/distro/</code> directory'), 905*4882a593Smuzhiyun ('Layer configuration variables', 'vhistory__file_name__contains:conf/layer.conf',queryset_with_search.filter(vhistory__file_name__contains='conf/layer.conf').count(), 'Select this filter to see variables set by the <code>layer.conf</code> configuration file inside your layers'), 906*4882a593Smuzhiyun ('bitbake.conf variables', 'vhistory__file_name__contains:/bitbake.conf',queryset_with_search.filter(vhistory__file_name__contains='/bitbake.conf').count(), 'Select this filter to see variables set by the <code>bitbake.conf</code> configuration file'), 907*4882a593Smuzhiyun ] 908*4882a593Smuzhiyun }, 909*4882a593Smuzhiyun }, 910*4882a593Smuzhiyun {'name': 'Description', 911*4882a593Smuzhiyun 'qhelp': "A brief explanation of the variable", 912*4882a593Smuzhiyun 'clclass': 'description', 'hidden' : 0, 913*4882a593Smuzhiyun 'dclass': "span4", 914*4882a593Smuzhiyun 'filter' : { 915*4882a593Smuzhiyun 'class' : 'description', 916*4882a593Smuzhiyun 'label': 'Show:', 917*4882a593Smuzhiyun 'options' : [ 918*4882a593Smuzhiyun ('Variables with description', 'description__regex:.+', queryset_with_search.filter(description__regex='.+').count(), 'We provide descriptions for the most common BitBake variables. The list of descriptions lives in <code>meta/conf/documentation.conf</code>'), 919*4882a593Smuzhiyun ] 920*4882a593Smuzhiyun }, 921*4882a593Smuzhiyun }, 922*4882a593Smuzhiyun ], 923*4882a593Smuzhiyun } 924*4882a593Smuzhiyun 925*4882a593Smuzhiyun response = toaster_render(request, template, context) 926*4882a593Smuzhiyun _set_parameters_values(pagesize, orderby, request) 927*4882a593Smuzhiyun return response 928*4882a593Smuzhiyun 929*4882a593Smuzhiyundef bfile(request, build_id, package_id): 930*4882a593Smuzhiyun template = 'bfile.html' 931*4882a593Smuzhiyun files = Package_File.objects.filter(package = package_id) 932*4882a593Smuzhiyun build = Build.objects.get(pk=build_id) 933*4882a593Smuzhiyun context = { 934*4882a593Smuzhiyun 'build': build, 935*4882a593Smuzhiyun 'project': build.project, 936*4882a593Smuzhiyun 'objects' : files 937*4882a593Smuzhiyun } 938*4882a593Smuzhiyun return toaster_render(request, template, context) 939*4882a593Smuzhiyun 940*4882a593Smuzhiyun 941*4882a593Smuzhiyun# A set of dependency types valid for both included and built package views 942*4882a593SmuzhiyunOTHER_DEPENDS_BASE = [ 943*4882a593Smuzhiyun Package_Dependency.TYPE_RSUGGESTS, 944*4882a593Smuzhiyun Package_Dependency.TYPE_RPROVIDES, 945*4882a593Smuzhiyun Package_Dependency.TYPE_RREPLACES, 946*4882a593Smuzhiyun Package_Dependency.TYPE_RCONFLICTS, 947*4882a593Smuzhiyun ] 948*4882a593Smuzhiyun 949*4882a593Smuzhiyun# value for invalid row id 950*4882a593SmuzhiyunINVALID_KEY = -1 951*4882a593Smuzhiyun 952*4882a593Smuzhiyun""" 953*4882a593SmuzhiyunGiven a package id, target_id retrieves two sets of this image and package's 954*4882a593Smuzhiyundependencies. The return value is a dictionary consisting of two other 955*4882a593Smuzhiyunlists: a list of 'runtime' dependencies, that is, having RDEPENDS 956*4882a593Smuzhiyunvalues in source package's recipe, and a list of other dependencies, that is 957*4882a593Smuzhiyunthe list of possible recipe variables as found in OTHER_DEPENDS_BASE plus 958*4882a593Smuzhiyunthe RRECOMMENDS or TRECOMMENDS value. 959*4882a593SmuzhiyunThe lists are built in the sort order specified for the package runtime 960*4882a593Smuzhiyundependency views. 961*4882a593Smuzhiyun""" 962*4882a593Smuzhiyundef _get_package_dependencies(package_id, target_id = INVALID_KEY): 963*4882a593Smuzhiyun runtime_deps = [] 964*4882a593Smuzhiyun other_deps = [] 965*4882a593Smuzhiyun other_depends_types = OTHER_DEPENDS_BASE 966*4882a593Smuzhiyun 967*4882a593Smuzhiyun if target_id != INVALID_KEY : 968*4882a593Smuzhiyun rdepends_type = Package_Dependency.TYPE_TRDEPENDS 969*4882a593Smuzhiyun other_depends_types += [Package_Dependency.TYPE_TRECOMMENDS] 970*4882a593Smuzhiyun else : 971*4882a593Smuzhiyun rdepends_type = Package_Dependency.TYPE_RDEPENDS 972*4882a593Smuzhiyun other_depends_types += [Package_Dependency.TYPE_RRECOMMENDS] 973*4882a593Smuzhiyun 974*4882a593Smuzhiyun package = Package.objects.get(pk=package_id) 975*4882a593Smuzhiyun if target_id != INVALID_KEY : 976*4882a593Smuzhiyun alldeps = package.package_dependencies_source.filter(target_id__exact = target_id) 977*4882a593Smuzhiyun else : 978*4882a593Smuzhiyun alldeps = package.package_dependencies_source.all() 979*4882a593Smuzhiyun for idep in alldeps: 980*4882a593Smuzhiyun dep_package = Package.objects.get(pk=idep.depends_on_id) 981*4882a593Smuzhiyun dep_entry = Package_Dependency.DEPENDS_DICT[idep.dep_type] 982*4882a593Smuzhiyun if dep_package.version == '' : 983*4882a593Smuzhiyun version = '' 984*4882a593Smuzhiyun else : 985*4882a593Smuzhiyun version = dep_package.version + "-" + dep_package.revision 986*4882a593Smuzhiyun installed = False 987*4882a593Smuzhiyun if target_id != INVALID_KEY : 988*4882a593Smuzhiyun if Target_Installed_Package.objects.filter(target_id__exact = target_id, package_id__exact = dep_package.id).count() > 0: 989*4882a593Smuzhiyun installed = True 990*4882a593Smuzhiyun dep = { 991*4882a593Smuzhiyun 'name' : dep_package.name, 992*4882a593Smuzhiyun 'version' : version, 993*4882a593Smuzhiyun 'size' : dep_package.size, 994*4882a593Smuzhiyun 'dep_type' : idep.dep_type, 995*4882a593Smuzhiyun 'dep_type_display' : dep_entry[0].capitalize(), 996*4882a593Smuzhiyun 'dep_type_help' : dep_entry[1] % (dep_package.name, package.name), 997*4882a593Smuzhiyun 'depends_on_id' : dep_package.id, 998*4882a593Smuzhiyun 'installed' : installed, 999*4882a593Smuzhiyun } 1000*4882a593Smuzhiyun 1001*4882a593Smuzhiyun if target_id != INVALID_KEY: 1002*4882a593Smuzhiyun dep['alias'] = _get_package_alias(dep_package) 1003*4882a593Smuzhiyun 1004*4882a593Smuzhiyun if idep.dep_type == rdepends_type : 1005*4882a593Smuzhiyun runtime_deps.append(dep) 1006*4882a593Smuzhiyun elif idep.dep_type in other_depends_types : 1007*4882a593Smuzhiyun other_deps.append(dep) 1008*4882a593Smuzhiyun 1009*4882a593Smuzhiyun rdep_sorted = sorted(runtime_deps, key=lambda k: k['name']) 1010*4882a593Smuzhiyun odep_sorted = sorted( 1011*4882a593Smuzhiyun sorted(other_deps, key=lambda k: k['name']), 1012*4882a593Smuzhiyun key=lambda k: k['dep_type']) 1013*4882a593Smuzhiyun retvalues = {'runtime_deps' : rdep_sorted, 'other_deps' : odep_sorted} 1014*4882a593Smuzhiyun return retvalues 1015*4882a593Smuzhiyun 1016*4882a593Smuzhiyun# Return the count of packages dependent on package for this target_id image 1017*4882a593Smuzhiyundef _get_package_reverse_dep_count(package, target_id): 1018*4882a593Smuzhiyun return package.package_dependencies_target.filter(target_id__exact=target_id, dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count() 1019*4882a593Smuzhiyun 1020*4882a593Smuzhiyun# Return the count of the packages that this package_id is dependent on. 1021*4882a593Smuzhiyun# Use one of the two RDEPENDS types, either TRDEPENDS if the package was 1022*4882a593Smuzhiyun# installed, or else RDEPENDS if only built. 1023*4882a593Smuzhiyundef _get_package_dependency_count(package, target_id, is_installed): 1024*4882a593Smuzhiyun if is_installed : 1025*4882a593Smuzhiyun return package.package_dependencies_source.filter(target_id__exact = target_id, 1026*4882a593Smuzhiyun dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count() 1027*4882a593Smuzhiyun else : 1028*4882a593Smuzhiyun return package.package_dependencies_source.filter(dep_type__exact = Package_Dependency.TYPE_RDEPENDS).count() 1029*4882a593Smuzhiyun 1030*4882a593Smuzhiyundef _get_package_alias(package): 1031*4882a593Smuzhiyun alias = package.installed_name 1032*4882a593Smuzhiyun if alias is not None and alias != '' and alias != package.name: 1033*4882a593Smuzhiyun return alias 1034*4882a593Smuzhiyun else: 1035*4882a593Smuzhiyun return '' 1036*4882a593Smuzhiyun 1037*4882a593Smuzhiyundef _get_fullpackagespec(package): 1038*4882a593Smuzhiyun r = package.name 1039*4882a593Smuzhiyun version_good = package.version is not None and package.version != '' 1040*4882a593Smuzhiyun revision_good = package.revision is not None and package.revision != '' 1041*4882a593Smuzhiyun if version_good or revision_good: 1042*4882a593Smuzhiyun r += '_' 1043*4882a593Smuzhiyun if version_good: 1044*4882a593Smuzhiyun r += package.version 1045*4882a593Smuzhiyun if revision_good: 1046*4882a593Smuzhiyun r += '-' 1047*4882a593Smuzhiyun if revision_good: 1048*4882a593Smuzhiyun r += package.revision 1049*4882a593Smuzhiyun return r 1050*4882a593Smuzhiyun 1051*4882a593Smuzhiyundef package_built_detail(request, build_id, package_id): 1052*4882a593Smuzhiyun template = "package_built_detail.html" 1053*4882a593Smuzhiyun if Build.objects.filter(pk=build_id).count() == 0 : 1054*4882a593Smuzhiyun return redirect(builds) 1055*4882a593Smuzhiyun 1056*4882a593Smuzhiyun # follow convention for pagination w/ search although not used for this view 1057*4882a593Smuzhiyun queryset = Package_File.objects.filter(package_id__exact=package_id) 1058*4882a593Smuzhiyun (pagesize, orderby) = _get_parameters_values(request, 25, 'path:+') 1059*4882a593Smuzhiyun mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } 1060*4882a593Smuzhiyun retval = _verify_parameters( request.GET, mandatory_parameters ) 1061*4882a593Smuzhiyun if retval: 1062*4882a593Smuzhiyun return _redirect_parameters( 'package_built_detail', request.GET, mandatory_parameters, build_id = build_id, package_id = package_id) 1063*4882a593Smuzhiyun 1064*4882a593Smuzhiyun (filter_string, search_term, ordering_string) = _search_tuple(request, Package_File) 1065*4882a593Smuzhiyun paths = _get_queryset(Package_File, queryset, filter_string, search_term, ordering_string, 'path') 1066*4882a593Smuzhiyun 1067*4882a593Smuzhiyun package = Package.objects.get(pk=package_id) 1068*4882a593Smuzhiyun package.fullpackagespec = _get_fullpackagespec(package) 1069*4882a593Smuzhiyun context = { 1070*4882a593Smuzhiyun 'build' : Build.objects.get(pk=build_id), 1071*4882a593Smuzhiyun 'package' : package, 1072*4882a593Smuzhiyun 'dependency_count' : _get_package_dependency_count(package, -1, False), 1073*4882a593Smuzhiyun 'objects' : paths, 1074*4882a593Smuzhiyun 'tablecols':[ 1075*4882a593Smuzhiyun { 1076*4882a593Smuzhiyun 'name':'File', 1077*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request, "path"), 1078*4882a593Smuzhiyun 'ordericon':_get_toggle_order_icon(request, "path"), 1079*4882a593Smuzhiyun }, 1080*4882a593Smuzhiyun { 1081*4882a593Smuzhiyun 'name':'Size', 1082*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request, "size", True), 1083*4882a593Smuzhiyun 'ordericon':_get_toggle_order_icon(request, "size"), 1084*4882a593Smuzhiyun 'dclass': 'sizecol span2', 1085*4882a593Smuzhiyun }, 1086*4882a593Smuzhiyun ] 1087*4882a593Smuzhiyun } 1088*4882a593Smuzhiyun if paths.all().count() < 2: 1089*4882a593Smuzhiyun context['disable_sort'] = True; 1090*4882a593Smuzhiyun 1091*4882a593Smuzhiyun response = toaster_render(request, template, context) 1092*4882a593Smuzhiyun _set_parameters_values(pagesize, orderby, request) 1093*4882a593Smuzhiyun return response 1094*4882a593Smuzhiyun 1095*4882a593Smuzhiyundef package_built_dependencies(request, build_id, package_id): 1096*4882a593Smuzhiyun template = "package_built_dependencies.html" 1097*4882a593Smuzhiyun if Build.objects.filter(pk=build_id).count() == 0 : 1098*4882a593Smuzhiyun return redirect(builds) 1099*4882a593Smuzhiyun 1100*4882a593Smuzhiyun package = Package.objects.get(pk=package_id) 1101*4882a593Smuzhiyun package.fullpackagespec = _get_fullpackagespec(package) 1102*4882a593Smuzhiyun dependencies = _get_package_dependencies(package_id) 1103*4882a593Smuzhiyun context = { 1104*4882a593Smuzhiyun 'build' : Build.objects.get(pk=build_id), 1105*4882a593Smuzhiyun 'package' : package, 1106*4882a593Smuzhiyun 'runtime_deps' : dependencies['runtime_deps'], 1107*4882a593Smuzhiyun 'other_deps' : dependencies['other_deps'], 1108*4882a593Smuzhiyun 'dependency_count' : _get_package_dependency_count(package, -1, False) 1109*4882a593Smuzhiyun } 1110*4882a593Smuzhiyun return toaster_render(request, template, context) 1111*4882a593Smuzhiyun 1112*4882a593Smuzhiyun 1113*4882a593Smuzhiyundef package_included_detail(request, build_id, target_id, package_id): 1114*4882a593Smuzhiyun template = "package_included_detail.html" 1115*4882a593Smuzhiyun if Build.objects.filter(pk=build_id).count() == 0 : 1116*4882a593Smuzhiyun return redirect(builds) 1117*4882a593Smuzhiyun 1118*4882a593Smuzhiyun # follow convention for pagination w/ search although not used for this view 1119*4882a593Smuzhiyun (pagesize, orderby) = _get_parameters_values(request, 25, 'path:+') 1120*4882a593Smuzhiyun mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby } 1121*4882a593Smuzhiyun retval = _verify_parameters( request.GET, mandatory_parameters ) 1122*4882a593Smuzhiyun if retval: 1123*4882a593Smuzhiyun return _redirect_parameters( 'package_included_detail', request.GET, mandatory_parameters, build_id = build_id, target_id = target_id, package_id = package_id) 1124*4882a593Smuzhiyun (filter_string, search_term, ordering_string) = _search_tuple(request, Package_File) 1125*4882a593Smuzhiyun 1126*4882a593Smuzhiyun queryset = Package_File.objects.filter(package_id__exact=package_id) 1127*4882a593Smuzhiyun paths = _get_queryset(Package_File, queryset, filter_string, search_term, ordering_string, 'path') 1128*4882a593Smuzhiyun 1129*4882a593Smuzhiyun package = Package.objects.get(pk=package_id) 1130*4882a593Smuzhiyun package.fullpackagespec = _get_fullpackagespec(package) 1131*4882a593Smuzhiyun package.alias = _get_package_alias(package) 1132*4882a593Smuzhiyun target = Target.objects.get(pk=target_id) 1133*4882a593Smuzhiyun context = { 1134*4882a593Smuzhiyun 'build' : Build.objects.get(pk=build_id), 1135*4882a593Smuzhiyun 'target' : target, 1136*4882a593Smuzhiyun 'package' : package, 1137*4882a593Smuzhiyun 'reverse_count' : _get_package_reverse_dep_count(package, target_id), 1138*4882a593Smuzhiyun 'dependency_count' : _get_package_dependency_count(package, target_id, True), 1139*4882a593Smuzhiyun 'objects': paths, 1140*4882a593Smuzhiyun 'tablecols':[ 1141*4882a593Smuzhiyun { 1142*4882a593Smuzhiyun 'name':'File', 1143*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request, "path"), 1144*4882a593Smuzhiyun 'ordericon':_get_toggle_order_icon(request, "path"), 1145*4882a593Smuzhiyun }, 1146*4882a593Smuzhiyun { 1147*4882a593Smuzhiyun 'name':'Size', 1148*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request, "size", True), 1149*4882a593Smuzhiyun 'ordericon':_get_toggle_order_icon(request, "size"), 1150*4882a593Smuzhiyun 'dclass': 'sizecol span2', 1151*4882a593Smuzhiyun }, 1152*4882a593Smuzhiyun ] 1153*4882a593Smuzhiyun } 1154*4882a593Smuzhiyun if paths.all().count() < 2: 1155*4882a593Smuzhiyun context['disable_sort'] = True 1156*4882a593Smuzhiyun response = toaster_render(request, template, context) 1157*4882a593Smuzhiyun _set_parameters_values(pagesize, orderby, request) 1158*4882a593Smuzhiyun return response 1159*4882a593Smuzhiyun 1160*4882a593Smuzhiyundef package_included_dependencies(request, build_id, target_id, package_id): 1161*4882a593Smuzhiyun template = "package_included_dependencies.html" 1162*4882a593Smuzhiyun if Build.objects.filter(pk=build_id).count() == 0 : 1163*4882a593Smuzhiyun return redirect(builds) 1164*4882a593Smuzhiyun 1165*4882a593Smuzhiyun package = Package.objects.get(pk=package_id) 1166*4882a593Smuzhiyun package.fullpackagespec = _get_fullpackagespec(package) 1167*4882a593Smuzhiyun package.alias = _get_package_alias(package) 1168*4882a593Smuzhiyun target = Target.objects.get(pk=target_id) 1169*4882a593Smuzhiyun 1170*4882a593Smuzhiyun dependencies = _get_package_dependencies(package_id, target_id) 1171*4882a593Smuzhiyun context = { 1172*4882a593Smuzhiyun 'build' : Build.objects.get(pk=build_id), 1173*4882a593Smuzhiyun 'package' : package, 1174*4882a593Smuzhiyun 'target' : target, 1175*4882a593Smuzhiyun 'runtime_deps' : dependencies['runtime_deps'], 1176*4882a593Smuzhiyun 'other_deps' : dependencies['other_deps'], 1177*4882a593Smuzhiyun 'reverse_count' : _get_package_reverse_dep_count(package, target_id), 1178*4882a593Smuzhiyun 'dependency_count' : _get_package_dependency_count(package, target_id, True) 1179*4882a593Smuzhiyun } 1180*4882a593Smuzhiyun return toaster_render(request, template, context) 1181*4882a593Smuzhiyun 1182*4882a593Smuzhiyundef package_included_reverse_dependencies(request, build_id, target_id, package_id): 1183*4882a593Smuzhiyun template = "package_included_reverse_dependencies.html" 1184*4882a593Smuzhiyun if Build.objects.filter(pk=build_id).count() == 0 : 1185*4882a593Smuzhiyun return redirect(builds) 1186*4882a593Smuzhiyun 1187*4882a593Smuzhiyun (pagesize, orderby) = _get_parameters_values(request, 25, 'package__name:+') 1188*4882a593Smuzhiyun mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': orderby } 1189*4882a593Smuzhiyun retval = _verify_parameters( request.GET, mandatory_parameters ) 1190*4882a593Smuzhiyun if retval: 1191*4882a593Smuzhiyun return _redirect_parameters( 'package_included_reverse_dependencies', request.GET, mandatory_parameters, build_id = build_id, target_id = target_id, package_id = package_id) 1192*4882a593Smuzhiyun (filter_string, search_term, ordering_string) = _search_tuple(request, Package_File) 1193*4882a593Smuzhiyun 1194*4882a593Smuzhiyun queryset = Package_Dependency.objects.select_related('depends_on').filter(depends_on=package_id, target_id=target_id, dep_type=Package_Dependency.TYPE_TRDEPENDS) 1195*4882a593Smuzhiyun objects = _get_queryset(Package_Dependency, queryset, filter_string, search_term, ordering_string, 'package__name') 1196*4882a593Smuzhiyun 1197*4882a593Smuzhiyun package = Package.objects.get(pk=package_id) 1198*4882a593Smuzhiyun package.fullpackagespec = _get_fullpackagespec(package) 1199*4882a593Smuzhiyun package.alias = _get_package_alias(package) 1200*4882a593Smuzhiyun target = Target.objects.get(pk=target_id) 1201*4882a593Smuzhiyun for o in objects: 1202*4882a593Smuzhiyun if o.package.version != '': 1203*4882a593Smuzhiyun o.package.version += '-' + o.package.revision 1204*4882a593Smuzhiyun o.alias = _get_package_alias(o.package) 1205*4882a593Smuzhiyun context = { 1206*4882a593Smuzhiyun 'build' : Build.objects.get(pk=build_id), 1207*4882a593Smuzhiyun 'package' : package, 1208*4882a593Smuzhiyun 'target' : target, 1209*4882a593Smuzhiyun 'objects' : objects, 1210*4882a593Smuzhiyun 'reverse_count' : _get_package_reverse_dep_count(package, target_id), 1211*4882a593Smuzhiyun 'dependency_count' : _get_package_dependency_count(package, target_id, True), 1212*4882a593Smuzhiyun 'tablecols':[ 1213*4882a593Smuzhiyun { 1214*4882a593Smuzhiyun 'name':'Package', 1215*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request, "package__name"), 1216*4882a593Smuzhiyun 'ordericon': _get_toggle_order_icon(request, "package__name"), 1217*4882a593Smuzhiyun }, 1218*4882a593Smuzhiyun { 1219*4882a593Smuzhiyun 'name':'Version', 1220*4882a593Smuzhiyun }, 1221*4882a593Smuzhiyun { 1222*4882a593Smuzhiyun 'name':'Size', 1223*4882a593Smuzhiyun 'orderfield': _get_toggle_order(request, "package__size", True), 1224*4882a593Smuzhiyun 'ordericon': _get_toggle_order_icon(request, "package__size"), 1225*4882a593Smuzhiyun 'dclass': 'sizecol span2', 1226*4882a593Smuzhiyun }, 1227*4882a593Smuzhiyun ] 1228*4882a593Smuzhiyun } 1229*4882a593Smuzhiyun if objects.all().count() < 2: 1230*4882a593Smuzhiyun context['disable_sort'] = True 1231*4882a593Smuzhiyun response = toaster_render(request, template, context) 1232*4882a593Smuzhiyun _set_parameters_values(pagesize, orderby, request) 1233*4882a593Smuzhiyun return response 1234*4882a593Smuzhiyun 1235*4882a593Smuzhiyundef image_information_dir(request, build_id, target_id, packagefile_id): 1236*4882a593Smuzhiyun # stubbed for now 1237*4882a593Smuzhiyun return redirect(builds) 1238*4882a593Smuzhiyun # the context processor that supplies data used across all the pages 1239*4882a593Smuzhiyun 1240*4882a593Smuzhiyun# a context processor which runs on every request; this provides the 1241*4882a593Smuzhiyun# projects and non_cli_projects (i.e. projects created by the user) 1242*4882a593Smuzhiyun# variables referred to in templates, which used to determine the 1243*4882a593Smuzhiyun# visibility of UI elements like the "New build" button 1244*4882a593Smuzhiyundef managedcontextprocessor(request): 1245*4882a593Smuzhiyun projects = Project.objects.all() 1246*4882a593Smuzhiyun ret = { 1247*4882a593Smuzhiyun "projects": projects, 1248*4882a593Smuzhiyun "non_cli_projects": projects.exclude(is_default=True), 1249*4882a593Smuzhiyun "DEBUG" : toastermain.settings.DEBUG, 1250*4882a593Smuzhiyun "TOASTER_BRANCH": toastermain.settings.TOASTER_BRANCH, 1251*4882a593Smuzhiyun "TOASTER_REVISION" : toastermain.settings.TOASTER_REVISION, 1252*4882a593Smuzhiyun } 1253*4882a593Smuzhiyun return ret 1254*4882a593Smuzhiyun 1255*4882a593Smuzhiyun# REST-based API calls to return build/building status to external Toaster 1256*4882a593Smuzhiyun# managers and aggregators via JSON 1257*4882a593Smuzhiyun 1258*4882a593Smuzhiyundef _json_build_status(build_id,extend): 1259*4882a593Smuzhiyun build_stat = None 1260*4882a593Smuzhiyun try: 1261*4882a593Smuzhiyun build = Build.objects.get( pk = build_id ) 1262*4882a593Smuzhiyun build_stat = {} 1263*4882a593Smuzhiyun build_stat['id'] = build.id 1264*4882a593Smuzhiyun build_stat['name'] = build.build_name 1265*4882a593Smuzhiyun build_stat['machine'] = build.machine 1266*4882a593Smuzhiyun build_stat['distro'] = build.distro 1267*4882a593Smuzhiyun build_stat['start'] = build.started_on 1268*4882a593Smuzhiyun # look up target name 1269*4882a593Smuzhiyun target= Target.objects.get( build = build ) 1270*4882a593Smuzhiyun if target: 1271*4882a593Smuzhiyun if target.task: 1272*4882a593Smuzhiyun build_stat['target'] = '%s:%s' % (target.target,target.task) 1273*4882a593Smuzhiyun else: 1274*4882a593Smuzhiyun build_stat['target'] = '%s' % (target.target) 1275*4882a593Smuzhiyun else: 1276*4882a593Smuzhiyun build_stat['target'] = '' 1277*4882a593Smuzhiyun # look up project name 1278*4882a593Smuzhiyun project = Project.objects.get( build = build ) 1279*4882a593Smuzhiyun if project: 1280*4882a593Smuzhiyun build_stat['project'] = project.name 1281*4882a593Smuzhiyun else: 1282*4882a593Smuzhiyun build_stat['project'] = '' 1283*4882a593Smuzhiyun if Build.IN_PROGRESS == build.outcome: 1284*4882a593Smuzhiyun now = timezone.now() 1285*4882a593Smuzhiyun timediff = now - build.started_on 1286*4882a593Smuzhiyun build_stat['seconds']='%.3f' % timediff.total_seconds() 1287*4882a593Smuzhiyun build_stat['clone']='%d:%d' % (build.repos_cloned,build.repos_to_clone) 1288*4882a593Smuzhiyun build_stat['parse']='%d:%d' % (build.recipes_parsed,build.recipes_to_parse) 1289*4882a593Smuzhiyun tf = Task.objects.filter(build = build) 1290*4882a593Smuzhiyun tfc = tf.count() 1291*4882a593Smuzhiyun if tfc > 0: 1292*4882a593Smuzhiyun tfd = tf.exclude(order__isnull=True).count() 1293*4882a593Smuzhiyun else: 1294*4882a593Smuzhiyun tfd = 0 1295*4882a593Smuzhiyun build_stat['task']='%d:%d' % (tfd,tfc) 1296*4882a593Smuzhiyun else: 1297*4882a593Smuzhiyun build_stat['outcome'] = build.get_outcome_text() 1298*4882a593Smuzhiyun timediff = build.completed_on - build.started_on 1299*4882a593Smuzhiyun build_stat['seconds']='%.3f' % timediff.total_seconds() 1300*4882a593Smuzhiyun build_stat['stop'] = build.completed_on 1301*4882a593Smuzhiyun messages = LogMessage.objects.all().filter(build = build) 1302*4882a593Smuzhiyun errors = len(messages.filter(level=LogMessage.ERROR) | 1303*4882a593Smuzhiyun messages.filter(level=LogMessage.EXCEPTION) | 1304*4882a593Smuzhiyun messages.filter(level=LogMessage.CRITICAL)) 1305*4882a593Smuzhiyun build_stat['errors'] = errors 1306*4882a593Smuzhiyun warnings = len(messages.filter(level=LogMessage.WARNING)) 1307*4882a593Smuzhiyun build_stat['warnings'] = warnings 1308*4882a593Smuzhiyun if extend: 1309*4882a593Smuzhiyun build_stat['cooker_log'] = build.cooker_log_path 1310*4882a593Smuzhiyun except Exception as e: 1311*4882a593Smuzhiyun build_state = str(e) 1312*4882a593Smuzhiyun return build_stat 1313*4882a593Smuzhiyun 1314*4882a593Smuzhiyundef json_builds(request): 1315*4882a593Smuzhiyun build_table = [] 1316*4882a593Smuzhiyun builds = [] 1317*4882a593Smuzhiyun try: 1318*4882a593Smuzhiyun builds = Build.objects.exclude(outcome=Build.IN_PROGRESS).order_by("-started_on") 1319*4882a593Smuzhiyun for build in builds: 1320*4882a593Smuzhiyun build_table.append(_json_build_status(build.id,False)) 1321*4882a593Smuzhiyun except Exception as e: 1322*4882a593Smuzhiyun build_table = str(e) 1323*4882a593Smuzhiyun return JsonResponse({'builds' : build_table, 'count' : len(builds)}) 1324*4882a593Smuzhiyun 1325*4882a593Smuzhiyundef json_building(request): 1326*4882a593Smuzhiyun build_table = [] 1327*4882a593Smuzhiyun builds = [] 1328*4882a593Smuzhiyun try: 1329*4882a593Smuzhiyun builds = Build.objects.filter(outcome=Build.IN_PROGRESS).order_by("-started_on") 1330*4882a593Smuzhiyun for build in builds: 1331*4882a593Smuzhiyun build_table.append(_json_build_status(build.id,False)) 1332*4882a593Smuzhiyun except Exception as e: 1333*4882a593Smuzhiyun build_table = str(e) 1334*4882a593Smuzhiyun return JsonResponse({'building' : build_table, 'count' : len(builds)}) 1335*4882a593Smuzhiyun 1336*4882a593Smuzhiyundef json_build(request,build_id): 1337*4882a593Smuzhiyun return JsonResponse({'build' : _json_build_status(build_id,True)}) 1338*4882a593Smuzhiyun 1339*4882a593Smuzhiyun 1340*4882a593Smuzhiyunimport toastermain.settings 1341*4882a593Smuzhiyun 1342*4882a593Smuzhiyunfrom orm.models import Project, ProjectLayer, ProjectVariable 1343*4882a593Smuzhiyunfrom bldcontrol.models import BuildEnvironment 1344*4882a593Smuzhiyun 1345*4882a593Smuzhiyun# we have a set of functions if we're in managed mode, or 1346*4882a593Smuzhiyun# a default "page not available" simple functions for interactive mode 1347*4882a593Smuzhiyun 1348*4882a593Smuzhiyunif True: 1349*4882a593Smuzhiyun from django.contrib.auth.models import User 1350*4882a593Smuzhiyun from django.contrib.auth import authenticate, login 1351*4882a593Smuzhiyun 1352*4882a593Smuzhiyun from orm.models import LayerSource, ToasterSetting, Release 1353*4882a593Smuzhiyun 1354*4882a593Smuzhiyun import traceback 1355*4882a593Smuzhiyun 1356*4882a593Smuzhiyun class BadParameterException(Exception): 1357*4882a593Smuzhiyun ''' The exception raised on invalid POST requests ''' 1358*4882a593Smuzhiyun pass 1359*4882a593Smuzhiyun 1360*4882a593Smuzhiyun # new project 1361*4882a593Smuzhiyun def newproject(request): 1362*4882a593Smuzhiyun if not project_enable: 1363*4882a593Smuzhiyun return redirect( landing ) 1364*4882a593Smuzhiyun 1365*4882a593Smuzhiyun template = "newproject.html" 1366*4882a593Smuzhiyun context = { 1367*4882a593Smuzhiyun 'email': request.user.email if request.user.is_authenticated else '', 1368*4882a593Smuzhiyun 'username': request.user.username if request.user.is_authenticated else '', 1369*4882a593Smuzhiyun 'releases': Release.objects.order_by("description"), 1370*4882a593Smuzhiyun } 1371*4882a593Smuzhiyun 1372*4882a593Smuzhiyun try: 1373*4882a593Smuzhiyun context['defaultbranch'] = ToasterSetting.objects.get(name = "DEFAULT_RELEASE").value 1374*4882a593Smuzhiyun except ToasterSetting.DoesNotExist: 1375*4882a593Smuzhiyun pass 1376*4882a593Smuzhiyun 1377*4882a593Smuzhiyun if request.method == "GET": 1378*4882a593Smuzhiyun # render new project page 1379*4882a593Smuzhiyun return toaster_render(request, template, context) 1380*4882a593Smuzhiyun elif request.method == "POST": 1381*4882a593Smuzhiyun mandatory_fields = ['projectname', 'ptype'] 1382*4882a593Smuzhiyun try: 1383*4882a593Smuzhiyun ptype = request.POST.get('ptype') 1384*4882a593Smuzhiyun if ptype == "import": 1385*4882a593Smuzhiyun mandatory_fields.append('importdir') 1386*4882a593Smuzhiyun else: 1387*4882a593Smuzhiyun mandatory_fields.append('projectversion') 1388*4882a593Smuzhiyun # make sure we have values for all mandatory_fields 1389*4882a593Smuzhiyun missing = [field for field in mandatory_fields if len(request.POST.get(field, '')) == 0] 1390*4882a593Smuzhiyun if missing: 1391*4882a593Smuzhiyun # set alert for missing fields 1392*4882a593Smuzhiyun raise BadParameterException("Fields missing: %s" % ", ".join(missing)) 1393*4882a593Smuzhiyun 1394*4882a593Smuzhiyun if not request.user.is_authenticated: 1395*4882a593Smuzhiyun user = authenticate(username = request.POST.get('username', '_anonuser'), password = 'nopass') 1396*4882a593Smuzhiyun if user is None: 1397*4882a593Smuzhiyun user = User.objects.create_user(username = request.POST.get('username', '_anonuser'), email = request.POST.get('email', ''), password = "nopass") 1398*4882a593Smuzhiyun 1399*4882a593Smuzhiyun user = authenticate(username = user.username, password = 'nopass') 1400*4882a593Smuzhiyun login(request, user) 1401*4882a593Smuzhiyun 1402*4882a593Smuzhiyun # save the project 1403*4882a593Smuzhiyun if ptype == "import": 1404*4882a593Smuzhiyun if not os.path.isdir('%s/conf' % request.POST['importdir']): 1405*4882a593Smuzhiyun raise BadParameterException("Bad path or missing 'conf' directory (%s)" % request.POST['importdir']) 1406*4882a593Smuzhiyun from django.core import management 1407*4882a593Smuzhiyun management.call_command('buildimport', '--command=import', '--name=%s' % request.POST['projectname'], '--path=%s' % request.POST['importdir'], interactive=False) 1408*4882a593Smuzhiyun prj = Project.objects.get(name = request.POST['projectname']) 1409*4882a593Smuzhiyun prj.merged_attr = True 1410*4882a593Smuzhiyun prj.save() 1411*4882a593Smuzhiyun else: 1412*4882a593Smuzhiyun release = Release.objects.get(pk = request.POST.get('projectversion', None )) 1413*4882a593Smuzhiyun prj = Project.objects.create_project(name = request.POST['projectname'], release = release) 1414*4882a593Smuzhiyun prj.user_id = request.user.pk 1415*4882a593Smuzhiyun if 'mergeattr' == request.POST.get('mergeattr', ''): 1416*4882a593Smuzhiyun prj.merged_attr = True 1417*4882a593Smuzhiyun prj.save() 1418*4882a593Smuzhiyun 1419*4882a593Smuzhiyun return redirect(reverse(project, args=(prj.pk,)) + "?notify=new-project") 1420*4882a593Smuzhiyun 1421*4882a593Smuzhiyun except (IntegrityError, BadParameterException) as e: 1422*4882a593Smuzhiyun # fill in page with previously submitted values 1423*4882a593Smuzhiyun for field in mandatory_fields: 1424*4882a593Smuzhiyun context.__setitem__(field, request.POST.get(field, "-- missing")) 1425*4882a593Smuzhiyun if isinstance(e, IntegrityError) and "username" in str(e): 1426*4882a593Smuzhiyun context['alert'] = "Your chosen username is already used" 1427*4882a593Smuzhiyun else: 1428*4882a593Smuzhiyun context['alert'] = str(e) 1429*4882a593Smuzhiyun return toaster_render(request, template, context) 1430*4882a593Smuzhiyun 1431*4882a593Smuzhiyun raise Exception("Invalid HTTP method for this page") 1432*4882a593Smuzhiyun 1433*4882a593Smuzhiyun # new project 1434*4882a593Smuzhiyun def newproject_specific(request, pid): 1435*4882a593Smuzhiyun if not project_enable: 1436*4882a593Smuzhiyun return redirect( landing ) 1437*4882a593Smuzhiyun 1438*4882a593Smuzhiyun project = Project.objects.get(pk=pid) 1439*4882a593Smuzhiyun template = "newproject_specific.html" 1440*4882a593Smuzhiyun context = { 1441*4882a593Smuzhiyun 'email': request.user.email if request.user.is_authenticated else '', 1442*4882a593Smuzhiyun 'username': request.user.username if request.user.is_authenticated else '', 1443*4882a593Smuzhiyun 'releases': Release.objects.order_by("description"), 1444*4882a593Smuzhiyun 'projectname': project.name, 1445*4882a593Smuzhiyun 'project_pk': project.pk, 1446*4882a593Smuzhiyun } 1447*4882a593Smuzhiyun 1448*4882a593Smuzhiyun # WORKAROUND: if we already know release, redirect 'newproject_specific' to 'project_specific' 1449*4882a593Smuzhiyun if '1' == project.get_variable('INTERNAL_PROJECT_SPECIFIC_SKIPRELEASE'): 1450*4882a593Smuzhiyun return redirect(reverse(project_specific, args=(project.pk,))) 1451*4882a593Smuzhiyun 1452*4882a593Smuzhiyun try: 1453*4882a593Smuzhiyun context['defaultbranch'] = ToasterSetting.objects.get(name = "DEFAULT_RELEASE").value 1454*4882a593Smuzhiyun except ToasterSetting.DoesNotExist: 1455*4882a593Smuzhiyun pass 1456*4882a593Smuzhiyun 1457*4882a593Smuzhiyun if request.method == "GET": 1458*4882a593Smuzhiyun # render new project page 1459*4882a593Smuzhiyun return toaster_render(request, template, context) 1460*4882a593Smuzhiyun elif request.method == "POST": 1461*4882a593Smuzhiyun mandatory_fields = ['projectname', 'ptype'] 1462*4882a593Smuzhiyun try: 1463*4882a593Smuzhiyun ptype = request.POST.get('ptype') 1464*4882a593Smuzhiyun if ptype == "build": 1465*4882a593Smuzhiyun mandatory_fields.append('projectversion') 1466*4882a593Smuzhiyun # make sure we have values for all mandatory_fields 1467*4882a593Smuzhiyun missing = [field for field in mandatory_fields if len(request.POST.get(field, '')) == 0] 1468*4882a593Smuzhiyun if missing: 1469*4882a593Smuzhiyun # set alert for missing fields 1470*4882a593Smuzhiyun raise BadParameterException("Fields missing: %s" % ", ".join(missing)) 1471*4882a593Smuzhiyun 1472*4882a593Smuzhiyun if not request.user.is_authenticated: 1473*4882a593Smuzhiyun user = authenticate(username = request.POST.get('username', '_anonuser'), password = 'nopass') 1474*4882a593Smuzhiyun if user is None: 1475*4882a593Smuzhiyun user = User.objects.create_user(username = request.POST.get('username', '_anonuser'), email = request.POST.get('email', ''), password = "nopass") 1476*4882a593Smuzhiyun 1477*4882a593Smuzhiyun user = authenticate(username = user.username, password = 'nopass') 1478*4882a593Smuzhiyun login(request, user) 1479*4882a593Smuzhiyun 1480*4882a593Smuzhiyun # save the project 1481*4882a593Smuzhiyun if ptype == "analysis": 1482*4882a593Smuzhiyun release = None 1483*4882a593Smuzhiyun else: 1484*4882a593Smuzhiyun release = Release.objects.get(pk = request.POST.get('projectversion', None )) 1485*4882a593Smuzhiyun 1486*4882a593Smuzhiyun prj = Project.objects.create_project(name = request.POST['projectname'], release = release, existing_project = project) 1487*4882a593Smuzhiyun prj.user_id = request.user.pk 1488*4882a593Smuzhiyun prj.save() 1489*4882a593Smuzhiyun return redirect(reverse(project_specific, args=(prj.pk,)) + "?notify=new-project") 1490*4882a593Smuzhiyun 1491*4882a593Smuzhiyun except (IntegrityError, BadParameterException) as e: 1492*4882a593Smuzhiyun # fill in page with previously submitted values 1493*4882a593Smuzhiyun for field in mandatory_fields: 1494*4882a593Smuzhiyun context.__setitem__(field, request.POST.get(field, "-- missing")) 1495*4882a593Smuzhiyun if isinstance(e, IntegrityError) and "username" in str(e): 1496*4882a593Smuzhiyun context['alert'] = "Your chosen username is already used" 1497*4882a593Smuzhiyun else: 1498*4882a593Smuzhiyun context['alert'] = str(e) 1499*4882a593Smuzhiyun return toaster_render(request, template, context) 1500*4882a593Smuzhiyun 1501*4882a593Smuzhiyun raise Exception("Invalid HTTP method for this page") 1502*4882a593Smuzhiyun 1503*4882a593Smuzhiyun # Shows the edit project page 1504*4882a593Smuzhiyun def project(request, pid): 1505*4882a593Smuzhiyun project = Project.objects.get(pk=pid) 1506*4882a593Smuzhiyun 1507*4882a593Smuzhiyun if '1' == os.environ.get('TOASTER_PROJECTSPECIFIC'): 1508*4882a593Smuzhiyun if request.GET: 1509*4882a593Smuzhiyun #Example:request.GET=<QueryDict: {'setMachine': ['qemuarm']}> 1510*4882a593Smuzhiyun params = urlencode(request.GET).replace('%5B%27','').replace('%27%5D','') 1511*4882a593Smuzhiyun return redirect("%s?%s" % (reverse(project_specific, args=(project.pk,)),params)) 1512*4882a593Smuzhiyun else: 1513*4882a593Smuzhiyun return redirect(reverse(project_specific, args=(project.pk,))) 1514*4882a593Smuzhiyun context = {"project": project} 1515*4882a593Smuzhiyun return toaster_render(request, "project.html", context) 1516*4882a593Smuzhiyun 1517*4882a593Smuzhiyun # Shows the edit project-specific page 1518*4882a593Smuzhiyun def project_specific(request, pid): 1519*4882a593Smuzhiyun project = Project.objects.get(pk=pid) 1520*4882a593Smuzhiyun 1521*4882a593Smuzhiyun # Are we refreshing from a successful project specific update clone? 1522*4882a593Smuzhiyun if Project.PROJECT_SPECIFIC_CLONING_SUCCESS == project.get_variable(Project.PROJECT_SPECIFIC_STATUS): 1523*4882a593Smuzhiyun return redirect(reverse(landing_specific,args=(project.pk,))) 1524*4882a593Smuzhiyun 1525*4882a593Smuzhiyun context = { 1526*4882a593Smuzhiyun "project": project, 1527*4882a593Smuzhiyun "is_new" : project.get_variable(Project.PROJECT_SPECIFIC_ISNEW), 1528*4882a593Smuzhiyun "default_image_recipe" : project.get_variable(Project.PROJECT_SPECIFIC_DEFAULTIMAGE), 1529*4882a593Smuzhiyun "mru" : Build.objects.all().filter(project=project,outcome=Build.IN_PROGRESS), 1530*4882a593Smuzhiyun } 1531*4882a593Smuzhiyun if project.build_set.filter(outcome=Build.IN_PROGRESS).count() > 0: 1532*4882a593Smuzhiyun context['build_in_progress_none_completed'] = True 1533*4882a593Smuzhiyun else: 1534*4882a593Smuzhiyun context['build_in_progress_none_completed'] = False 1535*4882a593Smuzhiyun return toaster_render(request, "project.html", context) 1536*4882a593Smuzhiyun 1537*4882a593Smuzhiyun # perform the final actions for the project specific page 1538*4882a593Smuzhiyun def project_specific_finalize(cmnd, pid): 1539*4882a593Smuzhiyun project = Project.objects.get(pk=pid) 1540*4882a593Smuzhiyun callback = project.get_variable(Project.PROJECT_SPECIFIC_CALLBACK) 1541*4882a593Smuzhiyun if "update" == cmnd: 1542*4882a593Smuzhiyun # Delete all '_PROJECT_PREPARE_' builds 1543*4882a593Smuzhiyun for b in Build.objects.all().filter(project=project): 1544*4882a593Smuzhiyun delete_build = False 1545*4882a593Smuzhiyun for t in b.target_set.all(): 1546*4882a593Smuzhiyun if '_PROJECT_PREPARE_' == t.target: 1547*4882a593Smuzhiyun delete_build = True 1548*4882a593Smuzhiyun if delete_build: 1549*4882a593Smuzhiyun from django.core import management 1550*4882a593Smuzhiyun management.call_command('builddelete', str(b.id), interactive=False) 1551*4882a593Smuzhiyun # perform callback at this last moment if defined, in case Toaster gets shutdown next 1552*4882a593Smuzhiyun default_target = project.get_variable(Project.PROJECT_SPECIFIC_DEFAULTIMAGE) 1553*4882a593Smuzhiyun if callback: 1554*4882a593Smuzhiyun callback = callback.replace("<IMAGE>",default_target) 1555*4882a593Smuzhiyun if "cancel" == cmnd: 1556*4882a593Smuzhiyun if callback: 1557*4882a593Smuzhiyun callback = callback.replace("<IMAGE>","none") 1558*4882a593Smuzhiyun callback = callback.replace("--update","--cancel") 1559*4882a593Smuzhiyun # perform callback at this last moment if defined, in case this Toaster gets shutdown next 1560*4882a593Smuzhiyun ret = '' 1561*4882a593Smuzhiyun if callback: 1562*4882a593Smuzhiyun ret = os.system('bash -c "%s"' % callback) 1563*4882a593Smuzhiyun project.set_variable(Project.PROJECT_SPECIFIC_CALLBACK,'') 1564*4882a593Smuzhiyun # Delete the temp project specific variables 1565*4882a593Smuzhiyun project.set_variable(Project.PROJECT_SPECIFIC_ISNEW,'') 1566*4882a593Smuzhiyun project.set_variable(Project.PROJECT_SPECIFIC_STATUS,Project.PROJECT_SPECIFIC_NONE) 1567*4882a593Smuzhiyun # WORKAROUND: Release this workaround flag 1568*4882a593Smuzhiyun project.set_variable('INTERNAL_PROJECT_SPECIFIC_SKIPRELEASE','') 1569*4882a593Smuzhiyun 1570*4882a593Smuzhiyun # Shows the final landing page for project specific update 1571*4882a593Smuzhiyun def landing_specific(request, pid): 1572*4882a593Smuzhiyun project_specific_finalize("update", pid) 1573*4882a593Smuzhiyun context = { 1574*4882a593Smuzhiyun "install_dir": os.environ['TOASTER_DIR'], 1575*4882a593Smuzhiyun } 1576*4882a593Smuzhiyun return toaster_render(request, "landing_specific.html", context) 1577*4882a593Smuzhiyun 1578*4882a593Smuzhiyun # Shows the related landing-specific page 1579*4882a593Smuzhiyun def landing_specific_cancel(request, pid): 1580*4882a593Smuzhiyun project_specific_finalize("cancel", pid) 1581*4882a593Smuzhiyun context = { 1582*4882a593Smuzhiyun "install_dir": os.environ['TOASTER_DIR'], 1583*4882a593Smuzhiyun "status": "cancel", 1584*4882a593Smuzhiyun } 1585*4882a593Smuzhiyun return toaster_render(request, "landing_specific.html", context) 1586*4882a593Smuzhiyun 1587*4882a593Smuzhiyun def jsunittests(request): 1588*4882a593Smuzhiyun """ Provides a page for the js unit tests """ 1589*4882a593Smuzhiyun bbv = BitbakeVersion.objects.filter(branch="master").first() 1590*4882a593Smuzhiyun release = Release.objects.filter(bitbake_version=bbv).first() 1591*4882a593Smuzhiyun 1592*4882a593Smuzhiyun name = "_js_unit_test_prj_" 1593*4882a593Smuzhiyun 1594*4882a593Smuzhiyun # If there is an existing project by this name delete it. 1595*4882a593Smuzhiyun # We don't want Lots of duplicates cluttering up the projects. 1596*4882a593Smuzhiyun Project.objects.filter(name=name).delete() 1597*4882a593Smuzhiyun 1598*4882a593Smuzhiyun new_project = Project.objects.create_project(name=name, 1599*4882a593Smuzhiyun release=release) 1600*4882a593Smuzhiyun # Add a layer 1601*4882a593Smuzhiyun layer = new_project.get_all_compatible_layer_versions().first() 1602*4882a593Smuzhiyun 1603*4882a593Smuzhiyun ProjectLayer.objects.get_or_create(layercommit=layer, 1604*4882a593Smuzhiyun project=new_project) 1605*4882a593Smuzhiyun 1606*4882a593Smuzhiyun # make sure we have a machine set for this project 1607*4882a593Smuzhiyun ProjectVariable.objects.get_or_create(project=new_project, 1608*4882a593Smuzhiyun name="MACHINE", 1609*4882a593Smuzhiyun value="qemux86") 1610*4882a593Smuzhiyun context = {'project': new_project} 1611*4882a593Smuzhiyun return toaster_render(request, "js-unit-tests.html", context) 1612*4882a593Smuzhiyun 1613*4882a593Smuzhiyun from django.views.decorators.csrf import csrf_exempt 1614*4882a593Smuzhiyun @csrf_exempt 1615*4882a593Smuzhiyun def xhr_testreleasechange(request, pid): 1616*4882a593Smuzhiyun def response(data): 1617*4882a593Smuzhiyun return HttpResponse(jsonfilter(data), 1618*4882a593Smuzhiyun content_type="application/json") 1619*4882a593Smuzhiyun 1620*4882a593Smuzhiyun """ returns layer versions that would be deleted on the new 1621*4882a593Smuzhiyun release__pk """ 1622*4882a593Smuzhiyun try: 1623*4882a593Smuzhiyun prj = Project.objects.get(pk = pid) 1624*4882a593Smuzhiyun new_release_id = request.GET['new_release_id'] 1625*4882a593Smuzhiyun 1626*4882a593Smuzhiyun # If we're already on this project do nothing 1627*4882a593Smuzhiyun if prj.release.pk == int(new_release_id): 1628*4882a593Smuzhiyun return reponse({"error": "ok", "rows": []}) 1629*4882a593Smuzhiyun 1630*4882a593Smuzhiyun retval = [] 1631*4882a593Smuzhiyun 1632*4882a593Smuzhiyun for project in prj.projectlayer_set.all(): 1633*4882a593Smuzhiyun release = Release.objects.get(pk = new_release_id) 1634*4882a593Smuzhiyun 1635*4882a593Smuzhiyun layer_versions = prj.get_all_compatible_layer_versions() 1636*4882a593Smuzhiyun layer_versions = layer_versions.filter(release = release) 1637*4882a593Smuzhiyun layer_versions = layer_versions.filter(layer__name = project.layercommit.layer.name) 1638*4882a593Smuzhiyun 1639*4882a593Smuzhiyun # there is no layer_version with the new release id, 1640*4882a593Smuzhiyun # and the same name 1641*4882a593Smuzhiyun if layer_versions.count() < 1: 1642*4882a593Smuzhiyun retval.append(project) 1643*4882a593Smuzhiyun 1644*4882a593Smuzhiyun return response({"error":"ok", 1645*4882a593Smuzhiyun "rows": [_lv_to_dict(prj) for y in [x.layercommit for x in retval]] 1646*4882a593Smuzhiyun }) 1647*4882a593Smuzhiyun 1648*4882a593Smuzhiyun except Exception as e: 1649*4882a593Smuzhiyun return response({"error": str(e) }) 1650*4882a593Smuzhiyun 1651*4882a593Smuzhiyun def xhr_configvaredit(request, pid): 1652*4882a593Smuzhiyun try: 1653*4882a593Smuzhiyun prj = Project.objects.get(id = pid) 1654*4882a593Smuzhiyun # There are cases where user can add variables which hold values 1655*4882a593Smuzhiyun # like http://, file:/// etc. In such case a simple split(":") 1656*4882a593Smuzhiyun # would fail. One example is SSTATE_MIRRORS variable. So we use 1657*4882a593Smuzhiyun # max_split var to handle them. 1658*4882a593Smuzhiyun max_split = 1 1659*4882a593Smuzhiyun # add conf variables 1660*4882a593Smuzhiyun if 'configvarAdd' in request.POST: 1661*4882a593Smuzhiyun t=request.POST['configvarAdd'].strip() 1662*4882a593Smuzhiyun if ":" in t: 1663*4882a593Smuzhiyun variable, value = t.split(":", max_split) 1664*4882a593Smuzhiyun else: 1665*4882a593Smuzhiyun variable = t 1666*4882a593Smuzhiyun value = "" 1667*4882a593Smuzhiyun 1668*4882a593Smuzhiyun pt, created = ProjectVariable.objects.get_or_create(project = prj, name = variable, value = value) 1669*4882a593Smuzhiyun # change conf variables 1670*4882a593Smuzhiyun if 'configvarChange' in request.POST: 1671*4882a593Smuzhiyun t=request.POST['configvarChange'].strip() 1672*4882a593Smuzhiyun if ":" in t: 1673*4882a593Smuzhiyun variable, value = t.split(":", max_split) 1674*4882a593Smuzhiyun else: 1675*4882a593Smuzhiyun variable = t 1676*4882a593Smuzhiyun value = "" 1677*4882a593Smuzhiyun 1678*4882a593Smuzhiyun pt, created = ProjectVariable.objects.get_or_create(project = prj, name = variable) 1679*4882a593Smuzhiyun pt.value=value 1680*4882a593Smuzhiyun pt.save() 1681*4882a593Smuzhiyun # remove conf variables 1682*4882a593Smuzhiyun if 'configvarDel' in request.POST: 1683*4882a593Smuzhiyun t=request.POST['configvarDel'].strip() 1684*4882a593Smuzhiyun pt = ProjectVariable.objects.get(pk = int(t)).delete() 1685*4882a593Smuzhiyun 1686*4882a593Smuzhiyun # return all project settings, filter out disallowed and elsewhere-managed variables 1687*4882a593Smuzhiyun vars_managed,vars_fstypes,vars_disallowed = get_project_configvars_context() 1688*4882a593Smuzhiyun configvars_query = ProjectVariable.objects.filter(project_id = pid).all() 1689*4882a593Smuzhiyun for var in vars_managed: 1690*4882a593Smuzhiyun configvars_query = configvars_query.exclude(name = var) 1691*4882a593Smuzhiyun for var in vars_disallowed: 1692*4882a593Smuzhiyun configvars_query = configvars_query.exclude(name = var) 1693*4882a593Smuzhiyun 1694*4882a593Smuzhiyun return_data = { 1695*4882a593Smuzhiyun "error": "ok", 1696*4882a593Smuzhiyun 'configvars': [(x.name, x.value, x.pk) for x in configvars_query] 1697*4882a593Smuzhiyun } 1698*4882a593Smuzhiyun try: 1699*4882a593Smuzhiyun return_data['distro'] = ProjectVariable.objects.get(project = prj, name = "DISTRO").value, 1700*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1701*4882a593Smuzhiyun pass 1702*4882a593Smuzhiyun try: 1703*4882a593Smuzhiyun return_data['dl_dir'] = ProjectVariable.objects.get(project = prj, name = "DL_DIR").value, 1704*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1705*4882a593Smuzhiyun pass 1706*4882a593Smuzhiyun try: 1707*4882a593Smuzhiyun return_data['fstypes'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_FSTYPES").value, 1708*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1709*4882a593Smuzhiyun pass 1710*4882a593Smuzhiyun try: 1711*4882a593Smuzhiyun return_data['image_install:append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL:append").value, 1712*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1713*4882a593Smuzhiyun pass 1714*4882a593Smuzhiyun try: 1715*4882a593Smuzhiyun return_data['package_classes'] = ProjectVariable.objects.get(project = prj, name = "PACKAGE_CLASSES").value, 1716*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1717*4882a593Smuzhiyun pass 1718*4882a593Smuzhiyun try: 1719*4882a593Smuzhiyun return_data['sstate_dir'] = ProjectVariable.objects.get(project = prj, name = "SSTATE_DIR").value, 1720*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1721*4882a593Smuzhiyun pass 1722*4882a593Smuzhiyun 1723*4882a593Smuzhiyun return HttpResponse(json.dumps( return_data ), content_type = "application/json") 1724*4882a593Smuzhiyun 1725*4882a593Smuzhiyun except Exception as e: 1726*4882a593Smuzhiyun return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json") 1727*4882a593Smuzhiyun 1728*4882a593Smuzhiyun 1729*4882a593Smuzhiyun def customrecipe_download(request, pid, recipe_id): 1730*4882a593Smuzhiyun recipe = get_object_or_404(CustomImageRecipe, pk=recipe_id) 1731*4882a593Smuzhiyun 1732*4882a593Smuzhiyun file_data = recipe.generate_recipe_file_contents() 1733*4882a593Smuzhiyun 1734*4882a593Smuzhiyun response = HttpResponse(file_data, content_type='text/plain') 1735*4882a593Smuzhiyun response['Content-Disposition'] = \ 1736*4882a593Smuzhiyun 'attachment; filename="%s_%s.bb"' % (recipe.name, 1737*4882a593Smuzhiyun recipe.version) 1738*4882a593Smuzhiyun 1739*4882a593Smuzhiyun return response 1740*4882a593Smuzhiyun 1741*4882a593Smuzhiyun def importlayer(request, pid): 1742*4882a593Smuzhiyun template = "importlayer.html" 1743*4882a593Smuzhiyun context = { 1744*4882a593Smuzhiyun 'project': Project.objects.get(id=pid), 1745*4882a593Smuzhiyun } 1746*4882a593Smuzhiyun return toaster_render(request, template, context) 1747*4882a593Smuzhiyun 1748*4882a593Smuzhiyun def layerdetails(request, pid, layerid): 1749*4882a593Smuzhiyun project = Project.objects.get(pk=pid) 1750*4882a593Smuzhiyun layer_version = Layer_Version.objects.get(pk=layerid) 1751*4882a593Smuzhiyun 1752*4882a593Smuzhiyun project_layers = ProjectLayer.objects.filter( 1753*4882a593Smuzhiyun project=project).values_list("layercommit_id", 1754*4882a593Smuzhiyun flat=True) 1755*4882a593Smuzhiyun 1756*4882a593Smuzhiyun context = { 1757*4882a593Smuzhiyun 'project': project, 1758*4882a593Smuzhiyun 'layer_source': LayerSource.types_dict(), 1759*4882a593Smuzhiyun 'layerversion': layer_version, 1760*4882a593Smuzhiyun 'layerdeps': { 1761*4882a593Smuzhiyun "list": [ 1762*4882a593Smuzhiyun { 1763*4882a593Smuzhiyun "id": dep.id, 1764*4882a593Smuzhiyun "name": dep.layer.name, 1765*4882a593Smuzhiyun "layerdetailurl": reverse('layerdetails', 1766*4882a593Smuzhiyun args=(pid, dep.pk)), 1767*4882a593Smuzhiyun "vcs_url": dep.layer.vcs_url, 1768*4882a593Smuzhiyun "vcs_reference": dep.get_vcs_reference() 1769*4882a593Smuzhiyun } 1770*4882a593Smuzhiyun for dep in layer_version.get_alldeps(project.id)] 1771*4882a593Smuzhiyun }, 1772*4882a593Smuzhiyun 'projectlayers': list(project_layers) 1773*4882a593Smuzhiyun } 1774*4882a593Smuzhiyun 1775*4882a593Smuzhiyun return toaster_render(request, 'layerdetails.html', context) 1776*4882a593Smuzhiyun 1777*4882a593Smuzhiyun 1778*4882a593Smuzhiyun def get_project_configvars_context(): 1779*4882a593Smuzhiyun # Vars managed outside of this view 1780*4882a593Smuzhiyun vars_managed = { 1781*4882a593Smuzhiyun 'MACHINE', 'BBLAYERS' 1782*4882a593Smuzhiyun } 1783*4882a593Smuzhiyun 1784*4882a593Smuzhiyun vars_disallowed = { 1785*4882a593Smuzhiyun 'PARALLEL_MAKE','BB_NUMBER_THREADS', 1786*4882a593Smuzhiyun 'BB_DISKMON_DIRS','BB_NUMBER_THREADS','CVS_PROXY_HOST','CVS_PROXY_PORT', 1787*4882a593Smuzhiyun 'PARALLEL_MAKE','TMPDIR', 1788*4882a593Smuzhiyun 'all_proxy','ftp_proxy','http_proxy ','https_proxy' 1789*4882a593Smuzhiyun } 1790*4882a593Smuzhiyun 1791*4882a593Smuzhiyun vars_fstypes = Target_Image_File.SUFFIXES 1792*4882a593Smuzhiyun 1793*4882a593Smuzhiyun return(vars_managed,sorted(vars_fstypes),vars_disallowed) 1794*4882a593Smuzhiyun 1795*4882a593Smuzhiyun def projectconf(request, pid): 1796*4882a593Smuzhiyun 1797*4882a593Smuzhiyun try: 1798*4882a593Smuzhiyun prj = Project.objects.get(id = pid) 1799*4882a593Smuzhiyun except Project.DoesNotExist: 1800*4882a593Smuzhiyun return HttpResponseNotFound("<h1>Project id " + pid + " is unavailable</h1>") 1801*4882a593Smuzhiyun 1802*4882a593Smuzhiyun # remove disallowed and externally managed varaibles from this list 1803*4882a593Smuzhiyun vars_managed,vars_fstypes,vars_disallowed = get_project_configvars_context() 1804*4882a593Smuzhiyun configvars = ProjectVariable.objects.filter(project_id = pid).all() 1805*4882a593Smuzhiyun for var in vars_managed: 1806*4882a593Smuzhiyun configvars = configvars.exclude(name = var) 1807*4882a593Smuzhiyun for var in vars_disallowed: 1808*4882a593Smuzhiyun configvars = configvars.exclude(name = var) 1809*4882a593Smuzhiyun 1810*4882a593Smuzhiyun context = { 1811*4882a593Smuzhiyun 'project': prj, 1812*4882a593Smuzhiyun 'configvars': configvars, 1813*4882a593Smuzhiyun 'vars_managed': vars_managed, 1814*4882a593Smuzhiyun 'vars_fstypes': vars_fstypes, 1815*4882a593Smuzhiyun 'vars_disallowed': vars_disallowed, 1816*4882a593Smuzhiyun } 1817*4882a593Smuzhiyun 1818*4882a593Smuzhiyun try: 1819*4882a593Smuzhiyun context['distro'] = ProjectVariable.objects.get(project = prj, name = "DISTRO").value 1820*4882a593Smuzhiyun context['distro_defined'] = "1" 1821*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1822*4882a593Smuzhiyun pass 1823*4882a593Smuzhiyun try: 1824*4882a593Smuzhiyun if ProjectVariable.objects.get(project = prj, name = "DL_DIR").value == "${TOPDIR}/../downloads": 1825*4882a593Smuzhiyun be = BuildEnvironment.objects.get(pk = str(1)) 1826*4882a593Smuzhiyun dl_dir = os.path.join(dirname(be.builddir), "downloads") 1827*4882a593Smuzhiyun context['dl_dir'] = dl_dir 1828*4882a593Smuzhiyun pv, created = ProjectVariable.objects.get_or_create(project = prj, name = "DL_DIR") 1829*4882a593Smuzhiyun pv.value = dl_dir 1830*4882a593Smuzhiyun pv.save() 1831*4882a593Smuzhiyun else: 1832*4882a593Smuzhiyun context['dl_dir'] = ProjectVariable.objects.get(project = prj, name = "DL_DIR").value 1833*4882a593Smuzhiyun context['dl_dir_defined'] = "1" 1834*4882a593Smuzhiyun except (ProjectVariable.DoesNotExist, BuildEnvironment.DoesNotExist): 1835*4882a593Smuzhiyun pass 1836*4882a593Smuzhiyun try: 1837*4882a593Smuzhiyun context['fstypes'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_FSTYPES").value 1838*4882a593Smuzhiyun context['fstypes_defined'] = "1" 1839*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1840*4882a593Smuzhiyun pass 1841*4882a593Smuzhiyun try: 1842*4882a593Smuzhiyun context['image_install:append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL:append").value 1843*4882a593Smuzhiyun context['image_install_append_defined'] = "1" 1844*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1845*4882a593Smuzhiyun pass 1846*4882a593Smuzhiyun try: 1847*4882a593Smuzhiyun context['package_classes'] = ProjectVariable.objects.get(project = prj, name = "PACKAGE_CLASSES").value 1848*4882a593Smuzhiyun context['package_classes_defined'] = "1" 1849*4882a593Smuzhiyun except ProjectVariable.DoesNotExist: 1850*4882a593Smuzhiyun pass 1851*4882a593Smuzhiyun try: 1852*4882a593Smuzhiyun if ProjectVariable.objects.get(project = prj, name = "SSTATE_DIR").value == "${TOPDIR}/../sstate-cache": 1853*4882a593Smuzhiyun be = BuildEnvironment.objects.get(pk = str(1)) 1854*4882a593Smuzhiyun sstate_dir = os.path.join(dirname(be.builddir), "sstate-cache") 1855*4882a593Smuzhiyun context['sstate_dir'] = sstate_dir 1856*4882a593Smuzhiyun pv, created = ProjectVariable.objects.get_or_create(project = prj, name = "SSTATE_DIR") 1857*4882a593Smuzhiyun pv.value = sstate_dir 1858*4882a593Smuzhiyun pv.save() 1859*4882a593Smuzhiyun else: 1860*4882a593Smuzhiyun context['sstate_dir'] = ProjectVariable.objects.get(project = prj, name = "SSTATE_DIR").value 1861*4882a593Smuzhiyun context['sstate_dir_defined'] = "1" 1862*4882a593Smuzhiyun except (ProjectVariable.DoesNotExist, BuildEnvironment.DoesNotExist): 1863*4882a593Smuzhiyun pass 1864*4882a593Smuzhiyun 1865*4882a593Smuzhiyun return toaster_render(request, "projectconf.html", context) 1866*4882a593Smuzhiyun 1867*4882a593Smuzhiyun def _file_names_for_artifact(build, artifact_type, artifact_id): 1868*4882a593Smuzhiyun """ 1869*4882a593Smuzhiyun Return a tuple (file path, file name for the download response) for an 1870*4882a593Smuzhiyun artifact of type artifact_type with ID artifact_id for build; if 1871*4882a593Smuzhiyun artifact type is not supported, returns (None, None) 1872*4882a593Smuzhiyun """ 1873*4882a593Smuzhiyun file_name = None 1874*4882a593Smuzhiyun response_file_name = None 1875*4882a593Smuzhiyun 1876*4882a593Smuzhiyun if artifact_type == "cookerlog": 1877*4882a593Smuzhiyun file_name = build.cooker_log_path 1878*4882a593Smuzhiyun response_file_name = "cooker.log" 1879*4882a593Smuzhiyun 1880*4882a593Smuzhiyun elif artifact_type == "imagefile": 1881*4882a593Smuzhiyun file_name = Target_Image_File.objects.get(target__build = build, pk = artifact_id).file_name 1882*4882a593Smuzhiyun 1883*4882a593Smuzhiyun elif artifact_type == "targetkernelartifact": 1884*4882a593Smuzhiyun target = TargetKernelFile.objects.get(pk=artifact_id) 1885*4882a593Smuzhiyun file_name = target.file_name 1886*4882a593Smuzhiyun 1887*4882a593Smuzhiyun elif artifact_type == "targetsdkartifact": 1888*4882a593Smuzhiyun target = TargetSDKFile.objects.get(pk=artifact_id) 1889*4882a593Smuzhiyun file_name = target.file_name 1890*4882a593Smuzhiyun 1891*4882a593Smuzhiyun elif artifact_type == "licensemanifest": 1892*4882a593Smuzhiyun file_name = Target.objects.get(build = build, pk = artifact_id).license_manifest_path 1893*4882a593Smuzhiyun 1894*4882a593Smuzhiyun elif artifact_type == "packagemanifest": 1895*4882a593Smuzhiyun file_name = Target.objects.get(build = build, pk = artifact_id).package_manifest_path 1896*4882a593Smuzhiyun 1897*4882a593Smuzhiyun elif artifact_type == "tasklogfile": 1898*4882a593Smuzhiyun file_name = Task.objects.get(build = build, pk = artifact_id).logfile 1899*4882a593Smuzhiyun 1900*4882a593Smuzhiyun elif artifact_type == "logmessagefile": 1901*4882a593Smuzhiyun file_name = LogMessage.objects.get(build = build, pk = artifact_id).pathname 1902*4882a593Smuzhiyun 1903*4882a593Smuzhiyun if file_name and not response_file_name: 1904*4882a593Smuzhiyun response_file_name = os.path.basename(file_name) 1905*4882a593Smuzhiyun 1906*4882a593Smuzhiyun return (file_name, response_file_name) 1907*4882a593Smuzhiyun 1908*4882a593Smuzhiyun def build_artifact(request, build_id, artifact_type, artifact_id): 1909*4882a593Smuzhiyun """ 1910*4882a593Smuzhiyun View which returns a build artifact file as a response 1911*4882a593Smuzhiyun """ 1912*4882a593Smuzhiyun file_name = None 1913*4882a593Smuzhiyun response_file_name = None 1914*4882a593Smuzhiyun 1915*4882a593Smuzhiyun try: 1916*4882a593Smuzhiyun build = Build.objects.get(pk = build_id) 1917*4882a593Smuzhiyun file_name, response_file_name = _file_names_for_artifact( 1918*4882a593Smuzhiyun build, artifact_type, artifact_id 1919*4882a593Smuzhiyun ) 1920*4882a593Smuzhiyun 1921*4882a593Smuzhiyun if file_name and response_file_name: 1922*4882a593Smuzhiyun fsock = open(file_name, "rb") 1923*4882a593Smuzhiyun content_type = MimeTypeFinder.get_mimetype(file_name) 1924*4882a593Smuzhiyun 1925*4882a593Smuzhiyun response = HttpResponse(fsock, content_type = content_type) 1926*4882a593Smuzhiyun 1927*4882a593Smuzhiyun disposition = "attachment; filename=" + response_file_name 1928*4882a593Smuzhiyun response["Content-Disposition"] = disposition 1929*4882a593Smuzhiyun 1930*4882a593Smuzhiyun return response 1931*4882a593Smuzhiyun else: 1932*4882a593Smuzhiyun return toaster_render(request, "unavailable_artifact.html") 1933*4882a593Smuzhiyun except (ObjectDoesNotExist, IOError): 1934*4882a593Smuzhiyun return toaster_render(request, "unavailable_artifact.html") 1935*4882a593Smuzhiyun 1936