|
@@ -6,24 +6,36 @@
|
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
|
#
|
|
|
|
|
|
+import ast
|
|
|
import re
|
|
|
+import subprocess
|
|
|
+import sys
|
|
|
+
|
|
|
+import bb.cooker
|
|
|
+from bb.ui import toasterui
|
|
|
+from bb.ui import eventreplay
|
|
|
|
|
|
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.shortcuts import render, redirect, get_object_or_404, HttpResponseRedirect
|
|
|
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 orm.models import BitbakeVersion, CustomImageRecipe, EventLogsImports
|
|
|
|
|
|
from django.urls import reverse, resolve
|
|
|
+from django.contrib import messages
|
|
|
+
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
|
+from django.core.files.storage import FileSystemStorage
|
|
|
+from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile
|
|
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
|
from django.http import HttpResponseNotFound, JsonResponse
|
|
|
from django.utils import timezone
|
|
|
+from django.views.generic import TemplateView
|
|
|
from datetime import timedelta, datetime
|
|
|
from toastergui.templatetags.projecttags import json as jsonfilter
|
|
|
from decimal import Decimal
|
|
@@ -32,6 +44,10 @@ import os
|
|
|
from os.path import dirname
|
|
|
import mimetypes
|
|
|
|
|
|
+from toastergui.forms import LoadFileForm
|
|
|
+
|
|
|
+from collections import namedtuple
|
|
|
+
|
|
|
import logging
|
|
|
|
|
|
from toastermain.logs import log_view_mixin
|
|
@@ -41,6 +57,7 @@ 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'))
|
|
|
+import_page = False
|
|
|
|
|
|
class MimeTypeFinder(object):
|
|
|
# setting this to False enables additional non-standard mimetypes
|
|
@@ -1940,3 +1957,155 @@ if True:
|
|
|
except (ObjectDoesNotExist, IOError):
|
|
|
return toaster_render(request, "unavailable_artifact.html")
|
|
|
|
|
|
+
|
|
|
+class CommandLineBuilds(TemplateView):
|
|
|
+ model = EventLogsImports
|
|
|
+ template_name = 'command_line_builds.html'
|
|
|
+
|
|
|
+ def get_context_data(self, **kwargs):
|
|
|
+ context = super(CommandLineBuilds, self).get_context_data(**kwargs)
|
|
|
+ #get value from BB_DEFAULT_EVENTLOG defined in bitbake.conf
|
|
|
+ eventlog = subprocess.check_output(['bitbake-getvar', 'BB_DEFAULT_EVENTLOG', '--value'])
|
|
|
+ if eventlog:
|
|
|
+ logs_dir = os.path.dirname(eventlog.decode().strip('\n'))
|
|
|
+ files = os.listdir(logs_dir)
|
|
|
+ imported_files = EventLogsImports.objects.all()
|
|
|
+ files_list = []
|
|
|
+
|
|
|
+ # Filter files that end with ".json"
|
|
|
+ event_files = []
|
|
|
+ for file in files:
|
|
|
+ if file.endswith(".json"):
|
|
|
+ # because BB_DEFAULT_EVENTLOG is a directory, we need to check if the file is a valid eventlog
|
|
|
+ with open("{}/{}".format(logs_dir, file)) as efile:
|
|
|
+ content = efile.read()
|
|
|
+ if 'allvariables' in content:
|
|
|
+ event_files.append(file)
|
|
|
+
|
|
|
+ #build dict for template using db data
|
|
|
+ for event_file in event_files:
|
|
|
+ if imported_files.filter(name=event_file):
|
|
|
+ files_list.append({
|
|
|
+ 'name': event_file,
|
|
|
+ 'imported': True,
|
|
|
+ 'build_id': imported_files.filter(name=event_file)[0].build_id,
|
|
|
+ 'size': os.path.getsize("{}/{}".format(logs_dir, event_file))
|
|
|
+ })
|
|
|
+ else:
|
|
|
+ files_list.append({
|
|
|
+ 'name': event_file,
|
|
|
+ 'imported': False,
|
|
|
+ 'build_id': None,
|
|
|
+ 'size': os.path.getsize("{}/{}".format(logs_dir, event_file))
|
|
|
+ })
|
|
|
+ context['import_all'] = True
|
|
|
+
|
|
|
+ context['files'] = files_list
|
|
|
+ context['dir'] = logs_dir
|
|
|
+ else:
|
|
|
+ context['files'] = []
|
|
|
+ context['dir'] = ''
|
|
|
+
|
|
|
+ # enable session variable
|
|
|
+ if not self.request.session.get('file'):
|
|
|
+ self.request.session['file'] = ""
|
|
|
+
|
|
|
+ context['form'] = LoadFileForm()
|
|
|
+ context['project_enable'] = project_enable
|
|
|
+ return context
|
|
|
+
|
|
|
+ def post(self, request, **kwargs):
|
|
|
+ logs_dir = request.POST.get('dir')
|
|
|
+ all_files = request.POST.get('all')
|
|
|
+
|
|
|
+ imported_files = EventLogsImports.objects.all()
|
|
|
+ try:
|
|
|
+ if all_files == 'true':
|
|
|
+ # use of session variable to deactivate icon for builds in progress
|
|
|
+ request.session['all_builds'] = True
|
|
|
+ request.session.modified = True
|
|
|
+ request.session.save()
|
|
|
+
|
|
|
+ files = ast.literal_eval(request.POST.get('file'))
|
|
|
+ for file in files:
|
|
|
+ if imported_files.filter(name=file.get('name')).exists():
|
|
|
+ imported_files.filter(name=file.get('name'))[0].imported = True
|
|
|
+ else:
|
|
|
+ with open("{}/{}".format(logs_dir, file.get('name'))) as eventfile:
|
|
|
+ # load variables from the first line
|
|
|
+ variables = None
|
|
|
+ while line := eventfile.readline().strip():
|
|
|
+ try:
|
|
|
+ variables = json.loads(line)['allvariables']
|
|
|
+ break
|
|
|
+ except (KeyError, json.JSONDecodeError):
|
|
|
+ continue
|
|
|
+ if not variables:
|
|
|
+ raise Exception("File content missing build variables")
|
|
|
+ eventfile.seek(0)
|
|
|
+ params = namedtuple('ConfigParams', ['observe_only'])(True)
|
|
|
+ player = eventreplay.EventPlayer(eventfile, variables)
|
|
|
+
|
|
|
+ toasterui.main(player, player, params)
|
|
|
+ event_log_import = EventLogsImports.objects.create(name=file.get('name'), imported=True)
|
|
|
+ event_log_import.build_id = Build.objects.last().id
|
|
|
+ event_log_import.save()
|
|
|
+ else:
|
|
|
+ if self.request.FILES.get('eventlog_file'):
|
|
|
+ file = self.request.FILES['eventlog_file']
|
|
|
+ else:
|
|
|
+ file = request.POST.get('file')
|
|
|
+ # use of session variable to deactivate icon for build in progress
|
|
|
+ request.session['file'] = file
|
|
|
+ request.session['all_builds'] = False
|
|
|
+ request.session.modified = True
|
|
|
+ request.session.save()
|
|
|
+
|
|
|
+ if imported_files.filter(name=file).exists():
|
|
|
+ imported_files.filter(name=file)[0].imported = True
|
|
|
+ else:
|
|
|
+ if isinstance(file, InMemoryUploadedFile) or isinstance(file, TemporaryUploadedFile):
|
|
|
+ variables = None
|
|
|
+ while line := file.readline().strip():
|
|
|
+ try:
|
|
|
+ variables = json.loads(line)['allvariables']
|
|
|
+ break
|
|
|
+ except (KeyError, json.JSONDecodeError):
|
|
|
+ continue
|
|
|
+ if not variables:
|
|
|
+ raise Exception("File content missing build variables")
|
|
|
+ file.seek(0)
|
|
|
+ params = namedtuple('ConfigParams', ['observe_only'])(True)
|
|
|
+ player = eventreplay.EventPlayer(file, variables)
|
|
|
+ if not os.path.exists('{}/{}'.format(logs_dir, file.name)):
|
|
|
+ fs = FileSystemStorage(location=logs_dir)
|
|
|
+ fs.save(file.name, file)
|
|
|
+ toasterui.main(player, player, params)
|
|
|
+ else:
|
|
|
+ with open("{}/{}".format(logs_dir, file)) as eventfile:
|
|
|
+ # load variables from the first line
|
|
|
+ variables = None
|
|
|
+ while line := eventfile.readline().strip():
|
|
|
+ try:
|
|
|
+ variables = json.loads(line)['allvariables']
|
|
|
+ break
|
|
|
+ except (KeyError, json.JSONDecodeError):
|
|
|
+ continue
|
|
|
+ if not variables:
|
|
|
+ raise Exception("File content missing build variables")
|
|
|
+ eventfile.seek(0)
|
|
|
+ params = namedtuple('ConfigParams', ['observe_only'])(True)
|
|
|
+ player = eventreplay.EventPlayer(eventfile, variables)
|
|
|
+ toasterui.main(player, player, params)
|
|
|
+ event_log_import = EventLogsImports.objects.create(name=file, imported=True)
|
|
|
+ event_log_import.build_id = Build.objects.last().id
|
|
|
+ event_log_import.save()
|
|
|
+ request.session['file'] = ""
|
|
|
+ except Exception:
|
|
|
+ messages.add_message(
|
|
|
+ self.request,
|
|
|
+ messages.ERROR,
|
|
|
+ "The file content is not in the correct format. Update file content or upload a different file."
|
|
|
+ )
|
|
|
+ return HttpResponseRedirect("/toastergui/cmdline/")
|
|
|
+ return HttpResponseRedirect('/toastergui/builds/')
|