123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935 |
- #
- # BitBake Toaster Implementation
- #
- # Copyright (C) 2013 Intel Corporation
- #
- # SPDX-License-Identifier: GPL-2.0-only
- #
- import re
- from django.db.models import F, Q, Sum
- from django.db import IntegrityError
- from django.shortcuts import render, redirect, get_object_or_404
- from django.utils.http import urlencode
- from orm.models import Build, Target, Task, Layer, Layer_Version, Recipe
- from orm.models import LogMessage, Variable, Package_Dependency, Package
- from orm.models import Task_Dependency, Package_File
- from orm.models import Target_Installed_Package, Target_File
- from orm.models import TargetKernelFile, TargetSDKFile, Target_Image_File
- from orm.models import BitbakeVersion, CustomImageRecipe
- from django.core.urlresolvers import reverse, resolve
- from django.core.exceptions import ObjectDoesNotExist
- from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
- from django.http import HttpResponseNotFound, JsonResponse
- from django.utils import timezone
- from datetime import timedelta, datetime
- from toastergui.templatetags.projecttags import json as jsonfilter
- from decimal import Decimal
- import json
- import os
- from os.path import dirname
- import mimetypes
- import logging
- logger = logging.getLogger("toaster")
- # Project creation and managed build enable
- project_enable = ('1' == os.environ.get('TOASTER_BUILDSERVER'))
- is_project_specific = ('1' == os.environ.get('TOASTER_PROJECTSPECIFIC'))
- class MimeTypeFinder(object):
- # setting this to False enables additional non-standard mimetypes
- # to be included in the guess
- _strict = False
- # returns the mimetype for a file path as a string,
- # or 'application/octet-stream' if the type couldn't be guessed
- @classmethod
- def get_mimetype(self, path):
- guess = mimetypes.guess_type(path, self._strict)
- guessed_type = guess[0]
- if guessed_type is None:
- guessed_type = 'application/octet-stream'
- return guessed_type
- # single point to add global values into the context before rendering
- def toaster_render(request, page, context):
- context['project_enable'] = project_enable
- context['project_specific'] = is_project_specific
- return render(request, page, context)
- # all new sessions should come through the landing page;
- # determine in which mode we are running in, and redirect appropriately
- def landing(request):
- # in build mode, we redirect to the command-line builds page
- # if there are any builds for the default (cli builds) project
- default_project = Project.objects.get_or_create_default_project()
- default_project_builds = Build.objects.filter(project = default_project)
- # we only redirect to projects page if there is a user-generated project
- num_builds = Build.objects.all().count()
- user_projects = Project.objects.filter(is_default = False)
- has_user_project = user_projects.count() > 0
- if num_builds == 0 and has_user_project:
- return redirect(reverse('all-projects'), permanent = False)
- if num_builds > 0:
- return redirect(reverse('all-builds'), permanent = False)
- context = {'lvs_nos' : Layer_Version.objects.all().count()}
- return toaster_render(request, 'landing.html', context)
- def objtojson(obj):
- from django.db.models.query import QuerySet
- from django.db.models import Model
- if isinstance(obj, datetime):
- return obj.isoformat()
- elif isinstance(obj, timedelta):
- return obj.total_seconds()
- elif isinstance(obj, QuerySet) or isinstance(obj, set):
- return list(obj)
- elif isinstance(obj, Decimal):
- return str(obj)
- elif type(obj).__name__ == "RelatedManager":
- return [x.pk for x in obj.all()]
- elif hasattr( obj, '__dict__') and isinstance(obj, Model):
- d = obj.__dict__
- nd = dict(d)
- for di in d.keys():
- if di.startswith("_"):
- del nd[di]
- elif isinstance(d[di], Model):
- nd[di] = d[di].pk
- elif isinstance(d[di], int) and hasattr(obj, "get_%s_display" % di):
- nd[di] = getattr(obj, "get_%s_display" % di)()
- return nd
- elif isinstance( obj, type(lambda x:x)):
- import inspect
- return inspect.getsourcelines(obj)[0]
- else:
- raise TypeError("Unserializable object %s (%s) of type %s" % ( obj, dir(obj), type(obj)))
- def _lv_to_dict(prj, x = None):
- if x is None:
- def wrapper(x):
- return _lv_to_dict(prj, x)
- return wrapper
- return {"id": x.pk,
- "name": x.layer.name,
- "tooltip": "%s | %s" % (x.layer.vcs_url,x.get_vcs_reference()),
- "detail": "(%s" % x.layer.vcs_url + (")" if x.release is None else " | "+x.get_vcs_reference()+")"),
- "giturl": x.layer.vcs_url,
- "layerdetailurl" : reverse('layerdetails', args=(prj.id,x.pk)),
- "revision" : x.get_vcs_reference(),
- }
- def _build_page_range(paginator, index = 1):
- try:
- page = paginator.page(index)
- except PageNotAnInteger:
- page = paginator.page(1)
- except EmptyPage:
- page = paginator.page(paginator.num_pages)
- page.page_range = [page.number]
- crt_range = 0
- for i in range(1,5):
- if (page.number + i) <= paginator.num_pages:
- page.page_range = page.page_range + [ page.number + i]
- crt_range +=1
- if (page.number - i) > 0:
- page.page_range = [page.number -i] + page.page_range
- crt_range +=1
- if crt_range == 4:
- break
- return page
- def _verify_parameters(g, mandatory_parameters):
- miss = []
- for mp in mandatory_parameters:
- if not mp in g:
- miss.append(mp)
- if len(miss):
- return miss
- return None
- def _redirect_parameters(view, g, mandatory_parameters, *args, **kwargs):
- try:
- from urllib import unquote, urlencode
- except ImportError:
- from urllib.parse import unquote, urlencode
- url = reverse(view, kwargs=kwargs)
- params = {}
- for i in g:
- params[i] = g[i]
- for i in mandatory_parameters:
- if not i in params:
- params[i] = unquote(str(mandatory_parameters[i]))
- return redirect(url + "?%s" % urlencode(params), permanent = False, **kwargs)
- class RedirectException(Exception):
- def __init__(self, view, g, mandatory_parameters, *args, **kwargs):
- super(RedirectException, self).__init__()
- self.view = view
- self.g = g
- self.mandatory_parameters = mandatory_parameters
- self.oargs = args
- self.okwargs = kwargs
- def get_redirect_response(self):
- return _redirect_parameters(self.view, self.g, self.mandatory_parameters, self.oargs, **self.okwargs)
- FIELD_SEPARATOR = ":"
- AND_VALUE_SEPARATOR = "!"
- OR_VALUE_SEPARATOR = "|"
- DESCENDING = "-"
- def __get_q_for_val(name, value):
- if "OR" in value or "AND" in value:
- result = None
- for x in value.split("OR"):
- x = __get_q_for_val(name, x)
- result = result | x if result else x
- return result
- if "AND" in value:
- result = None
- for x in value.split("AND"):
- x = __get_q_for_val(name, x)
- result = result & x if result else x
- return result
- if value.startswith("NOT"):
- value = value[3:]
- if value == 'None':
- value = None
- kwargs = { name : value }
- return ~Q(**kwargs)
- else:
- if value == 'None':
- value = None
- kwargs = { name : value }
- return Q(**kwargs)
- def _get_filtering_query(filter_string):
- search_terms = filter_string.split(FIELD_SEPARATOR)
- and_keys = search_terms[0].split(AND_VALUE_SEPARATOR)
- and_values = search_terms[1].split(AND_VALUE_SEPARATOR)
- and_query = None
- for kv in zip(and_keys, and_values):
- or_keys = kv[0].split(OR_VALUE_SEPARATOR)
- or_values = kv[1].split(OR_VALUE_SEPARATOR)
- query = None
- for key, val in zip(or_keys, or_values):
- x = __get_q_for_val(key, val)
- query = query | x if query else x
- and_query = and_query & query if and_query else query
- return and_query
- def _get_toggle_order(request, orderkey, toggle_reverse = False):
- if toggle_reverse:
- return "%s:+" % orderkey if request.GET.get('orderby', "") == "%s:-" % orderkey else "%s:-" % orderkey
- else:
- return "%s:-" % orderkey if request.GET.get('orderby', "") == "%s:+" % orderkey else "%s:+" % orderkey
- def _get_toggle_order_icon(request, orderkey):
- if request.GET.get('orderby', "") == "%s:+"%orderkey:
- return "down"
- elif request.GET.get('orderby', "") == "%s:-"%orderkey:
- return "up"
- else:
- return None
- # we check that the input comes in a valid form that we can recognize
- def _validate_input(field_input, model):
- invalid = None
- if field_input:
- field_input_list = field_input.split(FIELD_SEPARATOR)
- # Check we have only one colon
- if len(field_input_list) != 2:
- invalid = "We have an invalid number of separators: " + field_input + " -> " + str(field_input_list)
- return None, invalid
- # Check we have an equal number of terms both sides of the colon
- if len(field_input_list[0].split(AND_VALUE_SEPARATOR)) != len(field_input_list[1].split(AND_VALUE_SEPARATOR)):
- invalid = "Not all arg names got values"
- return None, invalid + str(field_input_list)
- # Check we are looking for a valid field
- valid_fields = [f.name for f in model._meta.get_fields()]
- for field in field_input_list[0].split(AND_VALUE_SEPARATOR):
- if True in [field.startswith(x) for x in valid_fields]:
- break
- else:
- return None, (field, valid_fields)
- return field_input, invalid
- # uses search_allowed_fields in orm/models.py to create a search query
- # for these fields with the supplied input text
- def _get_search_results(search_term, queryset, model):
- search_object = None
- for st in search_term.split(" "):
- queries = None
- for field in model.search_allowed_fields:
- query = Q(**{field + '__icontains': st})
- queries = queries | query if queries else query
- search_object = search_object & queries if search_object else queries
- queryset = queryset.filter(search_object)
- return queryset
- # function to extract the search/filter/ordering parameters from the request
- # it uses the request and the model to validate input for the filter and orderby values
- def _search_tuple(request, model):
- ordering_string, invalid = _validate_input(request.GET.get('orderby', ''), model)
- if invalid:
- raise BaseException("Invalid ordering model:" + str(model) + str(invalid))
- filter_string, invalid = _validate_input(request.GET.get('filter', ''), model)
- if invalid:
- raise BaseException("Invalid filter " + str(invalid))
- search_term = request.GET.get('search', '')
- return (filter_string, search_term, ordering_string)
- # returns a lazy-evaluated queryset for a filter/search/order combination
- def _get_queryset(model, queryset, filter_string, search_term, ordering_string, ordering_secondary=''):
- if filter_string:
- filter_query = _get_filtering_query(filter_string)
- queryset = queryset.filter(filter_query)
- else:
- queryset = queryset.all()
- if search_term:
- queryset = _get_search_results(search_term, queryset, model)
- if ordering_string:
- column, order = ordering_string.split(':')
- if column == re.sub('-','',ordering_secondary):
- ordering_secondary=''
- if order.lower() == DESCENDING:
- column = '-' + column
- if ordering_secondary:
- queryset = queryset.order_by(column, ordering_secondary)
- else:
- queryset = queryset.order_by(column)
- # insure only distinct records (e.g. from multiple search hits) are returned
- return queryset.distinct()
- # returns the value of entries per page and the name of the applied sorting field.
- # if the value is given explicitly as a GET parameter it will be the first selected,
- # otherwise the cookie value will be used.
- def _get_parameters_values(request, default_count, default_order):
- current_url = resolve(request.path_info).url_name
- pagesize = request.GET.get('count', request.session.get('%s_count' % current_url, default_count))
- orderby = request.GET.get('orderby', request.session.get('%s_orderby' % current_url, default_order))
- return (pagesize, orderby)
- # set cookies for parameters. this is usefull in case parameters are set
- # manually from the GET values of the link
- def _set_parameters_values(pagesize, orderby, request):
- from django.core.urlresolvers import resolve
- current_url = resolve(request.path_info).url_name
- request.session['%s_count' % current_url] = pagesize
- request.session['%s_orderby' % current_url] =orderby
- # date range: normalize GUI's dd/mm/yyyy to date object
- def _normalize_input_date(date_str,default):
- date_str=re.sub('/', '-', date_str)
- # accept dd/mm/yyyy to d/m/yy
- try:
- date_in = datetime.strptime(date_str, "%d-%m-%Y")
- except ValueError:
- # courtesy try with two digit year
- try:
- date_in = datetime.strptime(date_str, "%d-%m-%y")
- except ValueError:
- return default
- date_in = date_in.replace(tzinfo=default.tzinfo)
- return date_in
- # convert and normalize any received date range filter, for example:
- # "completed_on__gte!completed_on__lt:01/03/2015!02/03/2015_daterange" to
- # "completed_on__gte!completed_on__lt:2015-03-01!2015-03-02"
- def _modify_date_range_filter(filter_string):
- # was the date range radio button selected?
- if 0 > filter_string.find('_daterange'):
- return filter_string,''
- # normalize GUI dates to database format
- filter_string = filter_string.replace('_daterange','').replace(':','!');
- filter_list = filter_string.split('!');
- if 4 != len(filter_list):
- return filter_string
- today = timezone.localtime(timezone.now())
- date_id = filter_list[1]
- date_from = _normalize_input_date(filter_list[2],today)
- date_to = _normalize_input_date(filter_list[3],today)
- # swap dates if manually set dates are out of order
- if date_to < date_from:
- date_to,date_from = date_from,date_to
- # convert to strings, make 'date_to' inclusive by moving to begining of next day
- date_from_str = date_from.strftime("%Y-%m-%d")
- date_to_str = (date_to+timedelta(days=1)).strftime("%Y-%m-%d")
- filter_string=filter_list[0]+'!'+filter_list[1]+':'+date_from_str+'!'+date_to_str
- daterange_selected = re.sub('__.*','', date_id)
- return filter_string,daterange_selected
- def _add_daterange_context(queryset_all, request, daterange_list):
- # calculate the exact begining of local today and yesterday
- today_begin = timezone.localtime(timezone.now())
- yesterday_begin = today_begin - timedelta(days=1)
- # add daterange persistent
- context_date = {}
- context_date['last_date_from'] = request.GET.get('last_date_from',timezone.localtime(timezone.now()).strftime("%d/%m/%Y"))
- context_date['last_date_to' ] = request.GET.get('last_date_to' ,context_date['last_date_from'])
- # calculate the date ranges, avoid second sort for 'created'
- # fetch the respective max range from the database
- context_date['daterange_filter']=''
- for key in daterange_list:
- queryset_key = queryset_all.order_by(key)
- try:
- context_date['dateMin_'+key]=timezone.localtime(getattr(queryset_key.first(),key)).strftime("%d/%m/%Y")
- except AttributeError:
- context_date['dateMin_'+key]=timezone.localtime(timezone.now())
- try:
- context_date['dateMax_'+key]=timezone.localtime(getattr(queryset_key.last(),key)).strftime("%d/%m/%Y")
- except AttributeError:
- context_date['dateMax_'+key]=timezone.localtime(timezone.now())
- return context_date,today_begin,yesterday_begin
- ##
- # build dashboard for a single build, coming in as argument
- # Each build may contain multiple targets and each target
- # may generate multiple image files. display them all.
- #
- def builddashboard( request, build_id ):
- template = "builddashboard.html"
- if Build.objects.filter( pk=build_id ).count( ) == 0 :
- return redirect( builds )
- build = Build.objects.get( pk = build_id );
- layerVersionId = Layer_Version.objects.filter( build = build_id );
- recipeCount = Recipe.objects.filter( layer_version__id__in = layerVersionId ).count( );
- tgts = Target.objects.filter( build_id = build_id ).order_by( 'target' );
- # set up custom target list with computed package and image data
- targets = []
- ntargets = 0
- # True if at least one target for this build has an SDK artifact
- # or image file
- has_artifacts = False
- for t in tgts:
- elem = {}
- elem['target'] = t
- target_has_images = False
- image_files = []
- npkg = 0
- pkgsz = 0
- package = None
- # Chunk the query to avoid "too many SQL variables" error
- package_set = t.target_installed_package_set.all()
- package_set_len = len(package_set)
- for ps_start in range(0,package_set_len,500):
- ps_stop = min(ps_start+500,package_set_len)
- for package in Package.objects.filter(id__in = [x.package_id for x in package_set[ps_start:ps_stop]]):
- pkgsz = pkgsz + package.size
- if package.installed_name:
- npkg = npkg + 1
- elem['npkg'] = npkg
- elem['pkgsz'] = pkgsz
- ti = Target_Image_File.objects.filter(target_id = t.id)
- for i in ti:
- ndx = i.file_name.rfind('/')
- if ndx < 0:
- ndx = 0;
- f = i.file_name[ndx + 1:]
- image_files.append({
- 'id': i.id,
- 'path': f,
- 'size': i.file_size,
- 'suffix': i.suffix
- })
- if len(image_files) > 0:
- target_has_images = True
- elem['targetHasImages'] = target_has_images
- elem['imageFiles'] = image_files
- elem['target_kernel_artifacts'] = t.targetkernelfile_set.all()
- target_sdk_files = t.targetsdkfile_set.all()
- target_sdk_artifacts_count = target_sdk_files.count()
- elem['target_sdk_artifacts_count'] = target_sdk_artifacts_count
- elem['target_sdk_artifacts'] = target_sdk_files
- if target_has_images or target_sdk_artifacts_count > 0:
- has_artifacts = True
- targets.append(elem)
- ##
- # how many packages in this build - ignore anonymous ones
- #
- packageCount = 0
- packages = Package.objects.filter( build_id = build_id )
- for p in packages:
- if ( p.installed_name ):
- packageCount = packageCount + 1
- logmessages = list(LogMessage.objects.filter( build = build_id ))
- context = {
- 'build' : build,
- 'project' : build.project,
- 'hasArtifacts' : has_artifacts,
- 'ntargets' : ntargets,
- 'targets' : targets,
- 'recipecount' : recipeCount,
- 'packagecount' : packageCount,
- 'logmessages' : logmessages,
- }
- return toaster_render( request, template, context )
- def generateCoveredList2( revlist = None ):
- if not revlist:
- revlist = []
- covered_list = [ x for x in revlist if x.outcome == Task.OUTCOME_COVERED ]
- while len(covered_list):
- revlist = [ x for x in revlist if x.outcome != Task.OUTCOME_COVERED ]
- if len(revlist) > 0:
- return revlist
- newlist = _find_task_revdep_list(covered_list)
- revlist = list(set(revlist + newlist))
- covered_list = [ x for x in revlist if x.outcome == Task.OUTCOME_COVERED ]
- return revlist
- def task( request, build_id, task_id ):
- template = "task.html"
- tasks_list = Task.objects.filter( pk=task_id )
- if tasks_list.count( ) == 0:
- return redirect( builds )
- task_object = tasks_list[ 0 ];
- dependencies = sorted(
- _find_task_dep( task_object ),
- key=lambda t:'%s_%s %s'%(t.recipe.name, t.recipe.version, t.task_name))
- reverse_dependencies = sorted(
- _find_task_revdep( task_object ),
- key=lambda t:'%s_%s %s'%( t.recipe.name, t.recipe.version, t.task_name ))
- coveredBy = '';
- if ( task_object.outcome == Task.OUTCOME_COVERED ):
- # _list = generateCoveredList( task )
- coveredBy = sorted(generateCoveredList2( _find_task_revdep( task_object ) ), key = lambda x: x.recipe.name)
- log_head = ''
- log_body = ''
- if task_object.outcome == task_object.OUTCOME_FAILED:
- pass
- uri_list= [ ]
- variables = Variable.objects.filter(build=build_id)
- v=variables.filter(variable_name='SSTATE_DIR')
- if v.count() > 0:
- uri_list.append(v[0].variable_value)
- v=variables.filter(variable_name='SSTATE_MIRRORS')
- if (v.count() > 0):
- for mirror in v[0].variable_value.split('\\n'):
- s=re.sub('.* ','',mirror.strip(' \t\n\r'))
- if len(s):
- uri_list.append(s)
- context = {
- 'build' : Build.objects.filter( pk = build_id )[ 0 ],
- 'object' : task_object,
- 'task' : task_object,
- 'covered_by' : coveredBy,
- 'deps' : dependencies,
- 'rdeps' : reverse_dependencies,
- 'log_head' : log_head,
- 'log_body' : log_body,
- 'showing_matches' : False,
- 'uri_list' : uri_list,
- 'task_in_tasks_table_pg': int(task_object.order / 25) + 1
- }
- if request.GET.get( 'show_matches', "" ):
- context[ 'showing_matches' ] = True
- context[ 'matching_tasks' ] = Task.objects.filter(
- sstate_checksum=task_object.sstate_checksum ).filter(
- build__completed_on__lt=task_object.build.completed_on).exclude(
- order__isnull=True).exclude(outcome=Task.OUTCOME_NA).order_by('-build__completed_on')
- return toaster_render( request, template, context )
- def recipe(request, build_id, recipe_id, active_tab="1"):
- template = "recipe.html"
- if Recipe.objects.filter(pk=recipe_id).count() == 0 :
- return redirect(builds)
- recipe_object = Recipe.objects.get(pk=recipe_id)
- layer_version = Layer_Version.objects.get(pk=recipe_object.layer_version_id)
- layer = Layer.objects.get(pk=layer_version.layer_id)
- 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)
- package_count = Package.objects.filter(recipe_id = recipe_id).filter(build_id = build_id).filter(size__gte=0).count()
- if active_tab != '1' and active_tab != '3' and active_tab != '4' :
- active_tab = '1'
- tab_states = {'1': '', '3': '', '4': ''}
- tab_states[active_tab] = 'active'
- context = {
- 'build' : Build.objects.get(pk=build_id),
- 'object' : recipe_object,
- 'layer_version' : layer_version,
- 'layer' : layer,
- 'tasks' : tasks_list,
- 'package_count' : package_count,
- 'tab_states' : tab_states,
- }
- return toaster_render(request, template, context)
- def recipe_packages(request, build_id, recipe_id):
- template = "recipe_packages.html"
- if Recipe.objects.filter(pk=recipe_id).count() == 0 :
- return redirect(builds)
- (pagesize, orderby) = _get_parameters_values(request, 10, 'name:+')
- mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': orderby }
- retval = _verify_parameters( request.GET, mandatory_parameters )
- if retval:
- return _redirect_parameters( 'recipe_packages', request.GET, mandatory_parameters, build_id = build_id, recipe_id = recipe_id)
- (filter_string, search_term, ordering_string) = _search_tuple(request, Package)
- recipe_object = Recipe.objects.get(pk=recipe_id)
- queryset = Package.objects.filter(recipe_id = recipe_id).filter(build_id = build_id).filter(size__gte=0)
- package_count = queryset.count()
- queryset = _get_queryset(Package, queryset, filter_string, search_term, ordering_string, 'name')
- packages = _build_page_range(Paginator(queryset, pagesize),request.GET.get('page', 1))
- context = {
- 'build' : Build.objects.get(pk=build_id),
- 'recipe' : recipe_object,
- 'objects' : packages,
- 'object_count' : package_count,
- 'tablecols':[
- {
- 'name':'Package',
- 'orderfield': _get_toggle_order(request,"name"),
- 'ordericon': _get_toggle_order_icon(request,"name"),
- 'orderkey': "name",
- },
- {
- 'name':'Version',
- },
- {
- 'name':'Size',
- 'orderfield': _get_toggle_order(request,"size", True),
- 'ordericon': _get_toggle_order_icon(request,"size"),
- 'orderkey': 'size',
- 'dclass': 'sizecol span2',
- },
- ]
- }
- response = toaster_render(request, template, context)
- _set_parameters_values(pagesize, orderby, request)
- return response
- from django.http import HttpResponse
- def xhr_dirinfo(request, build_id, target_id):
- top = request.GET.get('start', '/')
- return HttpResponse(_get_dir_entries(build_id, target_id, top), content_type = "application/json")
- from django.utils.functional import Promise
- from django.utils.encoding import force_text
- class LazyEncoder(json.JSONEncoder):
- def default(self, obj):
- if isinstance(obj, Promise):
- return force_text(obj)
- return super(LazyEncoder, self).default(obj)
- from toastergui.templatetags.projecttags import filtered_filesizeformat
- import os
- def _get_dir_entries(build_id, target_id, start):
- node_str = {
- Target_File.ITYPE_REGULAR : '-',
- Target_File.ITYPE_DIRECTORY : 'd',
- Target_File.ITYPE_SYMLINK : 'l',
- Target_File.ITYPE_SOCKET : 's',
- Target_File.ITYPE_FIFO : 'p',
- Target_File.ITYPE_CHARACTER : 'c',
- Target_File.ITYPE_BLOCK : 'b',
- }
- response = []
- objects = Target_File.objects.filter(target__exact=target_id, directory__path=start)
- target_packages = Target_Installed_Package.objects.filter(target__exact=target_id).values_list('package_id', flat=True)
- for o in objects:
- # exclude root inode '/'
- if o.path == '/':
- continue
- try:
- entry = {}
- entry['parent'] = start
- entry['name'] = os.path.basename(o.path)
- entry['fullpath'] = o.path
- # set defaults, not all dentries have packages
- entry['installed_package'] = None
- entry['package_id'] = None
- entry['package'] = None
- entry['link_to'] = None
- if o.inodetype == Target_File.ITYPE_DIRECTORY:
- entry['isdir'] = 1
- # is there content in directory
- entry['childcount'] = Target_File.objects.filter(target__exact=target_id, directory__path=o.path).all().count()
- else:
- entry['isdir'] = 0
- # resolve the file to get the package from the resolved file
- resolved_id = o.sym_target_id
- resolved_path = o.path
- if target_packages.count():
- while resolved_id != "" and resolved_id is not None:
- tf = Target_File.objects.get(pk=resolved_id)
- resolved_path = tf.path
- resolved_id = tf.sym_target_id
- thisfile=Package_File.objects.all().filter(path__exact=resolved_path, package_id__in=target_packages)
- if thisfile.count():
- p = Package.objects.get(pk=thisfile[0].package_id)
- entry['installed_package'] = p.installed_name
- entry['package_id'] = str(p.id)
- entry['package'] = p.name
- # don't use resolved path from above, show immediate link-to
- if o.sym_target_id != "" and o.sym_target_id is not None:
- entry['link_to'] = Target_File.objects.get(pk=o.sym_target_id).path
- entry['size'] = filtered_filesizeformat(o.size)
- if entry['link_to'] is not None:
- entry['permission'] = node_str[o.inodetype] + o.permission
- else:
- entry['permission'] = node_str[o.inodetype] + o.permission
- entry['owner'] = o.owner
- entry['group'] = o.group
- response.append(entry)
- except Exception as e:
- print("Exception ", e)
- traceback.print_exc()
- # sort by directories first, then by name
- rsorted = sorted(response, key=lambda entry : entry['name'])
- rsorted = sorted(rsorted, key=lambda entry : entry['isdir'], reverse=True)
- return json.dumps(rsorted, cls=LazyEncoder).replace('</', '<\\/')
- def dirinfo(request, build_id, target_id, file_path=None):
- template = "dirinfo.html"
- objects = _get_dir_entries(build_id, target_id, '/')
- packages_sum = Package.objects.filter(id__in=Target_Installed_Package.objects.filter(target_id=target_id).values('package_id')).aggregate(Sum('installed_size'))
- dir_list = None
- if file_path is not None:
- """
- Link from the included package detail file list page and is
- requesting opening the dir info to a specific file path.
- Provide the list of directories to expand and the full path to
- highlight in the page.
- """
- # Aassume target's path separator matches host's, that is, os.sep
- sep = os.sep
- dir_list = []
- head = file_path
- while head != sep:
- (head, tail) = os.path.split(head)
- if head != sep:
- dir_list.insert(0, head)
- build = Build.objects.get(pk=build_id)
- context = { 'build': build,
- 'project': build.project,
- 'target': Target.objects.get(pk=target_id),
- 'packages_sum': packages_sum['installed_size__sum'],
- 'objects': objects,
- 'dir_list': dir_list,
- 'file_path': file_path,
- }
- return toaster_render(request, template, context)
- def _find_task_dep(task_object):
- tdeps = Task_Dependency.objects.filter(task=task_object).filter(depends_on__order__gt=0)
- tdeps = tdeps.exclude(depends_on__outcome=Task.OUTCOME_NA).select_related("depends_on")
- return [x.depends_on for x in tdeps]
- def _find_task_revdep(task_object):
- tdeps = Task_Dependency.objects.filter(depends_on=task_object).filter(task__order__gt=0)
- tdeps = tdeps.exclude(task__outcome = Task.OUTCOME_NA).select_related("task", "task__recipe", "task__build")
- # exclude self-dependencies to prevent infinite dependency loop
- # in generateCoveredList2()
- tdeps = tdeps.exclude(task=task_object)
- return [tdep.task for tdep in tdeps]
- def _find_task_revdep_list(tasklist):
- tdeps = Task_Dependency.objects.filter(depends_on__in=tasklist).filter(task__order__gt=0)
- tdeps = tdeps.exclude(task__outcome=Task.OUTCOME_NA).select_related("task", "task__recipe", "task__build")
- # exclude self-dependencies to prevent infinite dependency loop
- # in generateCoveredList2()
- tdeps = tdeps.exclude(task=F('depends_on'))
- return [tdep.task for tdep in tdeps]
- def _find_task_provider(task_object):
- task_revdeps = _find_task_revdep(task_object)
- for tr in task_revdeps:
- if tr.outcome != Task.OUTCOME_COVERED:
- return tr
- for tr in task_revdeps:
- trc = _find_task_provider(tr)
- if trc is not None:
- return trc
- return None
- def configuration(request, build_id):
- template = 'configuration.html'
- var_names = ('BB_VERSION', 'BUILD_SYS', 'NATIVELSBSTRING', 'TARGET_SYS',
- 'MACHINE', 'DISTRO', 'DISTRO_VERSION', 'TUNE_FEATURES', 'TARGET_FPU')
- context = dict(Variable.objects.filter(build=build_id, variable_name__in=var_names)\
- .values_list('variable_name', 'variable_value'))
- build = Build.objects.get(pk=build_id)
- context.update({'objectname': 'configuration',
- 'object_search_display':'variables',
- 'filter_search_display':'variables',
- 'build': build,
- 'project': build.project,
- 'targets': Target.objects.filter(build=build_id)})
- return toaster_render(request, template, context)
- def configvars(request, build_id):
- template = 'configvars.html'
- (pagesize, orderby) = _get_parameters_values(request, 100, 'variable_name:+')
- mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby, 'filter' : 'description__regex:.+' }
- retval = _verify_parameters( request.GET, mandatory_parameters )
- (filter_string, search_term, ordering_string) = _search_tuple(request, Variable)
- if retval:
- # if new search, clear the default filter
- if search_term and len(search_term):
- mandatory_parameters['filter']=''
- return _redirect_parameters( 'configvars', request.GET, mandatory_parameters, build_id = build_id)
- queryset = Variable.objects.filter(build=build_id).exclude(variable_name__istartswith='B_').exclude(variable_name__istartswith='do_')
- queryset_with_search = _get_queryset(Variable, queryset, None, search_term, ordering_string, 'variable_name').exclude(variable_value='',vhistory__file_name__isnull=True)
- queryset = _get_queryset(Variable, queryset, filter_string, search_term, ordering_string, 'variable_name')
- # remove records where the value is empty AND there are no history files
- queryset = queryset.exclude(variable_value='',vhistory__file_name__isnull=True)
- variables = _build_page_range(Paginator(queryset, pagesize), request.GET.get('page', 1))
- # show all matching files (not just the last one)
- file_filter= search_term + ":"
- if filter_string.find('/conf/') > 0:
- file_filter += 'conf/(local|bblayers).conf'
- if filter_string.find('conf/machine/') > 0:
- file_filter += 'conf/machine/'
- if filter_string.find('conf/distro/') > 0:
- file_filter += 'conf/distro/'
- if filter_string.find('/bitbake.conf') > 0:
- file_filter += '/bitbake.conf'
- build_dir=re.sub("/tmp/log/.*","",Build.objects.get(pk=build_id).cooker_log_path)
- build = Build.objects.get(pk=build_id)
- context = {
- 'objectname': 'configvars',
- 'object_search_display':'BitBake variables',
- 'filter_search_display':'variables',
- 'file_filter': file_filter,
- 'build': build,
- 'project': build.project,
- 'objects' : variables,
- 'total_count':queryset_with_search.count(),
- 'default_orderby' : 'variable_name:+',
- 'search_term':search_term,
- # Specifies the display of columns for the table, appearance in "Edit columns" box, toggling default show/hide, and specifying filters for columns
- 'tablecols' : [
- {'name': 'Variable',
- 'qhelp': "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",
- 'orderfield': _get_toggle_order(request, "variable_name"),
- 'ordericon':_get_toggle_order_icon(request, "variable_name"),
- },
- {'name': 'Value',
- 'qhelp': "The value assigned to the variable",
- },
- {'name': 'Set in file',
- 'qhelp': "The last configuration file that touched the variable value",
- 'clclass': 'file', 'hidden' : 0,
- 'orderkey' : 'vhistory__file_name',
- 'filter' : {
- 'class' : 'vhistory__file_name',
- 'label': 'Show:',
- 'options' : [
- ('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'),
- ('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'),
- ('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'),
- ('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'),
- ('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'),
- ]
- },
- },
- {'name': 'Description',
- 'qhelp': "A brief explanation of the variable",
- 'clclass': 'description', 'hidden' : 0,
- 'dclass': "span4",
- 'filter' : {
- 'class' : 'description',
- 'label': 'Show:',
- 'options' : [
- ('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>'),
- ]
- },
- },
- ],
- }
- response = toaster_render(request, template, context)
- _set_parameters_values(pagesize, orderby, request)
- return response
- def bfile(request, build_id, package_id):
- template = 'bfile.html'
- files = Package_File.objects.filter(package = package_id)
- build = Build.objects.get(pk=build_id)
- context = {
- 'build': build,
- 'project': build.project,
- 'objects' : files
- }
- return toaster_render(request, template, context)
- # A set of dependency types valid for both included and built package views
- OTHER_DEPENDS_BASE = [
- Package_Dependency.TYPE_RSUGGESTS,
- Package_Dependency.TYPE_RPROVIDES,
- Package_Dependency.TYPE_RREPLACES,
- Package_Dependency.TYPE_RCONFLICTS,
- ]
- # value for invalid row id
- INVALID_KEY = -1
- """
- Given a package id, target_id retrieves two sets of this image and package's
- dependencies. The return value is a dictionary consisting of two other
- lists: a list of 'runtime' dependencies, that is, having RDEPENDS
- values in source package's recipe, and a list of other dependencies, that is
- the list of possible recipe variables as found in OTHER_DEPENDS_BASE plus
- the RRECOMMENDS or TRECOMMENDS value.
- The lists are built in the sort order specified for the package runtime
- dependency views.
- """
- def _get_package_dependencies(package_id, target_id = INVALID_KEY):
- runtime_deps = []
- other_deps = []
- other_depends_types = OTHER_DEPENDS_BASE
- if target_id != INVALID_KEY :
- rdepends_type = Package_Dependency.TYPE_TRDEPENDS
- other_depends_types += [Package_Dependency.TYPE_TRECOMMENDS]
- else :
- rdepends_type = Package_Dependency.TYPE_RDEPENDS
- other_depends_types += [Package_Dependency.TYPE_RRECOMMENDS]
- package = Package.objects.get(pk=package_id)
- if target_id != INVALID_KEY :
- alldeps = package.package_dependencies_source.filter(target_id__exact = target_id)
- else :
- alldeps = package.package_dependencies_source.all()
- for idep in alldeps:
- dep_package = Package.objects.get(pk=idep.depends_on_id)
- dep_entry = Package_Dependency.DEPENDS_DICT[idep.dep_type]
- if dep_package.version == '' :
- version = ''
- else :
- version = dep_package.version + "-" + dep_package.revision
- installed = False
- if target_id != INVALID_KEY :
- if Target_Installed_Package.objects.filter(target_id__exact = target_id, package_id__exact = dep_package.id).count() > 0:
- installed = True
- dep = {
- 'name' : dep_package.name,
- 'version' : version,
- 'size' : dep_package.size,
- 'dep_type' : idep.dep_type,
- 'dep_type_display' : dep_entry[0].capitalize(),
- 'dep_type_help' : dep_entry[1] % (dep_package.name, package.name),
- 'depends_on_id' : dep_package.id,
- 'installed' : installed,
- }
- if target_id != INVALID_KEY:
- dep['alias'] = _get_package_alias(dep_package)
- if idep.dep_type == rdepends_type :
- runtime_deps.append(dep)
- elif idep.dep_type in other_depends_types :
- other_deps.append(dep)
- rdep_sorted = sorted(runtime_deps, key=lambda k: k['name'])
- odep_sorted = sorted(
- sorted(other_deps, key=lambda k: k['name']),
- key=lambda k: k['dep_type'])
- retvalues = {'runtime_deps' : rdep_sorted, 'other_deps' : odep_sorted}
- return retvalues
- # Return the count of packages dependent on package for this target_id image
- def _get_package_reverse_dep_count(package, target_id):
- return package.package_dependencies_target.filter(target_id__exact=target_id, dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count()
- # Return the count of the packages that this package_id is dependent on.
- # Use one of the two RDEPENDS types, either TRDEPENDS if the package was
- # installed, or else RDEPENDS if only built.
- def _get_package_dependency_count(package, target_id, is_installed):
- if is_installed :
- return package.package_dependencies_source.filter(target_id__exact = target_id,
- dep_type__exact = Package_Dependency.TYPE_TRDEPENDS).count()
- else :
- return package.package_dependencies_source.filter(dep_type__exact = Package_Dependency.TYPE_RDEPENDS).count()
- def _get_package_alias(package):
- alias = package.installed_name
- if alias is not None and alias != '' and alias != package.name:
- return alias
- else:
- return ''
- def _get_fullpackagespec(package):
- r = package.name
- version_good = package.version is not None and package.version != ''
- revision_good = package.revision is not None and package.revision != ''
- if version_good or revision_good:
- r += '_'
- if version_good:
- r += package.version
- if revision_good:
- r += '-'
- if revision_good:
- r += package.revision
- return r
- def package_built_detail(request, build_id, package_id):
- template = "package_built_detail.html"
- if Build.objects.filter(pk=build_id).count() == 0 :
- return redirect(builds)
- # follow convention for pagination w/ search although not used for this view
- queryset = Package_File.objects.filter(package_id__exact=package_id)
- (pagesize, orderby) = _get_parameters_values(request, 25, 'path:+')
- mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
- retval = _verify_parameters( request.GET, mandatory_parameters )
- if retval:
- return _redirect_parameters( 'package_built_detail', request.GET, mandatory_parameters, build_id = build_id, package_id = package_id)
- (filter_string, search_term, ordering_string) = _search_tuple(request, Package_File)
- paths = _get_queryset(Package_File, queryset, filter_string, search_term, ordering_string, 'path')
- package = Package.objects.get(pk=package_id)
- package.fullpackagespec = _get_fullpackagespec(package)
- context = {
- 'build' : Build.objects.get(pk=build_id),
- 'package' : package,
- 'dependency_count' : _get_package_dependency_count(package, -1, False),
- 'objects' : paths,
- 'tablecols':[
- {
- 'name':'File',
- 'orderfield': _get_toggle_order(request, "path"),
- 'ordericon':_get_toggle_order_icon(request, "path"),
- },
- {
- 'name':'Size',
- 'orderfield': _get_toggle_order(request, "size", True),
- 'ordericon':_get_toggle_order_icon(request, "size"),
- 'dclass': 'sizecol span2',
- },
- ]
- }
- if paths.all().count() < 2:
- context['disable_sort'] = True;
- response = toaster_render(request, template, context)
- _set_parameters_values(pagesize, orderby, request)
- return response
- def package_built_dependencies(request, build_id, package_id):
- template = "package_built_dependencies.html"
- if Build.objects.filter(pk=build_id).count() == 0 :
- return redirect(builds)
- package = Package.objects.get(pk=package_id)
- package.fullpackagespec = _get_fullpackagespec(package)
- dependencies = _get_package_dependencies(package_id)
- context = {
- 'build' : Build.objects.get(pk=build_id),
- 'package' : package,
- 'runtime_deps' : dependencies['runtime_deps'],
- 'other_deps' : dependencies['other_deps'],
- 'dependency_count' : _get_package_dependency_count(package, -1, False)
- }
- return toaster_render(request, template, context)
- def package_included_detail(request, build_id, target_id, package_id):
- template = "package_included_detail.html"
- if Build.objects.filter(pk=build_id).count() == 0 :
- return redirect(builds)
- # follow convention for pagination w/ search although not used for this view
- (pagesize, orderby) = _get_parameters_values(request, 25, 'path:+')
- mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby' : orderby }
- retval = _verify_parameters( request.GET, mandatory_parameters )
- if retval:
- return _redirect_parameters( 'package_included_detail', request.GET, mandatory_parameters, build_id = build_id, target_id = target_id, package_id = package_id)
- (filter_string, search_term, ordering_string) = _search_tuple(request, Package_File)
- queryset = Package_File.objects.filter(package_id__exact=package_id)
- paths = _get_queryset(Package_File, queryset, filter_string, search_term, ordering_string, 'path')
- package = Package.objects.get(pk=package_id)
- package.fullpackagespec = _get_fullpackagespec(package)
- package.alias = _get_package_alias(package)
- target = Target.objects.get(pk=target_id)
- context = {
- 'build' : Build.objects.get(pk=build_id),
- 'target' : target,
- 'package' : package,
- 'reverse_count' : _get_package_reverse_dep_count(package, target_id),
- 'dependency_count' : _get_package_dependency_count(package, target_id, True),
- 'objects': paths,
- 'tablecols':[
- {
- 'name':'File',
- 'orderfield': _get_toggle_order(request, "path"),
- 'ordericon':_get_toggle_order_icon(request, "path"),
- },
- {
- 'name':'Size',
- 'orderfield': _get_toggle_order(request, "size", True),
- 'ordericon':_get_toggle_order_icon(request, "size"),
- 'dclass': 'sizecol span2',
- },
- ]
- }
- if paths.all().count() < 2:
- context['disable_sort'] = True
- response = toaster_render(request, template, context)
- _set_parameters_values(pagesize, orderby, request)
- return response
- def package_included_dependencies(request, build_id, target_id, package_id):
- template = "package_included_dependencies.html"
- if Build.objects.filter(pk=build_id).count() == 0 :
- return redirect(builds)
- package = Package.objects.get(pk=package_id)
- package.fullpackagespec = _get_fullpackagespec(package)
- package.alias = _get_package_alias(package)
- target = Target.objects.get(pk=target_id)
- dependencies = _get_package_dependencies(package_id, target_id)
- context = {
- 'build' : Build.objects.get(pk=build_id),
- 'package' : package,
- 'target' : target,
- 'runtime_deps' : dependencies['runtime_deps'],
- 'other_deps' : dependencies['other_deps'],
- 'reverse_count' : _get_package_reverse_dep_count(package, target_id),
- 'dependency_count' : _get_package_dependency_count(package, target_id, True)
- }
- return toaster_render(request, template, context)
- def package_included_reverse_dependencies(request, build_id, target_id, package_id):
- template = "package_included_reverse_dependencies.html"
- if Build.objects.filter(pk=build_id).count() == 0 :
- return redirect(builds)
- (pagesize, orderby) = _get_parameters_values(request, 25, 'package__name:+')
- mandatory_parameters = { 'count': pagesize, 'page' : 1, 'orderby': orderby }
- retval = _verify_parameters( request.GET, mandatory_parameters )
- if retval:
- return _redirect_parameters( 'package_included_reverse_dependencies', request.GET, mandatory_parameters, build_id = build_id, target_id = target_id, package_id = package_id)
- (filter_string, search_term, ordering_string) = _search_tuple(request, Package_File)
- queryset = Package_Dependency.objects.select_related('depends_on__name', 'depends_on__size').filter(depends_on=package_id, target_id=target_id, dep_type=Package_Dependency.TYPE_TRDEPENDS)
- objects = _get_queryset(Package_Dependency, queryset, filter_string, search_term, ordering_string, 'package__name')
- package = Package.objects.get(pk=package_id)
- package.fullpackagespec = _get_fullpackagespec(package)
- package.alias = _get_package_alias(package)
- target = Target.objects.get(pk=target_id)
- for o in objects:
- if o.package.version != '':
- o.package.version += '-' + o.package.revision
- o.alias = _get_package_alias(o.package)
- context = {
- 'build' : Build.objects.get(pk=build_id),
- 'package' : package,
- 'target' : target,
- 'objects' : objects,
- 'reverse_count' : _get_package_reverse_dep_count(package, target_id),
- 'dependency_count' : _get_package_dependency_count(package, target_id, True),
- 'tablecols':[
- {
- 'name':'Package',
- 'orderfield': _get_toggle_order(request, "package__name"),
- 'ordericon': _get_toggle_order_icon(request, "package__name"),
- },
- {
- 'name':'Version',
- },
- {
- 'name':'Size',
- 'orderfield': _get_toggle_order(request, "package__size", True),
- 'ordericon': _get_toggle_order_icon(request, "package__size"),
- 'dclass': 'sizecol span2',
- },
- ]
- }
- if objects.all().count() < 2:
- context['disable_sort'] = True
- response = toaster_render(request, template, context)
- _set_parameters_values(pagesize, orderby, request)
- return response
- def image_information_dir(request, build_id, target_id, packagefile_id):
- # stubbed for now
- return redirect(builds)
- # the context processor that supplies data used across all the pages
- # a context processor which runs on every request; this provides the
- # projects and non_cli_projects (i.e. projects created by the user)
- # variables referred to in templates, which used to determine the
- # visibility of UI elements like the "New build" button
- def managedcontextprocessor(request):
- projects = Project.objects.all()
- ret = {
- "projects": projects,
- "non_cli_projects": projects.exclude(is_default=True),
- "DEBUG" : toastermain.settings.DEBUG,
- "TOASTER_BRANCH": toastermain.settings.TOASTER_BRANCH,
- "TOASTER_REVISION" : toastermain.settings.TOASTER_REVISION,
- }
- return ret
- # REST-based API calls to return build/building status to external Toaster
- # managers and aggregators via JSON
- def _json_build_status(build_id,extend):
- build_stat = None
- try:
- build = Build.objects.get( pk = build_id )
- build_stat = {}
- build_stat['id'] = build.id
- build_stat['name'] = build.build_name
- build_stat['machine'] = build.machine
- build_stat['distro'] = build.distro
- build_stat['start'] = build.started_on
- # look up target name
- target= Target.objects.get( build = build )
- if target:
- if target.task:
- build_stat['target'] = '%s:%s' % (target.target,target.task)
- else:
- build_stat['target'] = '%s' % (target.target)
- else:
- build_stat['target'] = ''
- # look up project name
- project = Project.objects.get( build = build )
- if project:
- build_stat['project'] = project.name
- else:
- build_stat['project'] = ''
- if Build.IN_PROGRESS == build.outcome:
- now = timezone.now()
- timediff = now - build.started_on
- build_stat['seconds']='%.3f' % timediff.total_seconds()
- build_stat['clone']='%d:%d' % (build.repos_cloned,build.repos_to_clone)
- build_stat['parse']='%d:%d' % (build.recipes_parsed,build.recipes_to_parse)
- tf = Task.objects.filter(build = build)
- tfc = tf.count()
- if tfc > 0:
- tfd = tf.exclude(order__isnull=True).count()
- else:
- tfd = 0
- build_stat['task']='%d:%d' % (tfd,tfc)
- else:
- build_stat['outcome'] = build.get_outcome_text()
- timediff = build.completed_on - build.started_on
- build_stat['seconds']='%.3f' % timediff.total_seconds()
- build_stat['stop'] = build.completed_on
- messages = LogMessage.objects.all().filter(build = build)
- errors = len(messages.filter(level=LogMessage.ERROR) |
- messages.filter(level=LogMessage.EXCEPTION) |
- messages.filter(level=LogMessage.CRITICAL))
- build_stat['errors'] = errors
- warnings = len(messages.filter(level=LogMessage.WARNING))
- build_stat['warnings'] = warnings
- if extend:
- build_stat['cooker_log'] = build.cooker_log_path
- except Exception as e:
- build_state = str(e)
- return build_stat
- def json_builds(request):
- build_table = []
- builds = []
- try:
- builds = Build.objects.exclude(outcome=Build.IN_PROGRESS).order_by("-started_on")
- for build in builds:
- build_table.append(_json_build_status(build.id,False))
- except Exception as e:
- build_table = str(e)
- return JsonResponse({'builds' : build_table, 'count' : len(builds)})
- def json_building(request):
- build_table = []
- builds = []
- try:
- builds = Build.objects.filter(outcome=Build.IN_PROGRESS).order_by("-started_on")
- for build in builds:
- build_table.append(_json_build_status(build.id,False))
- except Exception as e:
- build_table = str(e)
- return JsonResponse({'building' : build_table, 'count' : len(builds)})
- def json_build(request,build_id):
- return JsonResponse({'build' : _json_build_status(build_id,True)})
- import toastermain.settings
- from orm.models import Project, ProjectLayer, ProjectVariable
- from bldcontrol.models import BuildEnvironment
- # we have a set of functions if we're in managed mode, or
- # a default "page not available" simple functions for interactive mode
- if True:
- from django.contrib.auth.models import User
- from django.contrib.auth import authenticate, login
- from orm.models import LayerSource, ToasterSetting, Release
- import traceback
- class BadParameterException(Exception):
- ''' The exception raised on invalid POST requests '''
- pass
- # new project
- def newproject(request):
- if not project_enable:
- return redirect( landing )
- template = "newproject.html"
- context = {
- 'email': request.user.email if request.user.is_authenticated() else '',
- 'username': request.user.username if request.user.is_authenticated() else '',
- 'releases': Release.objects.order_by("description"),
- }
- try:
- context['defaultbranch'] = ToasterSetting.objects.get(name = "DEFAULT_RELEASE").value
- except ToasterSetting.DoesNotExist:
- pass
- if request.method == "GET":
- # render new project page
- return toaster_render(request, template, context)
- elif request.method == "POST":
- mandatory_fields = ['projectname', 'ptype']
- try:
- ptype = request.POST.get('ptype')
- if ptype == "import":
- mandatory_fields.append('importdir')
- else:
- mandatory_fields.append('projectversion')
- # make sure we have values for all mandatory_fields
- missing = [field for field in mandatory_fields if len(request.POST.get(field, '')) == 0]
- if missing:
- # set alert for missing fields
- raise BadParameterException("Fields missing: %s" % ", ".join(missing))
- if not request.user.is_authenticated():
- user = authenticate(username = request.POST.get('username', '_anonuser'), password = 'nopass')
- if user is None:
- user = User.objects.create_user(username = request.POST.get('username', '_anonuser'), email = request.POST.get('email', ''), password = "nopass")
- user = authenticate(username = user.username, password = 'nopass')
- login(request, user)
- # save the project
- if ptype == "import":
- if not os.path.isdir('%s/conf' % request.POST['importdir']):
- raise BadParameterException("Bad path or missing 'conf' directory (%s)" % request.POST['importdir'])
- from django.core import management
- management.call_command('buildimport', '--command=import', '--name=%s' % request.POST['projectname'], '--path=%s' % request.POST['importdir'], interactive=False)
- prj = Project.objects.get(name = request.POST['projectname'])
- prj.merged_attr = True
- prj.save()
- else:
- release = Release.objects.get(pk = request.POST.get('projectversion', None ))
- prj = Project.objects.create_project(name = request.POST['projectname'], release = release)
- prj.user_id = request.user.pk
- if 'mergeattr' == request.POST.get('mergeattr', ''):
- prj.merged_attr = True
- prj.save()
- return redirect(reverse(project, args=(prj.pk,)) + "?notify=new-project")
- except (IntegrityError, BadParameterException) as e:
- # fill in page with previously submitted values
- for field in mandatory_fields:
- context.__setitem__(field, request.POST.get(field, "-- missing"))
- if isinstance(e, IntegrityError) and "username" in str(e):
- context['alert'] = "Your chosen username is already used"
- else:
- context['alert'] = str(e)
- return toaster_render(request, template, context)
- raise Exception("Invalid HTTP method for this page")
- # new project
- def newproject_specific(request, pid):
- if not project_enable:
- return redirect( landing )
- project = Project.objects.get(pk=pid)
- template = "newproject_specific.html"
- context = {
- 'email': request.user.email if request.user.is_authenticated() else '',
- 'username': request.user.username if request.user.is_authenticated() else '',
- 'releases': Release.objects.order_by("description"),
- 'projectname': project.name,
- 'project_pk': project.pk,
- }
- # WORKAROUND: if we already know release, redirect 'newproject_specific' to 'project_specific'
- if '1' == project.get_variable('INTERNAL_PROJECT_SPECIFIC_SKIPRELEASE'):
- return redirect(reverse(project_specific, args=(project.pk,)))
- try:
- context['defaultbranch'] = ToasterSetting.objects.get(name = "DEFAULT_RELEASE").value
- except ToasterSetting.DoesNotExist:
- pass
- if request.method == "GET":
- # render new project page
- return toaster_render(request, template, context)
- elif request.method == "POST":
- mandatory_fields = ['projectname', 'ptype']
- try:
- ptype = request.POST.get('ptype')
- if ptype == "build":
- mandatory_fields.append('projectversion')
- # make sure we have values for all mandatory_fields
- missing = [field for field in mandatory_fields if len(request.POST.get(field, '')) == 0]
- if missing:
- # set alert for missing fields
- raise BadParameterException("Fields missing: %s" % ", ".join(missing))
- if not request.user.is_authenticated():
- user = authenticate(username = request.POST.get('username', '_anonuser'), password = 'nopass')
- if user is None:
- user = User.objects.create_user(username = request.POST.get('username', '_anonuser'), email = request.POST.get('email', ''), password = "nopass")
- user = authenticate(username = user.username, password = 'nopass')
- login(request, user)
- # save the project
- if ptype == "analysis":
- release = None
- else:
- release = Release.objects.get(pk = request.POST.get('projectversion', None ))
- prj = Project.objects.create_project(name = request.POST['projectname'], release = release, existing_project = project)
- prj.user_id = request.user.pk
- prj.save()
- return redirect(reverse(project_specific, args=(prj.pk,)) + "?notify=new-project")
- except (IntegrityError, BadParameterException) as e:
- # fill in page with previously submitted values
- for field in mandatory_fields:
- context.__setitem__(field, request.POST.get(field, "-- missing"))
- if isinstance(e, IntegrityError) and "username" in str(e):
- context['alert'] = "Your chosen username is already used"
- else:
- context['alert'] = str(e)
- return toaster_render(request, template, context)
- raise Exception("Invalid HTTP method for this page")
- # Shows the edit project page
- def project(request, pid):
- project = Project.objects.get(pk=pid)
- if '1' == os.environ.get('TOASTER_PROJECTSPECIFIC'):
- if request.GET:
- #Example:request.GET=<QueryDict: {'setMachine': ['qemuarm']}>
- params = urlencode(request.GET).replace('%5B%27','').replace('%27%5D','')
- return redirect("%s?%s" % (reverse(project_specific, args=(project.pk,)),params))
- else:
- return redirect(reverse(project_specific, args=(project.pk,)))
- context = {"project": project}
- return toaster_render(request, "project.html", context)
- # Shows the edit project-specific page
- def project_specific(request, pid):
- project = Project.objects.get(pk=pid)
- # Are we refreshing from a successful project specific update clone?
- if Project.PROJECT_SPECIFIC_CLONING_SUCCESS == project.get_variable(Project.PROJECT_SPECIFIC_STATUS):
- return redirect(reverse(landing_specific,args=(project.pk,)))
- context = {
- "project": project,
- "is_new" : project.get_variable(Project.PROJECT_SPECIFIC_ISNEW),
- "default_image_recipe" : project.get_variable(Project.PROJECT_SPECIFIC_DEFAULTIMAGE),
- "mru" : Build.objects.all().filter(project=project,outcome=Build.IN_PROGRESS),
- }
- if project.build_set.filter(outcome=Build.IN_PROGRESS).count() > 0:
- context['build_in_progress_none_completed'] = True
- else:
- context['build_in_progress_none_completed'] = False
- return toaster_render(request, "project.html", context)
- # perform the final actions for the project specific page
- def project_specific_finalize(cmnd, pid):
- project = Project.objects.get(pk=pid)
- callback = project.get_variable(Project.PROJECT_SPECIFIC_CALLBACK)
- if "update" == cmnd:
- # Delete all '_PROJECT_PREPARE_' builds
- for b in Build.objects.all().filter(project=project):
- delete_build = False
- for t in b.target_set.all():
- if '_PROJECT_PREPARE_' == t.target:
- delete_build = True
- if delete_build:
- from django.core import management
- management.call_command('builddelete', str(b.id), interactive=False)
- # perform callback at this last moment if defined, in case Toaster gets shutdown next
- default_target = project.get_variable(Project.PROJECT_SPECIFIC_DEFAULTIMAGE)
- if callback:
- callback = callback.replace("<IMAGE>",default_target)
- if "cancel" == cmnd:
- if callback:
- callback = callback.replace("<IMAGE>","none")
- callback = callback.replace("--update","--cancel")
- # perform callback at this last moment if defined, in case this Toaster gets shutdown next
- ret = ''
- if callback:
- ret = os.system('bash -c "%s"' % callback)
- project.set_variable(Project.PROJECT_SPECIFIC_CALLBACK,'')
- # Delete the temp project specific variables
- project.set_variable(Project.PROJECT_SPECIFIC_ISNEW,'')
- project.set_variable(Project.PROJECT_SPECIFIC_STATUS,Project.PROJECT_SPECIFIC_NONE)
- # WORKAROUND: Release this workaround flag
- project.set_variable('INTERNAL_PROJECT_SPECIFIC_SKIPRELEASE','')
- # Shows the final landing page for project specific update
- def landing_specific(request, pid):
- project_specific_finalize("update", pid)
- context = {
- "install_dir": os.environ['TOASTER_DIR'],
- }
- return toaster_render(request, "landing_specific.html", context)
- # Shows the related landing-specific page
- def landing_specific_cancel(request, pid):
- project_specific_finalize("cancel", pid)
- context = {
- "install_dir": os.environ['TOASTER_DIR'],
- "status": "cancel",
- }
- return toaster_render(request, "landing_specific.html", context)
- def jsunittests(request):
- """ Provides a page for the js unit tests """
- bbv = BitbakeVersion.objects.filter(branch="master").first()
- release = Release.objects.filter(bitbake_version=bbv).first()
- name = "_js_unit_test_prj_"
- # If there is an existing project by this name delete it.
- # We don't want Lots of duplicates cluttering up the projects.
- Project.objects.filter(name=name).delete()
- new_project = Project.objects.create_project(name=name,
- release=release)
- # Add a layer
- layer = new_project.get_all_compatible_layer_versions().first()
- ProjectLayer.objects.get_or_create(layercommit=layer,
- project=new_project)
- # make sure we have a machine set for this project
- ProjectVariable.objects.get_or_create(project=new_project,
- name="MACHINE",
- value="qemux86")
- context = {'project': new_project}
- return toaster_render(request, "js-unit-tests.html", context)
- from django.views.decorators.csrf import csrf_exempt
- @csrf_exempt
- def xhr_testreleasechange(request, pid):
- def response(data):
- return HttpResponse(jsonfilter(data),
- content_type="application/json")
- """ returns layer versions that would be deleted on the new
- release__pk """
- try:
- prj = Project.objects.get(pk = pid)
- new_release_id = request.GET['new_release_id']
- # If we're already on this project do nothing
- if prj.release.pk == int(new_release_id):
- return reponse({"error": "ok", "rows": []})
- retval = []
- for project in prj.projectlayer_set.all():
- release = Release.objects.get(pk = new_release_id)
- layer_versions = prj.get_all_compatible_layer_versions()
- layer_versions = layer_versions.filter(release = release)
- layer_versions = layer_versions.filter(layer__name = project.layercommit.layer.name)
- # there is no layer_version with the new release id,
- # and the same name
- if layer_versions.count() < 1:
- retval.append(project)
- return response({"error":"ok",
- "rows": [_lv_to_dict(prj) for y in [x.layercommit for x in retval]]
- })
- except Exception as e:
- return response({"error": str(e) })
- def xhr_configvaredit(request, pid):
- try:
- prj = Project.objects.get(id = pid)
- # There are cases where user can add variables which hold values
- # like http://, file:/// etc. In such case a simple split(":")
- # would fail. One example is SSTATE_MIRRORS variable. So we use
- # max_split var to handle them.
- max_split = 1
- # add conf variables
- if 'configvarAdd' in request.POST:
- t=request.POST['configvarAdd'].strip()
- if ":" in t:
- variable, value = t.split(":", max_split)
- else:
- variable = t
- value = ""
- pt, created = ProjectVariable.objects.get_or_create(project = prj, name = variable, value = value)
- # change conf variables
- if 'configvarChange' in request.POST:
- t=request.POST['configvarChange'].strip()
- if ":" in t:
- variable, value = t.split(":", max_split)
- else:
- variable = t
- value = ""
- pt, created = ProjectVariable.objects.get_or_create(project = prj, name = variable)
- pt.value=value
- pt.save()
- # remove conf variables
- if 'configvarDel' in request.POST:
- t=request.POST['configvarDel'].strip()
- pt = ProjectVariable.objects.get(pk = int(t)).delete()
- # return all project settings, filter out blacklist and elsewhere-managed variables
- vars_managed,vars_fstypes,vars_blacklist = get_project_configvars_context()
- configvars_query = ProjectVariable.objects.filter(project_id = pid).all()
- for var in vars_managed:
- configvars_query = configvars_query.exclude(name = var)
- for var in vars_blacklist:
- configvars_query = configvars_query.exclude(name = var)
- return_data = {
- "error": "ok",
- 'configvars': [(x.name, x.value, x.pk) for x in configvars_query]
- }
- try:
- return_data['distro'] = ProjectVariable.objects.get(project = prj, name = "DISTRO").value,
- except ProjectVariable.DoesNotExist:
- pass
- try:
- return_data['dl_dir'] = ProjectVariable.objects.get(project = prj, name = "DL_DIR").value,
- except ProjectVariable.DoesNotExist:
- pass
- try:
- return_data['fstypes'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_FSTYPES").value,
- except ProjectVariable.DoesNotExist:
- pass
- try:
- return_data['image_install_append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL_append").value,
- except ProjectVariable.DoesNotExist:
- pass
- try:
- return_data['package_classes'] = ProjectVariable.objects.get(project = prj, name = "PACKAGE_CLASSES").value,
- except ProjectVariable.DoesNotExist:
- pass
- try:
- return_data['sstate_dir'] = ProjectVariable.objects.get(project = prj, name = "SSTATE_DIR").value,
- except ProjectVariable.DoesNotExist:
- pass
- return HttpResponse(json.dumps( return_data ), content_type = "application/json")
- except Exception as e:
- return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
- def customrecipe_download(request, pid, recipe_id):
- recipe = get_object_or_404(CustomImageRecipe, pk=recipe_id)
- file_data = recipe.generate_recipe_file_contents()
- response = HttpResponse(file_data, content_type='text/plain')
- response['Content-Disposition'] = \
- 'attachment; filename="%s_%s.bb"' % (recipe.name,
- recipe.version)
- return response
- def importlayer(request, pid):
- template = "importlayer.html"
- context = {
- 'project': Project.objects.get(id=pid),
- }
- return toaster_render(request, template, context)
- def layerdetails(request, pid, layerid):
- project = Project.objects.get(pk=pid)
- layer_version = Layer_Version.objects.get(pk=layerid)
- project_layers = ProjectLayer.objects.filter(
- project=project).values_list("layercommit_id",
- flat=True)
- context = {
- 'project': project,
- 'layer_source': LayerSource.types_dict(),
- 'layerversion': layer_version,
- 'layerdeps': {
- "list": [
- {
- "id": dep.id,
- "name": dep.layer.name,
- "layerdetailurl": reverse('layerdetails',
- args=(pid, dep.pk)),
- "vcs_url": dep.layer.vcs_url,
- "vcs_reference": dep.get_vcs_reference()
- }
- for dep in layer_version.get_alldeps(project.id)]
- },
- 'projectlayers': list(project_layers)
- }
- return toaster_render(request, 'layerdetails.html', context)
- def get_project_configvars_context():
- # Vars managed outside of this view
- vars_managed = {
- 'MACHINE', 'BBLAYERS'
- }
- vars_blacklist = {
- 'PARALLEL_MAKE','BB_NUMBER_THREADS',
- 'BB_DISKMON_DIRS','BB_NUMBER_THREADS','CVS_PROXY_HOST','CVS_PROXY_PORT',
- 'PARALLEL_MAKE','TMPDIR',
- 'all_proxy','ftp_proxy','http_proxy ','https_proxy'
- }
- vars_fstypes = Target_Image_File.SUFFIXES
- return(vars_managed,sorted(vars_fstypes),vars_blacklist)
- def projectconf(request, pid):
- try:
- prj = Project.objects.get(id = pid)
- except Project.DoesNotExist:
- return HttpResponseNotFound("<h1>Project id " + pid + " is unavailable</h1>")
- # remove blacklist and externally managed varaibles from this list
- vars_managed,vars_fstypes,vars_blacklist = get_project_configvars_context()
- configvars = ProjectVariable.objects.filter(project_id = pid).all()
- for var in vars_managed:
- configvars = configvars.exclude(name = var)
- for var in vars_blacklist:
- configvars = configvars.exclude(name = var)
- context = {
- 'project': prj,
- 'configvars': configvars,
- 'vars_managed': vars_managed,
- 'vars_fstypes': vars_fstypes,
- 'vars_blacklist': vars_blacklist,
- }
- try:
- context['distro'] = ProjectVariable.objects.get(project = prj, name = "DISTRO").value
- context['distro_defined'] = "1"
- except ProjectVariable.DoesNotExist:
- pass
- try:
- if ProjectVariable.objects.get(project = prj, name = "DL_DIR").value == "${TOPDIR}/../downloads":
- be = BuildEnvironment.objects.get(pk = str(1))
- dl_dir = os.path.join(dirname(be.builddir), "downloads")
- context['dl_dir'] = dl_dir
- pv, created = ProjectVariable.objects.get_or_create(project = prj, name = "DL_DIR")
- pv.value = dl_dir
- pv.save()
- else:
- context['dl_dir'] = ProjectVariable.objects.get(project = prj, name = "DL_DIR").value
- context['dl_dir_defined'] = "1"
- except (ProjectVariable.DoesNotExist, BuildEnvironment.DoesNotExist):
- pass
- try:
- context['fstypes'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_FSTYPES").value
- context['fstypes_defined'] = "1"
- except ProjectVariable.DoesNotExist:
- pass
- try:
- context['image_install_append'] = ProjectVariable.objects.get(project = prj, name = "IMAGE_INSTALL_append").value
- context['image_install_append_defined'] = "1"
- except ProjectVariable.DoesNotExist:
- pass
- try:
- context['package_classes'] = ProjectVariable.objects.get(project = prj, name = "PACKAGE_CLASSES").value
- context['package_classes_defined'] = "1"
- except ProjectVariable.DoesNotExist:
- pass
- try:
- if ProjectVariable.objects.get(project = prj, name = "SSTATE_DIR").value == "${TOPDIR}/../sstate-cache":
- be = BuildEnvironment.objects.get(pk = str(1))
- sstate_dir = os.path.join(dirname(be.builddir), "sstate-cache")
- context['sstate_dir'] = sstate_dir
- pv, created = ProjectVariable.objects.get_or_create(project = prj, name = "SSTATE_DIR")
- pv.value = sstate_dir
- pv.save()
- else:
- context['sstate_dir'] = ProjectVariable.objects.get(project = prj, name = "SSTATE_DIR").value
- context['sstate_dir_defined'] = "1"
- except (ProjectVariable.DoesNotExist, BuildEnvironment.DoesNotExist):
- pass
- return toaster_render(request, "projectconf.html", context)
- def _file_names_for_artifact(build, artifact_type, artifact_id):
- """
- Return a tuple (file path, file name for the download response) for an
- artifact of type artifact_type with ID artifact_id for build; if
- artifact type is not supported, returns (None, None)
- """
- file_name = None
- response_file_name = None
- if artifact_type == "cookerlog":
- file_name = build.cooker_log_path
- response_file_name = "cooker.log"
- elif artifact_type == "imagefile":
- file_name = Target_Image_File.objects.get(target__build = build, pk = artifact_id).file_name
- elif artifact_type == "targetkernelartifact":
- target = TargetKernelFile.objects.get(pk=artifact_id)
- file_name = target.file_name
- elif artifact_type == "targetsdkartifact":
- target = TargetSDKFile.objects.get(pk=artifact_id)
- file_name = target.file_name
- elif artifact_type == "licensemanifest":
- file_name = Target.objects.get(build = build, pk = artifact_id).license_manifest_path
- elif artifact_type == "packagemanifest":
- file_name = Target.objects.get(build = build, pk = artifact_id).package_manifest_path
- elif artifact_type == "tasklogfile":
- file_name = Task.objects.get(build = build, pk = artifact_id).logfile
- elif artifact_type == "logmessagefile":
- file_name = LogMessage.objects.get(build = build, pk = artifact_id).pathname
- if file_name and not response_file_name:
- response_file_name = os.path.basename(file_name)
- return (file_name, response_file_name)
- def build_artifact(request, build_id, artifact_type, artifact_id):
- """
- View which returns a build artifact file as a response
- """
- file_name = None
- response_file_name = None
- try:
- build = Build.objects.get(pk = build_id)
- file_name, response_file_name = _file_names_for_artifact(
- build, artifact_type, artifact_id
- )
- if file_name and response_file_name:
- fsock = open(file_name, "rb")
- content_type = MimeTypeFinder.get_mimetype(file_name)
- response = HttpResponse(fsock, content_type = content_type)
- disposition = "attachment; filename=" + response_file_name
- response["Content-Disposition"] = disposition
- return response
- else:
- return toaster_render(request, "unavailable_artifact.html")
- except (ObjectDoesNotExist, IOError):
- return toaster_render(request, "unavailable_artifact.html")
|