diff options
author | Elliot Smith <elliot.smith@intel.com> | 2016-07-12 15:54:48 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-07-19 08:56:51 +0100 |
commit | 00c2c0be5ead435601a21a676401674b7045f6f0 (patch) | |
tree | 32295fe980f44dfae3353ed7bf58691aee356ecb /bitbake/lib/toaster/orm/models.py | |
parent | f39ae146eadf92f650ed6340158e780a65d483b1 (diff) | |
download | poky-00c2c0be5ead435601a21a676401674b7045f6f0.tar.gz |
bitbake: toaster: improve scan for SDK artifacts
SDK artifacts were previously picked up by toaster.bbclass and
notified to buildinfohelper (via toasterui). The artifacts
were then added to the Build object, so that it wasn't clear
which artifact went with which target; we were also unable
to attach SDK artifacts to a Build if they had already been
attached to a previous build.
Now, toaster.bbclass just notifies the TOOLCHAIN_OUTPUTNAME when
a populate_sdk* target completes. The scan is moved to buildinfohelper,
where we search the SDK deploy directory for files matching
TOOLCHAIN_OUTPUTNAME and attach them to targets (not builds).
If an SDK file is not produced by a target, we now look for a
similar, previously-run target which did produce artifacts.
If there is one, we clone the SDK artifacts from that target
onto the current one.
This all means that we can show SDK artifacts by target, and should
always get artifacts associated with a target, regardless of whether
it really build them.
This requires an additional model, TargetSDKFile, which tracks
the size and path of SDK artifact files with respect to Target
objects.
[YOCTO #8556]
(Bitbake rev: 5e650c611605507e1e0d1588cd5eb6535c2d34fc)
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
Signed-off-by: bavery <brian.avery@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/orm/models.py')
-rw-r--r-- | bitbake/lib/toaster/orm/models.py | 112 |
1 files changed, 70 insertions, 42 deletions
diff --git a/bitbake/lib/toaster/orm/models.py b/bitbake/lib/toaster/orm/models.py index 9edbef3396..61f6a2072e 100644 --- a/bitbake/lib/toaster/orm/models.py +++ b/bitbake/lib/toaster/orm/models.py | |||
@@ -581,28 +581,6 @@ class Build(models.Model): | |||
581 | def __str__(self): | 581 | def __str__(self): |
582 | return "%d %s %s" % (self.id, self.project, ",".join([t.target for t in self.target_set.all()])) | 582 | return "%d %s %s" % (self.id, self.project, ",".join([t.target for t in self.target_set.all()])) |
583 | 583 | ||
584 | |||
585 | # an Artifact is anything that results from a Build, and may be of interest to the user, and is not stored elsewhere | ||
586 | class BuildArtifact(models.Model): | ||
587 | build = models.ForeignKey(Build) | ||
588 | file_name = models.FilePathField() | ||
589 | file_size = models.IntegerField() | ||
590 | |||
591 | def get_local_file_name(self): | ||
592 | try: | ||
593 | deploydir = Variable.objects.get(build = self.build, variable_name="DEPLOY_DIR").variable_value | ||
594 | return self.file_name[len(deploydir)+1:] | ||
595 | except: | ||
596 | raise | ||
597 | |||
598 | return self.file_name | ||
599 | |||
600 | def get_basename(self): | ||
601 | return os.path.basename(self.file_name) | ||
602 | |||
603 | def is_available(self): | ||
604 | return self.build.buildrequest.environment.has_artifact(self.file_name) | ||
605 | |||
606 | class ProjectTarget(models.Model): | 584 | class ProjectTarget(models.Model): |
607 | project = models.ForeignKey(Project) | 585 | project = models.ForeignKey(Project) |
608 | target = models.CharField(max_length=100) | 586 | target = models.CharField(max_length=100) |
@@ -625,13 +603,19 @@ class Target(models.Model): | |||
625 | 603 | ||
626 | def get_similar_targets(self): | 604 | def get_similar_targets(self): |
627 | """ | 605 | """ |
628 | Get targets for the same machine, task and target name | 606 | Get target sfor the same machine, task and target name |
629 | (e.g. 'core-image-minimal') from a successful build for this project | 607 | (e.g. 'core-image-minimal') from a successful build for this project |
630 | (but excluding this target). | 608 | (but excluding this target). |
631 | 609 | ||
632 | Note that we look for targets built by this project because projects | 610 | Note that we only look for targets built by this project because |
633 | can have different configurations from each other, and put their | 611 | projects can have different configurations from each other, and put |
634 | artifacts in different directories. | 612 | their artifacts in different directories. |
613 | |||
614 | The possibility of error when retrieving candidate targets | ||
615 | is minimised by the fact that bitbake will rebuild artifacts if MACHINE | ||
616 | (or various other variables) change. In this case, there is no need to | ||
617 | clone artifacts from another target, as those artifacts will have | ||
618 | been re-generated for this target anyway. | ||
635 | """ | 619 | """ |
636 | query = ~Q(pk=self.pk) & \ | 620 | query = ~Q(pk=self.pk) & \ |
637 | Q(target=self.target) & \ | 621 | Q(target=self.target) & \ |
@@ -649,29 +633,54 @@ class Target(models.Model): | |||
649 | similar_target = None | 633 | similar_target = None |
650 | 634 | ||
651 | candidates = self.get_similar_targets() | 635 | candidates = self.get_similar_targets() |
652 | if candidates.count() < 1: | 636 | if candidates.count() == 0: |
653 | return similar_target | 637 | return similar_target |
654 | 638 | ||
655 | task_subquery = Q(task=self.task) | 639 | task_subquery = Q(task=self.task) |
656 | 640 | ||
657 | # we can look for a 'build' task if this task is a 'populate_sdk_ext' | 641 | # we can look for a 'build' task if this task is a 'populate_sdk_ext' |
658 | # task, as it will have created images; and vice versa; note that | 642 | # task, as the latter also creates images; and vice versa; note that |
659 | # 'build' targets can have their task set to ''; | 643 | # 'build' targets can have their task set to ''; |
660 | # also note that 'populate_sdk' does not produce image files | 644 | # also note that 'populate_sdk' does not produce image files |
661 | image_tasks = [ | 645 | image_tasks = [ |
662 | '', # aka 'build' | 646 | '', # aka 'build' |
663 | 'build', | 647 | 'build', |
648 | 'image', | ||
664 | 'populate_sdk_ext' | 649 | 'populate_sdk_ext' |
665 | ] | 650 | ] |
666 | if self.task in image_tasks: | 651 | if self.task in image_tasks: |
667 | task_subquery = Q(task__in=image_tasks) | 652 | task_subquery = Q(task__in=image_tasks) |
668 | 653 | ||
654 | # annotate with the count of files, to exclude any targets which | ||
655 | # don't have associated files | ||
656 | candidates = candidates.annotate(num_files=Count('target_image_file')) | ||
657 | |||
669 | query = task_subquery & Q(num_files__gt=0) | 658 | query = task_subquery & Q(num_files__gt=0) |
670 | 659 | ||
660 | candidates = candidates.filter(query) | ||
661 | |||
662 | if candidates.count() > 0: | ||
663 | candidates.order_by('build__completed_on') | ||
664 | similar_target = candidates.last() | ||
665 | |||
666 | return similar_target | ||
667 | |||
668 | def get_similar_target_with_sdk_files(self): | ||
669 | """ | ||
670 | Get the most recent similar target with TargetSDKFiles associated | ||
671 | with it, for the purpose of cloning those files onto this target. | ||
672 | """ | ||
673 | similar_target = None | ||
674 | |||
675 | candidates = self.get_similar_targets() | ||
676 | if candidates.count() == 0: | ||
677 | return similar_target | ||
678 | |||
671 | # annotate with the count of files, to exclude any targets which | 679 | # annotate with the count of files, to exclude any targets which |
672 | # don't have associated files | 680 | # don't have associated files |
673 | candidates = candidates.annotate( | 681 | candidates = candidates.annotate(num_files=Count('targetsdkfile')) |
674 | num_files=Count('target_image_file')) | 682 | |
683 | query = Q(task=self.task) & Q(num_files__gt=0) | ||
675 | 684 | ||
676 | candidates = candidates.filter(query) | 685 | candidates = candidates.filter(query) |
677 | 686 | ||
@@ -681,11 +690,10 @@ class Target(models.Model): | |||
681 | 690 | ||
682 | return similar_target | 691 | return similar_target |
683 | 692 | ||
684 | def clone_artifacts_from(self, target): | 693 | def clone_image_artifacts_from(self, target): |
685 | """ | 694 | """ |
686 | Make clones of the BuildArtifacts, Target_Image_Files and | 695 | Make clones of the Target_Image_Files and TargetKernelFile objects |
687 | TargetArtifactFile objects associated with Target target, then | 696 | associated with Target target, then associate them with this target. |
688 | associate them with this target. | ||
689 | 697 | ||
690 | Note that for Target_Image_Files, we only want files from the previous | 698 | Note that for Target_Image_Files, we only want files from the previous |
691 | build whose suffix matches one of the suffixes defined in this | 699 | build whose suffix matches one of the suffixes defined in this |
@@ -711,18 +719,38 @@ class Target(models.Model): | |||
711 | image_file.target = self | 719 | image_file.target = self |
712 | image_file.save() | 720 | image_file.save() |
713 | 721 | ||
714 | artifact_files = target.targetartifactfile_set.all() | 722 | kernel_files = target.targetkernelfile_set.all() |
715 | for artifact_file in artifact_files: | 723 | for kernel_file in kernel_files: |
716 | artifact_file.pk = None | 724 | kernel_file.pk = None |
717 | artifact_file.target = self | 725 | kernel_file.target = self |
718 | artifact_file.save() | 726 | kernel_file.save() |
719 | 727 | ||
720 | self.license_manifest_path = target.license_manifest_path | 728 | self.license_manifest_path = target.license_manifest_path |
721 | self.save() | 729 | self.save() |
722 | 730 | ||
723 | # an Artifact is anything that results from a target being built, and may | 731 | def clone_sdk_artifacts_from(self, target): |
724 | # be of interest to the user, and is not an image file | 732 | """ |
725 | class TargetArtifactFile(models.Model): | 733 | Clone TargetSDKFile objects from target and associate them with this |
734 | target. | ||
735 | """ | ||
736 | sdk_files = target.targetsdkfile_set.all() | ||
737 | for sdk_file in sdk_files: | ||
738 | sdk_file.pk = None | ||
739 | sdk_file.target = self | ||
740 | sdk_file.save() | ||
741 | |||
742 | # kernel artifacts for a target: bzImage and modules* | ||
743 | class TargetKernelFile(models.Model): | ||
744 | target = models.ForeignKey(Target) | ||
745 | file_name = models.FilePathField() | ||
746 | file_size = models.IntegerField() | ||
747 | |||
748 | @property | ||
749 | def basename(self): | ||
750 | return os.path.basename(self.file_name) | ||
751 | |||
752 | # SDK artifacts for a target: sh and manifest files | ||
753 | class TargetSDKFile(models.Model): | ||
726 | target = models.ForeignKey(Target) | 754 | target = models.ForeignKey(Target) |
727 | file_name = models.FilePathField() | 755 | file_name = models.FilePathField() |
728 | file_size = models.IntegerField() | 756 | file_size = models.IntegerField() |