diff options
author | Elliot Smith <elliot.smith@intel.com> | 2016-07-12 15:54:46 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-07-19 08:56:51 +0100 |
commit | 4125da7763ffc70cc77578c677bb7e5fc7ebaf57 (patch) | |
tree | 3c303f0070365d73217950b96ef234cfe9bcc022 /bitbake/lib/bb/ui/buildinfohelper.py | |
parent | e9808576daad137695bdedd0883ee0a35b7d870a (diff) | |
download | poky-4125da7763ffc70cc77578c677bb7e5fc7ebaf57.tar.gz |
bitbake: toaster: attach kernel artifacts to targets
The bzImage and modules files were previously attached to a build,
rather than to the target which produced them. This meant it was
not possible to determine which kernel artifact produced by a
build came from which target; which in turn made it difficult to
associate existing kernel artifact with targets when those
targets didn't produce artifacts (e.g. if the same machine + target
combination was built again and didn't produce a bzImage or modules
file because those files already existed).
By associating kernel artifacts with the target (via a new
TargetArtifactFile model), we make it possible to find all
the artifacts for a given machine + target combination. Then, in
cases where a build is completed but its targets don't produce
any artifacts, we can find a previous Target object with the same
machine + target and copy its artifacts to the targets for a
just-completed build.
Note that this doesn't cover SDK artifacts yet, which are still
retrieved in toaster.bbclass and show up as "Other artifacts",
lumped together for the whole build rather than by target.
[YOCTO #8556]
(Bitbake rev: 9b151416e428c2565a27d89116439f9a8d578e3d)
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/bb/ui/buildinfohelper.py')
-rw-r--r-- | bitbake/lib/bb/ui/buildinfohelper.py | 85 |
1 files changed, 56 insertions, 29 deletions
diff --git a/bitbake/lib/bb/ui/buildinfohelper.py b/bitbake/lib/bb/ui/buildinfohelper.py index 8bdc9cc0a7..a5b22379aa 100644 --- a/bitbake/lib/bb/ui/buildinfohelper.py +++ b/bitbake/lib/bb/ui/buildinfohelper.py | |||
@@ -37,7 +37,7 @@ os.environ["DJANGO_SETTINGS_MODULE"] =\ | |||
37 | django.setup() | 37 | django.setup() |
38 | 38 | ||
39 | from orm.models import Build, Task, Recipe, Layer_Version, Layer, Target, LogMessage, HelpText | 39 | from orm.models import Build, Task, Recipe, Layer_Version, Layer, Target, LogMessage, HelpText |
40 | from orm.models import Target_Image_File, BuildArtifact | 40 | from orm.models import Target_Image_File, BuildArtifact, TargetArtifactFile |
41 | from orm.models import Variable, VariableHistory | 41 | from orm.models import Variable, VariableHistory |
42 | from orm.models import Package, Package_File, Target_Installed_Package, Target_File | 42 | from orm.models import Package, Package_File, Target_Installed_Package, Target_File |
43 | from orm.models import Task_Dependency, Package_Dependency | 43 | from orm.models import Task_Dependency, Package_Dependency |
@@ -121,6 +121,13 @@ class ORMWrapper(object): | |||
121 | 121 | ||
122 | return vars(self)[dictname][key] | 122 | return vars(self)[dictname][key] |
123 | 123 | ||
124 | def get_similar_target_with_image_files(self, target): | ||
125 | """ | ||
126 | Get a Target object "similar" to target; i.e. with the same target | ||
127 | name ('core-image-minimal' etc.) and machine. | ||
128 | """ | ||
129 | return target.get_similar_target_with_image_files() | ||
130 | |||
124 | def _timestamp_to_datetime(self, secs): | 131 | def _timestamp_to_datetime(self, secs): |
125 | """ | 132 | """ |
126 | Convert timestamp in seconds to Python datetime | 133 | Convert timestamp in seconds to Python datetime |
@@ -678,27 +685,32 @@ class ORMWrapper(object): | |||
678 | file_name = file_name, | 685 | file_name = file_name, |
679 | file_size = file_size) | 686 | file_size = file_size) |
680 | 687 | ||
681 | def save_artifact_information_no_dedupe(self, build_obj, file_name, file_size): | 688 | def save_target_artifact_file(self, target_obj, file_name, file_size): |
682 | """ | 689 | """ |
683 | Save artifact information without checking for duplicate paths; | 690 | Save artifact file information for a Target target_obj. |
684 | this is used when we are saving data about an artifact which was | 691 | |
685 | generated by a previous build but which is also relevant to this build, | 692 | Note that this doesn't include SDK artifacts, only images and |
686 | e.g. a bzImage file. | 693 | related files (e.g. bzImage). |
687 | """ | 694 | """ |
688 | BuildArtifact.objects.create(build=build_obj, file_name=file_name, | 695 | TargetArtifactFile.objects.create(target=target_obj, |
689 | file_size=file_size) | 696 | file_name=file_name, file_size=file_size) |
690 | 697 | ||
691 | def save_artifact_information(self, build_obj, file_name, file_size): | 698 | def save_artifact_information(self, build_obj, file_name, file_size): |
692 | # we skip the image files from other builds | 699 | """ |
693 | if Target_Image_File.objects.filter(file_name = file_name).count() > 0: | 700 | TODO this is currently used to save SDK artifacts to the database, |
694 | return | 701 | but will be replaced in future once SDK artifacts are associated with |
695 | 702 | Target objects (as they eventually should be) | |
703 | """ | ||
696 | # do not update artifacts found in other builds | 704 | # do not update artifacts found in other builds |
697 | if BuildArtifact.objects.filter(file_name = file_name).count() > 0: | 705 | if BuildArtifact.objects.filter(file_name = file_name).count() > 0: |
698 | return | 706 | return |
699 | 707 | ||
700 | self.save_artifact_information_no_dedupe(self, build_obj, file_name, | 708 | # do not update artifact if already a target artifact file for that path |
701 | file_size) | 709 | if TargetArtifactFile.objects.filter(file_name = file_name).count() > 0: |
710 | return | ||
711 | |||
712 | BuildArtifact.objects.create(build=build_obj, file_name=file_name, | ||
713 | file_size=file_size) | ||
702 | 714 | ||
703 | def create_logmessage(self, log_information): | 715 | def create_logmessage(self, log_information): |
704 | assert 'build' in log_information | 716 | assert 'build' in log_information |
@@ -1496,7 +1508,7 @@ class BuildInfoHelper(object): | |||
1496 | 1508 | ||
1497 | self.orm_wrapper.create_logmessage(log_information) | 1509 | self.orm_wrapper.create_logmessage(log_information) |
1498 | 1510 | ||
1499 | def _get_files_from_image_license(self, image_license_manifest_path): | 1511 | def _get_filenames_from_image_license(self, image_license_manifest_path): |
1500 | """ | 1512 | """ |
1501 | Find the FILES line in the image_license.manifest file, | 1513 | Find the FILES line in the image_license.manifest file, |
1502 | which has the basenames of the bzImage and modules files | 1514 | which has the basenames of the bzImage and modules files |
@@ -1567,19 +1579,20 @@ class BuildInfoHelper(object): | |||
1567 | 1579 | ||
1568 | OR | 1580 | OR |
1569 | 1581 | ||
1570 | 2. There are no files for the target, so copy them from a | 1582 | 2. There are no new files for the target (they were already produced by |
1571 | previous build with the same target + machine. | 1583 | a previous build), so copy them from the most recent previous build with |
1584 | the same target, task and machine. | ||
1572 | """ | 1585 | """ |
1573 | deploy_dir_image = \ | 1586 | deploy_dir_image = \ |
1574 | self.server.runCommand(['getVariable', 'DEPLOY_DIR_IMAGE'])[0] | 1587 | self.server.runCommand(['getVariable', 'DEPLOY_DIR_IMAGE'])[0] |
1575 | 1588 | ||
1576 | # if there's no DEPLOY_DIR_IMAGE, there aren't going to be | 1589 | # if there's no DEPLOY_DIR_IMAGE, there aren't going to be |
1577 | # any build artifacts, so we can return immediately | 1590 | # any image artifacts, so we can return immediately |
1578 | if not deploy_dir_image: | 1591 | if not deploy_dir_image: |
1579 | return | 1592 | return |
1580 | 1593 | ||
1581 | buildname = self.server.runCommand(['getVariable', 'BUILDNAME'])[0] | 1594 | buildname = self.server.runCommand(['getVariable', 'BUILDNAME'])[0] |
1582 | machine = self.server.runCommand(['getVariable', 'MACHINE'])[0] | 1595 | machine = self.server.runCommand(['getVariable', 'MACHINE'])[0] |
1583 | image_name = self.server.runCommand(['getVariable', 'IMAGE_NAME'])[0] | 1596 | image_name = self.server.runCommand(['getVariable', 'IMAGE_NAME'])[0] |
1584 | 1597 | ||
1585 | # location of the image_license.manifest files for this build; | 1598 | # location of the image_license.manifest files for this build; |
@@ -1597,7 +1610,10 @@ class BuildInfoHelper(object): | |||
1597 | image_file_extensions_unique = set(image_file_extensions.split(' ')) | 1610 | image_file_extensions_unique = set(image_file_extensions.split(' ')) |
1598 | 1611 | ||
1599 | targets = self.internal_state['targets'] | 1612 | targets = self.internal_state['targets'] |
1613 | |||
1614 | # filter out anything which isn't an image target | ||
1600 | image_targets = [target for target in targets if target.is_image] | 1615 | image_targets = [target for target in targets if target.is_image] |
1616 | |||
1601 | for target in image_targets: | 1617 | for target in image_targets: |
1602 | # this is set to True if we find at least one file relating to | 1618 | # this is set to True if we find at least one file relating to |
1603 | # this target; if this remains False after the scan, we copy the | 1619 | # this target; if this remains False after the scan, we copy the |
@@ -1625,16 +1641,17 @@ class BuildInfoHelper(object): | |||
1625 | if os.path.isfile(image_license_manifest_path): | 1641 | if os.path.isfile(image_license_manifest_path): |
1626 | has_files = True | 1642 | has_files = True |
1627 | 1643 | ||
1628 | basenames = self._get_files_from_image_license( | 1644 | basenames = self._get_filenames_from_image_license( |
1629 | image_license_manifest_path) | 1645 | image_license_manifest_path) |
1630 | 1646 | ||
1631 | for basename in basenames: | 1647 | for basename in basenames: |
1632 | artifact_path = os.path.join(deploy_dir_image, basename) | 1648 | artifact_path = os.path.join(deploy_dir_image, basename) |
1633 | artifact_size = os.stat(artifact_path).st_size | 1649 | artifact_size = os.stat(artifact_path).st_size |
1634 | 1650 | ||
1635 | self.orm_wrapper.save_artifact_information_no_dedupe( | 1651 | # note that the artifact will only be saved against this |
1636 | self.internal_state['build'], artifact_path, | 1652 | # build if it hasn't been already |
1637 | artifact_size) | 1653 | self.orm_wrapper.save_target_artifact_file(target, |
1654 | artifact_path, artifact_size) | ||
1638 | 1655 | ||
1639 | # store the license manifest path on the target | 1656 | # store the license manifest path on the target |
1640 | # (this file is also created any time an image file is created) | 1657 | # (this file is also created any time an image file is created) |
@@ -1648,7 +1665,10 @@ class BuildInfoHelper(object): | |||
1648 | # (via real_image_name); note that we don't have to set | 1665 | # (via real_image_name); note that we don't have to set |
1649 | # has_files = True, as searching for the license manifest file | 1666 | # has_files = True, as searching for the license manifest file |
1650 | # will already have set it to true if at least one image file was | 1667 | # will already have set it to true if at least one image file was |
1651 | # produced | 1668 | # produced; note that the real_image_name includes BUILDNAME, which |
1669 | # in turn includes a timestamp; so if no files were produced for | ||
1670 | # this timestamp (i.e. the build reused existing image files already | ||
1671 | # in the directory), no files will be recorded against this target | ||
1652 | image_files = self._get_image_files(deploy_dir_image, | 1672 | image_files = self._get_image_files(deploy_dir_image, |
1653 | real_image_name, image_file_extensions_unique) | 1673 | real_image_name, image_file_extensions_unique) |
1654 | 1674 | ||
@@ -1657,11 +1677,18 @@ class BuildInfoHelper(object): | |||
1657 | target, image_file['path'], image_file['size']) | 1677 | target, image_file['path'], image_file['size']) |
1658 | 1678 | ||
1659 | if not has_files: | 1679 | if not has_files: |
1660 | # TODO copy artifact and image files from the | 1680 | # copy image files and build artifacts from the |
1661 | # most-recently-built Target with the same target + machine | 1681 | # most-recently-built Target with the |
1662 | # as this Target; also copy the license manifest path, | 1682 | # same target + machine as this Target; also copy the license |
1663 | # as that is treated differently | 1683 | # manifest path, as that is not treated as an artifact and needs |
1664 | pass | 1684 | # to be set separately |
1685 | most_recent = \ | ||
1686 | self.orm_wrapper.get_similar_target_with_image_files(target) | ||
1687 | |||
1688 | if most_recent: | ||
1689 | logger.info('image artifacts for target %s cloned from ' \ | ||
1690 | 'target %s' % (target.pk, most_recent.pk)) | ||
1691 | target.clone_artifacts_from(most_recent) | ||
1665 | 1692 | ||
1666 | def close(self, errorcode): | 1693 | def close(self, errorcode): |
1667 | if self.brbe is not None: | 1694 | if self.brbe is not None: |