xref: /openbmc/openbmc/poky/meta/classes-recipe/license_image.bbclass (revision 8460358c3d24c71d9d38fd126c745854a6301564)
192b42cb3SPatrick Williams#
292b42cb3SPatrick Williams# Copyright OpenEmbedded Contributors
392b42cb3SPatrick Williams#
492b42cb3SPatrick Williams# SPDX-License-Identifier: MIT
592b42cb3SPatrick Williams#
692b42cb3SPatrick Williams
792b42cb3SPatrick WilliamsROOTFS_LICENSE_DIR = "${IMAGE_ROOTFS}/usr/share/common-licenses"
892b42cb3SPatrick Williams
992b42cb3SPatrick Williams# This requires LICENSE_CREATE_PACKAGE=1 to work too
1092b42cb3SPatrick WilliamsCOMPLEMENTARY_GLOB[lic-pkgs] = "*-lic"
1192b42cb3SPatrick Williams
1292b42cb3SPatrick Williamspython() {
1392b42cb3SPatrick Williams    if not oe.data.typed_value('LICENSE_CREATE_PACKAGE', d):
1492b42cb3SPatrick Williams        features = set(oe.data.typed_value('IMAGE_FEATURES', d))
1592b42cb3SPatrick Williams        if 'lic-pkgs' in features:
1692b42cb3SPatrick Williams            bb.error("'lic-pkgs' in IMAGE_FEATURES but LICENSE_CREATE_PACKAGE not enabled to generate -lic packages")
1792b42cb3SPatrick Williams}
1892b42cb3SPatrick Williams
1992b42cb3SPatrick Williamspython write_package_manifest() {
2092b42cb3SPatrick Williams    # Get list of installed packages
21220dafdbSAndrew Geissler    license_image_dir = d.expand('${LICENSE_DIRECTORY}/${SSTATE_PKGARCH}/${IMAGE_NAME}')
2292b42cb3SPatrick Williams    bb.utils.mkdirhier(license_image_dir)
2392b42cb3SPatrick Williams    from oe.rootfs import image_list_installed_packages
2492b42cb3SPatrick Williams    from oe.utils import format_pkg_list
2592b42cb3SPatrick Williams
2692b42cb3SPatrick Williams    pkgs = image_list_installed_packages(d)
2792b42cb3SPatrick Williams    output = format_pkg_list(pkgs)
2892b42cb3SPatrick Williams    with open(os.path.join(license_image_dir, 'package.manifest'), "w+") as package_manifest:
2992b42cb3SPatrick Williams        package_manifest.write(output)
3092b42cb3SPatrick Williams}
3192b42cb3SPatrick Williams
3292b42cb3SPatrick Williamspython license_create_manifest() {
3392b42cb3SPatrick Williams    import oe.packagedata
3492b42cb3SPatrick Williams    from oe.rootfs import image_list_installed_packages
3592b42cb3SPatrick Williams
3692b42cb3SPatrick Williams    build_images_from_feeds = d.getVar('BUILD_IMAGES_FROM_FEEDS')
3792b42cb3SPatrick Williams    if build_images_from_feeds == "1":
3892b42cb3SPatrick Williams        return 0
3992b42cb3SPatrick Williams
4092b42cb3SPatrick Williams    pkg_dic = {}
4192b42cb3SPatrick Williams    for pkg in sorted(image_list_installed_packages(d)):
4292b42cb3SPatrick Williams        pkg_info = os.path.join(d.getVar('PKGDATA_DIR'),
4392b42cb3SPatrick Williams                                'runtime-reverse', pkg)
4492b42cb3SPatrick Williams        pkg_name = os.path.basename(os.readlink(pkg_info))
4592b42cb3SPatrick Williams
4692b42cb3SPatrick Williams        pkg_dic[pkg_name] = oe.packagedata.read_pkgdatafile(pkg_info)
4792b42cb3SPatrick Williams        if not "LICENSE" in pkg_dic[pkg_name].keys():
4892b42cb3SPatrick Williams            pkg_lic_name = "LICENSE:" + pkg_name
4992b42cb3SPatrick Williams            pkg_dic[pkg_name]["LICENSE"] = pkg_dic[pkg_name][pkg_lic_name]
5092b42cb3SPatrick Williams
5192b42cb3SPatrick Williams    rootfs_license_manifest = os.path.join(d.getVar('LICENSE_DIRECTORY'),
52220dafdbSAndrew Geissler                        d.getVar('SSTATE_PKGARCH'), d.getVar('IMAGE_NAME'), 'license.manifest')
5392b42cb3SPatrick Williams    write_license_files(d, rootfs_license_manifest, pkg_dic, rootfs=True)
5492b42cb3SPatrick Williams}
5592b42cb3SPatrick Williams
5692b42cb3SPatrick Williamsdef write_license_files(d, license_manifest, pkg_dic, rootfs=True):
5792b42cb3SPatrick Williams    import re
5892b42cb3SPatrick Williams    import stat
5992b42cb3SPatrick Williams
6092b42cb3SPatrick Williams    bad_licenses = (d.getVar("INCOMPATIBLE_LICENSE") or "").split()
61*8460358cSPatrick Williams    bad_licenses = oe.license.expand_wildcard_licenses(d, bad_licenses)
62220dafdbSAndrew Geissler    pkgarchs = d.getVar("SSTATE_ARCHS").split()
63220dafdbSAndrew Geissler    pkgarchs.reverse()
6492b42cb3SPatrick Williams
6592b42cb3SPatrick Williams    exceptions = (d.getVar("INCOMPATIBLE_LICENSE_EXCEPTIONS") or "").split()
6692b42cb3SPatrick Williams    with open(license_manifest, "w") as license_file:
6792b42cb3SPatrick Williams        for pkg in sorted(pkg_dic):
6892b42cb3SPatrick Williams            remaining_bad_licenses = oe.license.apply_pkg_license_exception(pkg, bad_licenses, exceptions)
69*8460358cSPatrick Williams            incompatible_licenses = oe.license.incompatible_pkg_license(d, remaining_bad_licenses, pkg_dic[pkg]["LICENSE"])
7092b42cb3SPatrick Williams            if incompatible_licenses:
7192b42cb3SPatrick Williams                bb.fatal("Package %s cannot be installed into the image because it has incompatible license(s): %s" %(pkg, ' '.join(incompatible_licenses)))
7292b42cb3SPatrick Williams            else:
73*8460358cSPatrick Williams                incompatible_licenses = oe.license.incompatible_pkg_license(d, bad_licenses, pkg_dic[pkg]["LICENSE"])
7492b42cb3SPatrick Williams                if incompatible_licenses:
75*8460358cSPatrick Williams                    oe.qa.handle_error('license-exception', "Including %s with incompatible license(s) %s into the image, because it has been allowed by exception list." %(pkg, ' '.join(incompatible_licenses)), d)
7692b42cb3SPatrick Williams            try:
7792b42cb3SPatrick Williams                (pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \
7892b42cb3SPatrick Williams                    oe.license.manifest_licenses(pkg_dic[pkg]["LICENSE"],
79*8460358cSPatrick Williams                    remaining_bad_licenses, oe.license.canonical_license, d)
8092b42cb3SPatrick Williams            except oe.license.LicenseError as exc:
8192b42cb3SPatrick Williams                bb.fatal('%s: %s' % (d.getVar('P'), exc))
8292b42cb3SPatrick Williams
8392b42cb3SPatrick Williams            if not "IMAGE_MANIFEST" in pkg_dic[pkg]:
8492b42cb3SPatrick Williams                # Rootfs manifest
8592b42cb3SPatrick Williams                license_file.write("PACKAGE NAME: %s\n" % pkg)
8692b42cb3SPatrick Williams                license_file.write("PACKAGE VERSION: %s\n" % pkg_dic[pkg]["PV"])
8792b42cb3SPatrick Williams                license_file.write("RECIPE NAME: %s\n" % pkg_dic[pkg]["PN"])
8892b42cb3SPatrick Williams                license_file.write("LICENSE: %s\n\n" % pkg_dic[pkg]["LICENSE"])
8992b42cb3SPatrick Williams
9092b42cb3SPatrick Williams                # If the package doesn't contain any file, that is, its size is 0, the license
9192b42cb3SPatrick Williams                # isn't relevant as far as the final image is concerned. So doing license check
9292b42cb3SPatrick Williams                # doesn't make much sense, skip it.
9392b42cb3SPatrick Williams                if pkg_dic[pkg]["PKGSIZE:%s" % pkg] == "0":
9492b42cb3SPatrick Williams                    continue
9592b42cb3SPatrick Williams            else:
9692b42cb3SPatrick Williams                # Image manifest
9792b42cb3SPatrick Williams                license_file.write("RECIPE NAME: %s\n" % pkg_dic[pkg]["PN"])
9892b42cb3SPatrick Williams                license_file.write("VERSION: %s\n" % pkg_dic[pkg]["PV"])
9992b42cb3SPatrick Williams                license_file.write("LICENSE: %s\n" % pkg_dic[pkg]["LICENSE"])
10092b42cb3SPatrick Williams                license_file.write("FILES: %s\n\n" % pkg_dic[pkg]["FILES"])
10192b42cb3SPatrick Williams
10292b42cb3SPatrick Williams            for lic in pkg_dic[pkg]["LICENSES"]:
103220dafdbSAndrew Geissler                for pkgarch in pkgarchs:
10492b42cb3SPatrick Williams                    lic_file = os.path.join(d.getVar('LICENSE_DIRECTORY'),
105220dafdbSAndrew Geissler                                            pkgarch,
10692b42cb3SPatrick Williams                                            pkg_dic[pkg]["PN"], "generic_%s" %
10792b42cb3SPatrick Williams                                            re.sub(r'\+', '', lic))
108220dafdbSAndrew Geissler                    if os.path.exists(lic_file):
109220dafdbSAndrew Geissler                        break
11092b42cb3SPatrick Williams                # add explicity avoid of CLOSED license because isn't generic
11192b42cb3SPatrick Williams                if lic == "CLOSED":
11292b42cb3SPatrick Williams                   continue
11392b42cb3SPatrick Williams
11492b42cb3SPatrick Williams                if not os.path.exists(lic_file):
11592b42cb3SPatrick Williams                    oe.qa.handle_error('license-file-missing',
11692b42cb3SPatrick Williams                                       "The license listed %s was not in the "\
11792b42cb3SPatrick Williams                                       "licenses collected for recipe %s"
11892b42cb3SPatrick Williams                                       % (lic, pkg_dic[pkg]["PN"]), d)
11992b42cb3SPatrick Williams    oe.qa.exit_if_errors(d)
12092b42cb3SPatrick Williams
12192b42cb3SPatrick Williams    # Two options here:
12292b42cb3SPatrick Williams    # - Just copy the manifest
12392b42cb3SPatrick Williams    # - Copy the manifest and the license directories
12492b42cb3SPatrick Williams    # With both options set we see a .5 M increase in core-image-minimal
12592b42cb3SPatrick Williams    copy_lic_manifest = d.getVar('COPY_LIC_MANIFEST')
12692b42cb3SPatrick Williams    copy_lic_dirs = d.getVar('COPY_LIC_DIRS')
12792b42cb3SPatrick Williams    if rootfs and copy_lic_manifest == "1":
12892b42cb3SPatrick Williams        rootfs_license_dir = d.getVar('ROOTFS_LICENSE_DIR')
12992b42cb3SPatrick Williams        bb.utils.mkdirhier(rootfs_license_dir)
13092b42cb3SPatrick Williams        rootfs_license_manifest = os.path.join(rootfs_license_dir,
13192b42cb3SPatrick Williams                os.path.split(license_manifest)[1])
13292b42cb3SPatrick Williams        if not os.path.exists(rootfs_license_manifest):
13392b42cb3SPatrick Williams            oe.path.copyhardlink(license_manifest, rootfs_license_manifest)
13492b42cb3SPatrick Williams
13592b42cb3SPatrick Williams        if copy_lic_dirs == "1":
13692b42cb3SPatrick Williams            for pkg in sorted(pkg_dic):
13792b42cb3SPatrick Williams                pkg_rootfs_license_dir = os.path.join(rootfs_license_dir, pkg)
13892b42cb3SPatrick Williams                bb.utils.mkdirhier(pkg_rootfs_license_dir)
139220dafdbSAndrew Geissler                for pkgarch in pkgarchs:
14092b42cb3SPatrick Williams                    pkg_license_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
141220dafdbSAndrew Geissler                                                   pkgarch, pkg_dic[pkg]["PN"])
142220dafdbSAndrew Geissler                    if os.path.exists(pkg_license_dir):
143220dafdbSAndrew Geissler                        break
144220dafdbSAndrew Geissler                if not os.path.exists(pkg_license_dir ):
145220dafdbSAndrew Geissler                    bb.fatal("Couldn't find license information for dependency %s" % pkg)
14692b42cb3SPatrick Williams
147*8460358cSPatrick Williams                pkg_manifest_licenses = [oe.license.canonical_license(d, lic) \
14892b42cb3SPatrick Williams                        for lic in pkg_dic[pkg]["LICENSES"]]
14992b42cb3SPatrick Williams
15092b42cb3SPatrick Williams                licenses = os.listdir(pkg_license_dir)
15192b42cb3SPatrick Williams                for lic in licenses:
15292b42cb3SPatrick Williams                    pkg_license = os.path.join(pkg_license_dir, lic)
15392b42cb3SPatrick Williams                    pkg_rootfs_license = os.path.join(pkg_rootfs_license_dir, lic)
15492b42cb3SPatrick Williams
15592b42cb3SPatrick Williams                    if re.match(r"^generic_.*$", lic):
156*8460358cSPatrick Williams                        generic_lic = oe.license.canonical_license(d,
15792b42cb3SPatrick Williams                                re.search(r"^generic_(.*)$", lic).group(1))
15892b42cb3SPatrick Williams
15992b42cb3SPatrick Williams                        # Do not copy generic license into package if isn't
16092b42cb3SPatrick Williams                        # declared into LICENSES of the package.
16192b42cb3SPatrick Williams                        if not re.sub(r'\+$', '', generic_lic) in \
16292b42cb3SPatrick Williams                                [re.sub(r'\+', '', lic) for lic in \
16392b42cb3SPatrick Williams                                 pkg_manifest_licenses]:
16492b42cb3SPatrick Williams                            continue
16592b42cb3SPatrick Williams
16692b42cb3SPatrick Williams                        if oe.license.license_ok(generic_lic,
16792b42cb3SPatrick Williams                                bad_licenses) == False:
16892b42cb3SPatrick Williams                            continue
16992b42cb3SPatrick Williams
17092b42cb3SPatrick Williams                        # Make sure we use only canonical name for the license file
17192b42cb3SPatrick Williams                        generic_lic_file = "generic_%s" % generic_lic
17292b42cb3SPatrick Williams                        rootfs_license = os.path.join(rootfs_license_dir, generic_lic_file)
17392b42cb3SPatrick Williams                        if not os.path.exists(rootfs_license):
17492b42cb3SPatrick Williams                            oe.path.copyhardlink(pkg_license, rootfs_license)
17592b42cb3SPatrick Williams
17692b42cb3SPatrick Williams                        if not os.path.exists(pkg_rootfs_license):
17792b42cb3SPatrick Williams                            os.symlink(os.path.join('..', generic_lic_file), pkg_rootfs_license)
17892b42cb3SPatrick Williams                    else:
179*8460358cSPatrick Williams                        if (oe.license.license_ok(oe.license.canonical_license(d,
18092b42cb3SPatrick Williams                                lic), bad_licenses) == False or
18192b42cb3SPatrick Williams                                os.path.exists(pkg_rootfs_license)):
18292b42cb3SPatrick Williams                            continue
18392b42cb3SPatrick Williams
18492b42cb3SPatrick Williams                        oe.path.copyhardlink(pkg_license, pkg_rootfs_license)
18592b42cb3SPatrick Williams            # Fixup file ownership and permissions
18692b42cb3SPatrick Williams            for walkroot, dirs, files in os.walk(rootfs_license_dir):
18792b42cb3SPatrick Williams                for f in files:
18892b42cb3SPatrick Williams                    p = os.path.join(walkroot, f)
18992b42cb3SPatrick Williams                    os.lchown(p, 0, 0)
19092b42cb3SPatrick Williams                    if not os.path.islink(p):
19192b42cb3SPatrick Williams                        os.chmod(p, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
19292b42cb3SPatrick Williams                for dir in dirs:
19392b42cb3SPatrick Williams                    p = os.path.join(walkroot, dir)
19492b42cb3SPatrick Williams                    os.lchown(p, 0, 0)
19592b42cb3SPatrick Williams                    os.chmod(p, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
19692b42cb3SPatrick Williams
197220dafdbSAndrew Geisslerwrite_license_files[vardepsexclude] = "SSTATE_ARCHS"
19892b42cb3SPatrick Williams
19992b42cb3SPatrick Williamsdef license_deployed_manifest(d):
20092b42cb3SPatrick Williams    """
20192b42cb3SPatrick Williams    Write the license manifest for the deployed recipes.
20292b42cb3SPatrick Williams    The deployed recipes usually includes the bootloader
20392b42cb3SPatrick Williams    and extra files to boot the target.
20492b42cb3SPatrick Williams    """
20592b42cb3SPatrick Williams
20692b42cb3SPatrick Williams    dep_dic = {}
20792b42cb3SPatrick Williams    man_dic = {}
20892b42cb3SPatrick Williams    lic_dir = d.getVar("LICENSE_DIRECTORY")
209220dafdbSAndrew Geissler    pkgarchs = d.getVar("SSTATE_ARCHS").split()
210220dafdbSAndrew Geissler    pkgarchs.reverse()
21192b42cb3SPatrick Williams
21292b42cb3SPatrick Williams    dep_dic = get_deployed_dependencies(d)
21392b42cb3SPatrick Williams    for dep in dep_dic.keys():
21492b42cb3SPatrick Williams        man_dic[dep] = {}
21592b42cb3SPatrick Williams        # It is necessary to mark this will be used for image manifest
21692b42cb3SPatrick Williams        man_dic[dep]["IMAGE_MANIFEST"] = True
21792b42cb3SPatrick Williams        man_dic[dep]["PN"] = dep
21892b42cb3SPatrick Williams        man_dic[dep]["FILES"] = \
21992b42cb3SPatrick Williams            " ".join(get_deployed_files(dep_dic[dep]))
220220dafdbSAndrew Geissler
221220dafdbSAndrew Geissler        for pkgarch in pkgarchs:
222220dafdbSAndrew Geissler            licfile = os.path.join(lic_dir, pkgarch, dep, "recipeinfo")
223220dafdbSAndrew Geissler            if os.path.exists(licfile):
224220dafdbSAndrew Geissler                break
225220dafdbSAndrew Geissler        if not os.path.exists(licfile):
226220dafdbSAndrew Geissler            bb.fatal("Couldn't find license information for dependency %s" % dep)
227220dafdbSAndrew Geissler        with open(licfile, "r") as f:
22892b42cb3SPatrick Williams            for line in f.readlines():
22992b42cb3SPatrick Williams                key,val = line.split(": ", 1)
23092b42cb3SPatrick Williams                man_dic[dep][key] = val[:-1]
23192b42cb3SPatrick Williams
232220dafdbSAndrew Geissler    lic_manifest_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'), d.getVar('SSTATE_PKGARCH'),
23392b42cb3SPatrick Williams                                    d.getVar('IMAGE_NAME'))
23492b42cb3SPatrick Williams    bb.utils.mkdirhier(lic_manifest_dir)
23592b42cb3SPatrick Williams    image_license_manifest = os.path.join(lic_manifest_dir, 'image_license.manifest')
23692b42cb3SPatrick Williams    write_license_files(d, image_license_manifest, man_dic, rootfs=False)
23792b42cb3SPatrick Williams
23892b42cb3SPatrick Williams    link_name = d.getVar('IMAGE_LINK_NAME')
23992b42cb3SPatrick Williams    if link_name:
240220dafdbSAndrew Geissler        lic_manifest_symlink_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'), d.getVar('SSTATE_PKGARCH'),
24192b42cb3SPatrick Williams                                    link_name)
24292b42cb3SPatrick Williams        # remove old symlink
24392b42cb3SPatrick Williams        if os.path.islink(lic_manifest_symlink_dir):
24492b42cb3SPatrick Williams            os.unlink(lic_manifest_symlink_dir)
24592b42cb3SPatrick Williams
24692b42cb3SPatrick Williams        # create the image dir symlink
24792b42cb3SPatrick Williams        if lic_manifest_dir != lic_manifest_symlink_dir:
24892b42cb3SPatrick Williams            os.symlink(lic_manifest_dir, lic_manifest_symlink_dir)
24992b42cb3SPatrick Williams
250220dafdbSAndrew Geisslerlicense_deployed_manifest[vardepsexclude] = "SSTATE_ARCHS"
251220dafdbSAndrew Geissler
25292b42cb3SPatrick Williamsdef get_deployed_dependencies(d):
25392b42cb3SPatrick Williams    """
25492b42cb3SPatrick Williams    Get all the deployed dependencies of an image
25592b42cb3SPatrick Williams    """
25692b42cb3SPatrick Williams
25792b42cb3SPatrick Williams    deploy = {}
25892b42cb3SPatrick Williams    # Get all the dependencies for the current task (rootfs).
25992b42cb3SPatrick Williams    taskdata = d.getVar("BB_TASKDEPDATA", False)
260864cc43bSPatrick Williams    pn = d.getVar("PN")
26192b42cb3SPatrick Williams    depends = list(set([dep[0] for dep
26292b42cb3SPatrick Williams                    in list(taskdata.values())
26392b42cb3SPatrick Williams                    if not dep[0].endswith("-native") and not dep[0] == pn]))
26492b42cb3SPatrick Williams
26592b42cb3SPatrick Williams    # To verify what was deployed it checks the rootfs dependencies against
26692b42cb3SPatrick Williams    # the SSTATE_MANIFESTS for "deploy" task.
26792b42cb3SPatrick Williams    # The manifest file name contains the arch. Because we are not running
26892b42cb3SPatrick Williams    # in the recipe context it is necessary to check every arch used.
26992b42cb3SPatrick Williams    sstate_manifest_dir = d.getVar("SSTATE_MANIFESTS")
27092b42cb3SPatrick Williams    archs = list(set(d.getVar("SSTATE_ARCHS").split()))
27192b42cb3SPatrick Williams    for dep in depends:
27292b42cb3SPatrick Williams        for arch in archs:
27392b42cb3SPatrick Williams            sstate_manifest_file = os.path.join(sstate_manifest_dir,
27492b42cb3SPatrick Williams                    "manifest-%s-%s.deploy" % (arch, dep))
27592b42cb3SPatrick Williams            if os.path.exists(sstate_manifest_file):
27692b42cb3SPatrick Williams                deploy[dep] = sstate_manifest_file
27792b42cb3SPatrick Williams                break
27892b42cb3SPatrick Williams
27992b42cb3SPatrick Williams    return deploy
280220dafdbSAndrew Geisslerget_deployed_dependencies[vardepsexclude] = "BB_TASKDEPDATA SSTATE_ARCHS"
28192b42cb3SPatrick Williams
28292b42cb3SPatrick Williamsdef get_deployed_files(man_file):
28392b42cb3SPatrick Williams    """
28492b42cb3SPatrick Williams    Get the files deployed from the sstate manifest
28592b42cb3SPatrick Williams    """
28692b42cb3SPatrick Williams
28792b42cb3SPatrick Williams    dep_files = []
28892b42cb3SPatrick Williams    excluded_files = []
28992b42cb3SPatrick Williams    with open(man_file, "r") as manifest:
29092b42cb3SPatrick Williams        all_files = manifest.read()
29192b42cb3SPatrick Williams    for f in all_files.splitlines():
29292b42cb3SPatrick Williams        if ((not (os.path.islink(f) or os.path.isdir(f))) and
29392b42cb3SPatrick Williams                not os.path.basename(f) in excluded_files):
29492b42cb3SPatrick Williams            dep_files.append(os.path.basename(f))
29592b42cb3SPatrick Williams    return dep_files
29692b42cb3SPatrick Williams
2975082cc7fSAndrew GeisslerROOTFS_POSTPROCESS_COMMAND:prepend = "write_package_manifest license_create_manifest "
29892b42cb3SPatrick Williamsdo_rootfs[recrdeptask] += "do_populate_lic"
29992b42cb3SPatrick Williams
30092b42cb3SPatrick Williamspython do_populate_lic_deploy() {
30192b42cb3SPatrick Williams    license_deployed_manifest(d)
30292b42cb3SPatrick Williams    oe.qa.exit_if_errors(d)
30392b42cb3SPatrick Williams}
30492b42cb3SPatrick Williams
30592b42cb3SPatrick Williamsaddtask populate_lic_deploy before do_build after do_image_complete
30692b42cb3SPatrick Williamsdo_populate_lic_deploy[recrdeptask] += "do_populate_lic do_deploy"
30792b42cb3SPatrick Williams
30892b42cb3SPatrick Williamspython license_qa_dead_symlink() {
30992b42cb3SPatrick Williams    import os
31092b42cb3SPatrick Williams
31192b42cb3SPatrick Williams    for root, dirs, files in os.walk(d.getVar('ROOTFS_LICENSE_DIR')):
31292b42cb3SPatrick Williams        for file in files:
31392b42cb3SPatrick Williams            full_path = root + "/" + file
31492b42cb3SPatrick Williams            if os.path.islink(full_path) and not os.path.exists(full_path):
31592b42cb3SPatrick Williams                bb.error("broken symlink: " + full_path)
31692b42cb3SPatrick Williams}
31792b42cb3SPatrick WilliamsIMAGE_QA_COMMANDS += "license_qa_dead_symlink"
318