mirror of
https://git.yoctoproject.org/poky
synced 2026-06-01 00:59:48 +00:00
bitbake: toaster: bitbake cooker log saving and downloading
This patch brings in cooker log saving and proper download links. * toasterui will now write the cooker log file if running in managed mode * the BuildRequest has a new state, REQ_ARCHIVE, indicating that the build is completed, and the artifacts are ready to be grabbed * the runbuild test execution commands will gather needed artifacts, and save them to a storage directory selected during Toaster setup. * the build dashboard, project builds and all builds pages have permanent links for the cooker log [YOCTO #7220] [YOCTO #7206] (Bitbake rev: fad80e36c9da663b000cdf2cb3c75440c6431d84) Signed-off-by: Alexandru DAMIAN <alexandru.damian@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
committed by
Richard Purdie
parent
a574f293fe
commit
c368d83bd6
@@ -62,6 +62,23 @@ class Command(NoArgsCommand):
|
||||
|
||||
|
||||
def handle(self, **options):
|
||||
# verify that we have a settings for downloading artifacts
|
||||
while ToasterSetting.objects.filter(name="ARTIFACTS_STORAGE_DIR").count() == 0:
|
||||
guessedpath = os.getcwd() + "/toaster_build_artifacts/"
|
||||
print("Toaster needs to know in which directory it can download build log files and other artifacts.\n Toaster suggests \"%s\"." % guessedpath)
|
||||
artifacts_storage_dir = raw_input(" Press Enter to select \"%s\" or type the full path to a different directory: " % guessedpath)
|
||||
if len(artifacts_storage_dir) == 0:
|
||||
artifacts_storage_dir = guessedpath
|
||||
if len(artifacts_storage_dir) > 0 and artifacts_storage_dir.startswith("/"):
|
||||
try:
|
||||
os.makedirs(artifacts_storage_dir)
|
||||
except OSError as ose:
|
||||
if "File exists" in str(ose):
|
||||
pass
|
||||
else:
|
||||
raise ose
|
||||
ToasterSetting.objects.create(name="ARTIFACTS_STORAGE_DIR", value=artifacts_storage_dir)
|
||||
|
||||
self.guesspath = DN(DN(DN(DN(DN(DN(DN(__file__)))))))
|
||||
# refuse to start if we have no build environments
|
||||
while BuildEnvironment.objects.count() == 0:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.core.management.base import NoArgsCommand, CommandError
|
||||
from django.db import transaction
|
||||
from orm.models import Build
|
||||
from orm.models import Build, ToasterSetting
|
||||
from bldcontrol.bbcontroller import getBuildEnvironmentController, ShellCmdException, BuildSetupException
|
||||
from bldcontrol.models import BuildRequest, BuildEnvironment, BRError, BRVariable
|
||||
import os
|
||||
@@ -93,7 +93,33 @@ class Command(NoArgsCommand):
|
||||
bec.be.lock = BuildEnvironment.LOCK_FREE
|
||||
bec.be.save()
|
||||
|
||||
def archive(self):
|
||||
''' archives data from the builds '''
|
||||
artifact_storage_dir = ToasterSetting.objects.get(name="ARTIFACTS_STORAGE_DIR").value
|
||||
for br in BuildRequest.objects.filter(state = BuildRequest.REQ_ARCHIVE):
|
||||
# save cooker log
|
||||
if br.build == None:
|
||||
br.state = BuildRequest.REQ_FAILED
|
||||
br.save()
|
||||
continue
|
||||
build_artifact_storage_dir = os.path.join(artifact_storage_dir, "%d" % br.build.pk)
|
||||
try:
|
||||
os.makedirs(build_artifact_storage_dir)
|
||||
except OSError as ose:
|
||||
if "File exists" in str(ose):
|
||||
pass
|
||||
else:
|
||||
raise ose
|
||||
|
||||
file_name = os.path.join(build_artifact_storage_dir, "cooker_log.txt")
|
||||
try:
|
||||
with open(file_name, "w") as f:
|
||||
f.write(br.environment.get_artifact(br.build.cooker_log_path).read())
|
||||
except IOError:
|
||||
os.unlink(file_name)
|
||||
|
||||
br.state = BuildRequest.REQ_COMPLETED
|
||||
br.save()
|
||||
|
||||
def cleanup(self):
|
||||
from django.utils import timezone
|
||||
@@ -104,4 +130,5 @@ class Command(NoArgsCommand):
|
||||
|
||||
def handle_noargs(self, **options):
|
||||
self.cleanup()
|
||||
self.archive()
|
||||
self.schedule()
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(DataMigration):
|
||||
# ids that cannot be imported from BuildRequest
|
||||
|
||||
def forwards(self, orm):
|
||||
REQ_COMPLETED = 3
|
||||
REQ_ARCHIVE = 6
|
||||
"Write your forwards methods here."
|
||||
# Note: Don't use "from appname.models import ModelName".
|
||||
# Use orm.ModelName to refer to models in this application,
|
||||
# and orm['appname.ModelName'] for models in other applications.
|
||||
orm.BuildRequest.objects.filter(state=REQ_COMPLETED).update(state=REQ_ARCHIVE)
|
||||
|
||||
def backwards(self, orm):
|
||||
REQ_COMPLETED = 3
|
||||
REQ_ARCHIVE = 6
|
||||
"Write your backwards methods here."
|
||||
orm.BuildRequest.objects.filter(state=REQ_ARCHIVE).update(state=REQ_COMPLETED)
|
||||
|
||||
models = {
|
||||
u'bldcontrol.brbitbake': {
|
||||
'Meta': {'object_name': 'BRBitbake'},
|
||||
'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']", 'unique': 'True'})
|
||||
},
|
||||
u'bldcontrol.brerror': {
|
||||
'Meta': {'object_name': 'BRError'},
|
||||
'errmsg': ('django.db.models.fields.TextField', [], {}),
|
||||
'errtype': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
|
||||
'traceback': ('django.db.models.fields.TextField', [], {})
|
||||
},
|
||||
u'bldcontrol.brlayer': {
|
||||
'Meta': {'object_name': 'BRLayer'},
|
||||
'commit': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'giturl': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"})
|
||||
},
|
||||
u'bldcontrol.brtarget': {
|
||||
'Meta': {'object_name': 'BRTarget'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
|
||||
'target': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'task': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'})
|
||||
},
|
||||
u'bldcontrol.brvariable': {
|
||||
'Meta': {'object_name': 'BRVariable'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'req': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildRequest']"}),
|
||||
'value': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
u'bldcontrol.buildenvironment': {
|
||||
'Meta': {'object_name': 'BuildEnvironment'},
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '254'}),
|
||||
'bbaddress': ('django.db.models.fields.CharField', [], {'max_length': '254', 'blank': 'True'}),
|
||||
'bbport': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
|
||||
'bbstate': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'bbtoken': ('django.db.models.fields.CharField', [], {'max_length': '126', 'blank': 'True'}),
|
||||
'betype': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'builddir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'lock': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'sourcedir': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'bldcontrol.buildrequest': {
|
||||
'Meta': {'object_name': 'BuildRequest'},
|
||||
'build': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['orm.Build']", 'unique': 'True', 'null': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'environment': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['bldcontrol.BuildEnvironment']", 'null': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']"}),
|
||||
'state': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'orm.bitbakeversion': {
|
||||
'Meta': {'object_name': 'BitbakeVersion'},
|
||||
'branch': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
|
||||
'dirpath': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'giturl': ('django.db.models.fields.URLField', [], {'max_length': '200'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
|
||||
},
|
||||
u'orm.build': {
|
||||
'Meta': {'object_name': 'Build'},
|
||||
'bitbake_version': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
|
||||
'build_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'completed_on': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'cooker_log_path': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
|
||||
'distro': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'distro_version': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'errors_no': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'machine': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'outcome': ('django.db.models.fields.IntegerField', [], {'default': '2'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Project']", 'null': 'True'}),
|
||||
'started_on': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'timespent': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'warnings_no': ('django.db.models.fields.IntegerField', [], {'default': '0'})
|
||||
},
|
||||
u'orm.project': {
|
||||
'Meta': {'object_name': 'Project'},
|
||||
'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'release': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.Release']"}),
|
||||
'short_description': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
|
||||
'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'})
|
||||
},
|
||||
u'orm.release': {
|
||||
'Meta': {'object_name': 'Release'},
|
||||
'bitbake_version': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['orm.BitbakeVersion']"}),
|
||||
'branch_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50'}),
|
||||
'description': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'helptext': ('django.db.models.fields.TextField', [], {'null': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '32'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['bldcontrol']
|
||||
symmetrical = True
|
||||
@@ -94,6 +94,7 @@ class BuildRequest(models.Model):
|
||||
REQ_COMPLETED = 3
|
||||
REQ_FAILED = 4
|
||||
REQ_DELETED = 5
|
||||
REQ_ARCHIVE = 6
|
||||
|
||||
REQUEST_STATE = (
|
||||
(REQ_CREATED, "created"),
|
||||
@@ -102,6 +103,7 @@ class BuildRequest(models.Model):
|
||||
(REQ_COMPLETED, "completed"),
|
||||
(REQ_FAILED, "failed"),
|
||||
(REQ_DELETED, "deleted"),
|
||||
(REQ_ARCHIVE, "archive"),
|
||||
)
|
||||
|
||||
search_allowed_fields = ("brtarget__target",)
|
||||
|
||||
Reference in New Issue
Block a user