[OE-core] [PATCHv2 6/6] license.bbclass: Create image license manifest

Paul Eggleton paul.eggleton at linux.intel.com
Wed Nov 11 17:32:32 UTC 2015


On Tuesday 10 November 2015 08:52:22 Mariano Lopez wrote:
> On 11/10/2015 04:42 AM, Paul Eggleton wrote:
> > On Monday 09 November 2015 14:04:43 mariano.lopez at linux.intel.com wrote:
> >> From: Mariano Lopez <mariano.lopez at linux.intel.com>
> >> 
> >> This change adds the license_deployed_manifest function
> >> that will create the manifest for the packages deployed
> >> in the image but not installed in rootfs.
> > 
> > Again, not "in the image" but "next to the image". I'd suggest giving an
> > example or two here so that it's clear what's being referred to.
> > 
> >> This new function was added to ROOTFS_POSTPROCESS_COMMAND
> >> so it will run after every rootfs task. Because of this
> >> it could run few times for a single build and get different
> >> dependencies. Sometimes this dependencies won't include all
> >> the deployed packages, in order to avoid missing licenses a
> >> tmp file is create during the build and deleted after the
> >> build (LICENSE_TMP_JSON).
> >> 
> >> This change also modify the write_license_files because
> >> the image manifest is different from the root manifest.
> >> 
> >> [YOCTO #6772]
> >> 
> >> Signed-off-by: Mariano Lopez <mariano.lopez at linux.intel.com>
> >> ---
> >> 
> >>   meta/classes/license.bbclass | 78
> >> 
> >> +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73
> >> insertions(+), 5 deletions(-)
> >> 
> >> diff --git a/meta/classes/license.bbclass b/meta/classes/license.bbclass
> >> index 463dd54..fa8807e 100644
> >> --- a/meta/classes/license.bbclass
> >> +++ b/meta/classes/license.bbclass
> >> @@ -11,6 +11,7 @@ LICENSE_CREATE_PACKAGE[type] = "boolean"
> >> 
> >>   LICENSE_CREATE_PACKAGE ??= "0"
> >>   LICENSE_PACKAGE_SUFFIX ??= "-lic"
> >>   LICENSE_FILES_DIRECTORY ??= "${datadir}/licenses/"
> >> 
> >> +LICENSE_TMP_JSON ?= "${LICENSE_DIRECTORY}/deploy_packages.json"
> >> 
> >>   addtask populate_lic after do_patch before do_build
> >>   do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}"
> >> 
> >> @@ -49,6 +50,59 @@ python license_create_manifest() {
> >> 
> >>       write_license_files(d, rootfs_license_manifest, pkg_dic)
> >>   
> >>   }
> >> 
> >> +python license_deployed_manifest_task() {
> >> +    license_deployed_manifest(d)
> >> +}
> >> +
> >> +def license_deployed_manifest(d):
> >> +    """ Write the license manifest for the deployed packages.
> >> +        The deployed packages usually includes the bootloader
> >> +        and extra files to boot the target.
> >> +    """
> >> +    import json
> >> +
> >> +    packages = ""
> >> +    dep_dic = {}
> >> +    pkg_dic = {}
> >> +    info_dir = os.path.join(d.getVar("PKGDATA_DIR",True), "runtime")
> >> +
> >> +    # Sometimes the initramfs image is build and it doesn't have
> >> +    # the boot dependencies. In order to overcome this it is
> >> +    # necessary to get save previous dependencies found. This is
> >> +    # why the json_file is used (and deleted once the build is done)
> >> +    json_file = d.getVar("LICENSE_TMP_JSON", True)
> >> +    json_lock = bb.utils.lockfile("%s.lock" % json_file)
> >> +    if os.path.exists(json_file):
> >> +        with open(json_file) as f:
> >> +            pkg_dic = json.loads(f.read())
> >> +
> >> +    dep_dic = get_deployed_dependencies(d)
> >> +    for dep in dep_dic.keys():
> >> +        # At least one package of the deployed dependency is needed
> >> +        # to get the version.
> >> +        pkg = get_package_from_deployed(d, dep)
> >> +        if pkg and pkg not in pkg_dic.keys():
> >> +            data_file = os.path.join(info_dir, pkg)
> >> +            pkg_dic[pkg] = oe.packagedata.read_pkgdatafile(data_file)
> >> +            # It is necessary to mark this will be used for image
> >> manifest
> >> +            pkg_dic[pkg]["IMAGE_MANIFEST"] = True
> >> +            pkg_dic[pkg]["FILES"] = \
> >> +                    get_deployed_files(d, dep_dic[dep])
> >> +            if not "LICENSE" in pkg_dic[pkg].keys():
> >> +                pkg_lic = "LICENSE_" + pkg
> >> +                pkg_dic[pkg]["LICENSE"] = pkg_dic[pkg][pkg_lic]
> >> +
> >> +    with open(json_file, "w") as f:
> >> +        json.dump(pkg_dic, f, indent=4)
> >> +    bb.utils.unlockfile(json_lock)
> >> +
> >> +    # Because it might be called several times we lock the license file
> >> +    image_license_manifest = os.path.join(d.getVar('LICENSE_DIRECTORY',
> >> True), +            d.getVar('IMAGE_NAME', True),
> >> 'image_license.manifest')
> >> +    manifest_lock = bb.utils.lockfile("%s.lock" %
> >> image_license_manifest)
> >> +    write_license_files(d, image_license_manifest, pkg_dic)
> >> +    bb.utils.unlockfile(manifest_lock)
> >> +
> >> 
> >>   def get_deployed_dependencies(d):
> >>       """ Get all the deployed dependencies of an image """
> >> 
> >> @@ -154,6 +208,11 @@ def get_deployed_files(d, man_file):
> >>               dep_files = "%s %s" % (dep_files, os.path.basename(f))
> >>       
> >>       return dep_files
> >> 
> >> +python license_delete_tmp_files () {
> >> +    json_file = d.getVar("LICENSE_TMP_JSON", True)
> >> +    os.remove(json_file)
> >> +}
> >> +
> >> 
> >>   def write_license_files(d, license_manifest, pkg_dic):
> >>       import re
> >> 
> >> @@ -175,10 +234,18 @@ def write_license_files(d, license_manifest,
> >> pkg_dic): pkg_dic[pkg]["LICENSES"] = re.sub('  *', ' ',
> >> pkg_dic[pkg]["LICENSES"]) pkg_dic[pkg]["LICENSES"] =
> >> pkg_dic[pkg]["LICENSES"].split()
> >> 
> >> -            license_file.write("PACKAGE NAME: %s\n" % pkg)
> >> -            license_file.write("PACKAGE VERSION: %s\n" %
> >> pkg_dic[pkg]["PV"]) -            license_file.write("RECIPE NAME: %s\n" %
> >> pkg_dic[pkg]["PN"]) -            license_file.write("LICENSE: %s\n\n" %
> >> pkg_dic[pkg]["LICENSE"]) +            if not "IMAGE_MANIFEST" in
> >> pkg_dic[pkg]:
> >> +                # Rootfs manifest
> >> +                license_file.write("PACKAGE NAME: %s\n" % pkg)
> >> +                license_file.write("PACKAGE VERSION: %s\n" %
> >> pkg_dic[pkg]["PV"]) +                license_file.write("RECIPE NAME:
> >> %s\n"
> >> % pkg_dic[pkg]["PN"]) +                license_file.write("LICENSE:
> >> %s\n\n"
> >> % pkg_dic[pkg]["LICENSE"]) +            else:
> >> +                # Image manifest
> >> +                license_file.write("RECIPE NAME: %s\n" %
> >> pkg_dic[pkg]["PN"]) +                license_file.write("VERSION: %s\n" %
> >> pkg_dic[pkg]["PV"]) +                license_file.write("LICENSE: %s\n" %
> >> pkg_dic[pkg]["LICENSE"]) +               
> >> license_file.write("FILES:%s\n\n"
> >> % pkg_dic[pkg]["FILES"])
> >> 
> >>               # If the package doesn't contain any file, that is, its
> >>               size is
> >> 
> >> 0, the license # isn't relevant as far as the final image is concerned.
> >> So
> >> doing license check @@ -586,7 +653,8 @@ SSTATETASKS += "do_populate_lic"
> >> 
> >>   do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
> >>   do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
> >> 
> >> -ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest;
> >> license_create_manifest; " +ROOTFS_POSTPROCESS_COMMAND_prepend =
> >> "write_package_manifest; license_create_manifest;
> >> license_deployed_manifest_task; " +IMAGE_POSTPROCESS_COMMAND_prepend = "
> >> license_delete_tmp_files; "
> >> 
> >>   do_populate_lic_setscene[dirs] = "${LICSSTATEDIR}/${PN}"
> >>   do_populate_lic_setscene[cleandirs] = "${LICSSTATEDIR}"
> > 
> > A couple of things:
> > 
> > 1) Please take care to use the appropriate terminology. "package" has a
> > specific meaning; what we are dealing with here is files deployed directly
> > from recipes, packages aren't involved (or shouldn't be).
> 
> The terminology here is used because I reused the code to write rootfs
> manifest. I can change the terminology of this function or I can write a
> function just for the image manifest.

Understood, but I was referring more to how you describe things in the commit 
message and elsewhere in the code.

> > 2) You're looking into PKGDATA_DIR, as I mentioned in one of my other
> > replies I don't think this is right. The risk is that if a recipe doesn't
> > actually write out any packages, the manifest will be incomplete. We need
> > a different approach here where pkgdata isn't involved at all. IIRC my
> > earlier suggestion was to use what is written out by do_populate_lic,
> > i.e. tmp/deploy/licenses/ - if that isn't practical we can have that task
> > write out the LICENSE value to a separate file, and that will then work
> > for any recipe.
> 
> The use of PKGDATA_DIR is for the version of the deployed files, getting
> the license from here was just because it was practical. Is there
> another way to get the version without using PKGDATA_DIR?

In the context you're in, I'm not sure there is. However, I'm tempted to say 
if we're writing out LICENSE to a separate file during do_populate_lic, we 
might as well do the same with PV.

Cheers,
Paul


-- 

Paul Eggleton
Intel Open Source Technology Centre



More information about the Openembedded-core mailing list