Patchwork [1/1] license.bbclass: Splitting out licenses

login
register
mail settings
Submitter Elizabeth Flanagan
Date July 25, 2011, 11:24 p.m.
Message ID <CAPhnLPBkbaj6MzfnLKfkwKpDO4UwejH+cWa2V=4CCpv55CReaw@mail.gmail.com>
Download mbox | patch
Permalink /patch/8469/
State New, archived
Headers show

Comments

Elizabeth Flanagan - July 25, 2011, 11:24 p.m.
Adding a bit more functionality here:
1. Adding some more SPDX Maps to take care of + licenses
2. Strip out -native and -cross package license wrangling.
   If it doesn't go on the image, we shouldn't wrangle it.
3. Split out the license destination directory to a
   IMAGE_NAME time stamped dir in
   /tmp/deploy/licenses/${IMAGE_NAME}/<stamp>

I've removed the handler from my previous Pull as license
manifest needs more discussion and I don't want these
bug fixes to be held up by an added feature.

Signed-off-by: Beth Flanagan <elizabeth.flanagan@intel.com>
---
 meta/classes/license.bbclass |  140 ++++++++++++++++++++++++------------------
 1 files changed, 81 insertions(+), 59 deletions(-)

 do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}"
 do_populate_lic[cleandirs] = "${LICSSTATEDIR}"

@@ -27,6 +28,8 @@ do_populate_lic[cleandirs] = "${LICSSTATEDIR}"
 SPDXLICENSEMAP[GPL] = "GPL-1"
 SPDXLICENSEMAP[GPLv2] = "GPL-2"
 SPDXLICENSEMAP[GPLv3] = "GPL-3"
+SPDXLICENSEMAP[GPLv2+] = "GPL-2+"
+SPDXLICENSEMAP[GPLv3+] = "GPL-3+"

 #LGPL variations
 SPDXLICENSEMAP[LGPL] = "LGPL-2"
@@ -49,6 +52,9 @@ SPDXLICENSEMAP[openssl] = "Openssl"
 #Other variations
 SPDXLICENSEMAP[AFL2.1] = "AFL-2"
 SPDXLICENSEMAP[EPLv1.0] = "EPL-1"
+SPDXLICENSEMAP[zlib] = "Zlib"
+SPDXLICENSEMAP[EPLv1.0] = "EPL-1"
+

 python do_populate_lic() {
     """
@@ -64,13 +70,11 @@ python do_populate_lic() {
             ast.NodeVisitor.generic_visit(self, node)

         def visit_Str(self, node):
-            #
             # Until I figure out what to do with
-            # the two modifiers I support (or greater = +
-            # and "with exceptions" being *
+            # "with exceptions" (*)
             # we'll just strip out the modifier and put
             # the base license.
-            find_license(node.s.replace("+", "").replace("*", ""))
+            find_license(node.s.replace("*", ""))
             ast.NodeVisitor.generic_visit(self, node)

         def visit_BinOp(self, node):
@@ -86,14 +90,14 @@ python do_populate_lic() {
         try:
             bb.copyfile(os.path.join(source, file_name),
os.path.join(destination, file_name))
         except:
-            bb.warn("%s: No generic license file exists for: %s at
%s" % (pn, file_name, source))
+            bb.note("%s: No generic license file exists for: %s at
%s" % (pn, file_name, source))
             pass

     def link_license(source, destination, file_name):
         try:
             os.symlink(os.path.join(source, file_name),
os.path.join(destination, "generic_" + file_name))
         except:
-            bb.warn("%s: Could not symlink: %s at %s to %s at %s" %
(pn, file_name, source, file_name, destination))
+            bb.note("%s: Could not symlink: %s at %s to %s at %s" %
(pn, file_name, source, file_name, destination))
             pass

     def find_license(license_type):
@@ -111,72 +115,90 @@ python do_populate_lic() {
                 copy_license(generic_directory, gen_lic_dest,
spdx_generic)
                 link_license(gen_lic_dest, destdir, spdx_generic)
             else:
-                # And here is where we warn people that their
licenses are lousy
-                bb.warn("%s: No generic license file exists for: %s
at %s" % (pn, license_type, generic_directory))
-                bb.warn("%s: There is also no SPDXLICENSEMAP for this
license type: %s at %s" % (pn, license_type, generic_directory))
+                # And here is where we tell people that their
licenses are lousy
+                bb.note("%s: No generic license file exists for: %s
at %s" % (pn, license_type, generic_directory))
+                bb.note("%s: There is also no SPDXLICENSEMAP for this
license type: %s at %s" % (pn, license_type, generic_directory))
                 pass
         elif os.path.isfile(os.path.join(generic_directory, license_type)):
             copy_license(generic_directory, gen_lic_dest, license_type)
             link_license(gen_lic_dest, destdir, license_type)

-    # All the license types for the package
-    license_types = bb.data.getVar('LICENSE', d, True)
-    # All the license files for the package
-    lic_files = bb.data.getVar('LIC_FILES_CHKSUM', d, True)
-    pn = bb.data.getVar('PN', d, True)
-    # The base directory we wrangle licenses to
-    destdir = os.path.join(bb.data.getVar('LICSSTATEDIR', d, True), pn)
-    # The license files are located in S/LIC_FILE_CHECKSUM.
-    srcdir = bb.data.getVar('S', d, True)
-    # Directory we store the generic licenses as set in the distro
configuration
-    generic_directory = bb.data.getVar('COMMON_LICENSE_DIR', d, True)
-
     try:
-        bb.mkdirhier(destdir)
+        bb.mkdirhier(bb.data.getVar('LICENSE_DIRECTORY', d, True))
+    except:
+        pass
+    file = open(bb.data.getVar('BNFILE', d, True))
+    bn = file.readline()
+    file.close()
+    bb.data.setVar('IMAGE_LICENSE_DIRECTORY',
os.path.join(bb.data.getVar('LICENSE_DIRECTORY', d, True), bn), d)
+    try:
+        bb.mkdirhier(bb.data.getVar('IMAGE_LICENSE_DIRECTORY', d, True))
     except:
         pass

-    if not generic_directory:
-        raise bb.build.FuncFailed("COMMON_LICENSE_DIR is unset.
Please set this in your distro config")
-
-    if not lic_files:
-        # No recipe should have an invalid license file. This is checked else
-        # where, but let's be pedantic
-        bb.note(pn + ": Recipe file does not have license file information.")
-        return True
-
-    for url in lic_files.split():
-        (type, host, path, user, pswd, parm) = bb.decodeurl(url)
-        # We want the license file to be copied into the destination
-        srclicfile = os.path.join(srcdir, path)
-        ret = bb.copyfile(srclicfile, os.path.join(destdir,
os.path.basename(path)))
-        # If the copy didn't occur, something horrible went wrong and
we fail out
-        if ret is False or ret == 0:
-            bb.warn("%s could not be copied for some reason. It may
not exist. WARN for now." % srclicfile)
-
-    gen_lic_dest = os.path.join(bb.data.getVar('LICENSE_DIRECTORY',
d, True), "common-licenses")
-
-    clean_licenses = ""
-
-    for x in license_types.replace("(", " ( ").replace(")", " ) ").split():
-        if ((x != "(") and (x != ")") and (x != "&") and (x != "|")):
-            clean_licenses += "'" + x + "'"
-        else:
-            clean_licenses += " " + x + " "
-
-    # lstrip any possible indents, since ast needs python syntax.
-    node = ast.parse(clean_licenses.lstrip())
-    v = LicenseVisitor()
-    v.visit(node)
+    # Let's stop polluting the wrangled licenses with packages that
don't go on the image
+    if not ("-native" in bb.data.getVar('PN', d, True) ) and  not
("-cross" in bb.data.getVar('PN', d, True)):
+        # All the license types for the package
+        license_types = bb.data.getVar('LICENSE', d, True)
+        # All the license files for the package
+        lic_files = bb.data.getVar('LIC_FILES_CHKSUM', d, True)
+        pn = bb.data.getVar('PN', d, True)
+        # The base directory we wrangle licenses to
+        destdir = os.path.join(bb.data.getVar('LICSSTATEDIR', d, True), pn)
+        # The license files are located in S/LIC_FILE_CHECKSUM.
+        srcdir = bb.data.getVar('S', d, True)
+        # Directory we store the generic licenses as set in the
distro configuration
+        generic_directory = bb.data.getVar('COMMON_LICENSE_DIR', d, True)
+
+        try:
+           bb.mkdirhier(destdir)
+        except:
+            pass
+
+        if not generic_directory:
+            raise bb.build.FuncFailed("COMMON_LICENSE_DIR is unset.
Please set this in your distro config")
+
+        if not lic_files:
+            # No recipe should have an invalid license file. This is
checked else
+            # where, but let's be pedantic
+            bb.note(pn + ": Recipe file does not have license file
information.")
+            return True
+
+        for url in lic_files.split():
+            (type, host, path, user, pswd, parm) = bb.decodeurl(url)
+            # We want the license file to be copied into the destination
+            srclicfile = os.path.join(srcdir, path)
+            ret = bb.copyfile(srclicfile, os.path.join(destdir,
os.path.basename(path)))
+            # If the copy didn't occur, something horrible went wrong
and we fail out
+            if ret is False or ret == 0:
+                bb.warn("%s could not be copied for some reason. It
may not exist. WARN for now." % srclicfile)
+
+        gen_lic_dest =
os.path.join(bb.data.getVar('IMAGE_LICENSE_DIRECTORY', d, True),
"common-licenses")
+
+        clean_licenses = ""
+
+        for x in license_types.replace("(", " ( ").replace(")", " ) ").split():
+            if ((x != "(") and (x != ")") and (x != "&") and (x != "|")):
+                clean_licenses += "'" + x + "'"
+            else:
+                clean_licenses += " " + x + " "
+
+        # lstrip any possible indents, since ast needs python syntax.
+        node = ast.parse(clean_licenses.lstrip())
+        v = LicenseVisitor()
+        v.visit(node)
+    else:
+        shutil.rmtree(os.path.join(bb.data.getVar('LICSSTATEDIR', d,
True), bb.data.getVar('PN', d, True)))
 }

 SSTATETASKS += "do_populate_lic"
+
 do_populate_lic[sstate-name] = "populate-lic"
 do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
-do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
+do_populate_lic[sstate-outputdirs] = "${IMAGE_LICENSE_DIRECTORY}/"

 python do_populate_lic_setscene () {
-	sstate_setscene(d)
+    sstate_setscene(d)
 }
-addtask do_populate_lic_setscene

+addtask do_populate_lic_setscene
Richard Purdie - July 26, 2011, 2:57 p.m.
On Mon, 2011-07-25 at 16:24 -0700, Flanagan, Elizabeth wrote:
> Adding a bit more functionality here:
> 1. Adding some more SPDX Maps to take care of + licenses
> 2. Strip out -native and -cross package license wrangling.
>    If it doesn't go on the image, we shouldn't wrangle it.
> 3. Split out the license destination directory to a
>    IMAGE_NAME time stamped dir in
>    /tmp/deploy/licenses/${IMAGE_NAME}/<stamp>
> 
> I've removed the handler from my previous Pull as license
> manifest needs more discussion and I don't want these
> bug fixes to be held up by an added feature.

I obviously don't understand this code :/

What happens when I run "bitbake core-image-minimal core-image-sato",
i.e. when I build two images in one build?

I suspect this current approach is flawed and we actually need to
postprocess the installed package list after do_rootfs completes at
image generation time to build the *real* list based on the installed
packages?

This code is obviously still needed as it would provide the basis so the
code can get the licenses it needs to pull together...

Cheers,

Richard



> Signed-off-by: Beth Flanagan <elizabeth.flanagan@intel.com>
> ---
>  meta/classes/license.bbclass |  140 ++++++++++++++++++++++++------------------
>  1 files changed, 81 insertions(+), 59 deletions(-)
> 
> diff --git a/meta/classes/license.bbclass b/meta/classes/license.bbclass
> index 3f93bf5..7e440e5 100644
> --- a/meta/classes/license.bbclass
> +++ b/meta/classes/license.bbclass
> @@ -3,15 +3,16 @@
>  # TODO:
>  # - We should also enable the ability to put the generated license
> directory onto the
>  #  rootfs
> -# - Gather up more generic licenses
>  # - There is a real issue revolving around license naming standards.
> See license names
>  #  licenses.conf and compare them to the license names in the
> recipes. You'll see some
>  #  differences and that should be corrected.
> 
> -LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses"
> +LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses/"
> +IMAGE_LICENSE_DIRECTORY ?= ""
>  LICSSTATEDIR = "${WORKDIR}/license-destdir/"
> 
>  addtask populate_lic after do_patch before do_package
> +
>  do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}"
>  do_populate_lic[cleandirs] = "${LICSSTATEDIR}"
> 
> @@ -27,6 +28,8 @@ do_populate_lic[cleandirs] = "${LICSSTATEDIR}"
>  SPDXLICENSEMAP[GPL] = "GPL-1"
>  SPDXLICENSEMAP[GPLv2] = "GPL-2"
>  SPDXLICENSEMAP[GPLv3] = "GPL-3"
> +SPDXLICENSEMAP[GPLv2+] = "GPL-2+"
> +SPDXLICENSEMAP[GPLv3+] = "GPL-3+"
> 
>  #LGPL variations
>  SPDXLICENSEMAP[LGPL] = "LGPL-2"
> @@ -49,6 +52,9 @@ SPDXLICENSEMAP[openssl] = "Openssl"
>  #Other variations
>  SPDXLICENSEMAP[AFL2.1] = "AFL-2"
>  SPDXLICENSEMAP[EPLv1.0] = "EPL-1"
> +SPDXLICENSEMAP[zlib] = "Zlib"
> +SPDXLICENSEMAP[EPLv1.0] = "EPL-1"
> +
> 
>  python do_populate_lic() {
>      """
> @@ -64,13 +70,11 @@ python do_populate_lic() {
>              ast.NodeVisitor.generic_visit(self, node)
> 
>          def visit_Str(self, node):
> -            #
>              # Until I figure out what to do with
> -            # the two modifiers I support (or greater = +
> -            # and "with exceptions" being *
> +            # "with exceptions" (*)
>              # we'll just strip out the modifier and put
>              # the base license.
> -            find_license(node.s.replace("+", "").replace("*", ""))
> +            find_license(node.s.replace("*", ""))
>              ast.NodeVisitor.generic_visit(self, node)
> 
>          def visit_BinOp(self, node):
> @@ -86,14 +90,14 @@ python do_populate_lic() {
>          try:
>              bb.copyfile(os.path.join(source, file_name),
> os.path.join(destination, file_name))
>          except:
> -            bb.warn("%s: No generic license file exists for: %s at
> %s" % (pn, file_name, source))
> +            bb.note("%s: No generic license file exists for: %s at
> %s" % (pn, file_name, source))
>              pass
> 
>      def link_license(source, destination, file_name):
>          try:
>              os.symlink(os.path.join(source, file_name),
> os.path.join(destination, "generic_" + file_name))
>          except:
> -            bb.warn("%s: Could not symlink: %s at %s to %s at %s" %
> (pn, file_name, source, file_name, destination))
> +            bb.note("%s: Could not symlink: %s at %s to %s at %s" %
> (pn, file_name, source, file_name, destination))
>              pass
> 
>      def find_license(license_type):
> @@ -111,72 +115,90 @@ python do_populate_lic() {
>                  copy_license(generic_directory, gen_lic_dest,
> spdx_generic)
>                  link_license(gen_lic_dest, destdir, spdx_generic)
>              else:
> -                # And here is where we warn people that their
> licenses are lousy
> -                bb.warn("%s: No generic license file exists for: %s
> at %s" % (pn, license_type, generic_directory))
> -                bb.warn("%s: There is also no SPDXLICENSEMAP for this
> license type: %s at %s" % (pn, license_type, generic_directory))
> +                # And here is where we tell people that their
> licenses are lousy
> +                bb.note("%s: No generic license file exists for: %s
> at %s" % (pn, license_type, generic_directory))
> +                bb.note("%s: There is also no SPDXLICENSEMAP for this
> license type: %s at %s" % (pn, license_type, generic_directory))
>                  pass
>          elif os.path.isfile(os.path.join(generic_directory, license_type)):
>              copy_license(generic_directory, gen_lic_dest, license_type)
>              link_license(gen_lic_dest, destdir, license_type)
> 
> -    # All the license types for the package
> -    license_types = bb.data.getVar('LICENSE', d, True)
> -    # All the license files for the package
> -    lic_files = bb.data.getVar('LIC_FILES_CHKSUM', d, True)
> -    pn = bb.data.getVar('PN', d, True)
> -    # The base directory we wrangle licenses to
> -    destdir = os.path.join(bb.data.getVar('LICSSTATEDIR', d, True), pn)
> -    # The license files are located in S/LIC_FILE_CHECKSUM.
> -    srcdir = bb.data.getVar('S', d, True)
> -    # Directory we store the generic licenses as set in the distro
> configuration
> -    generic_directory = bb.data.getVar('COMMON_LICENSE_DIR', d, True)
> -
>      try:
> -        bb.mkdirhier(destdir)
> +        bb.mkdirhier(bb.data.getVar('LICENSE_DIRECTORY', d, True))
> +    except:
> +        pass
> +    file = open(bb.data.getVar('BNFILE', d, True))
> +    bn = file.readline()
> +    file.close()
> +    bb.data.setVar('IMAGE_LICENSE_DIRECTORY',
> os.path.join(bb.data.getVar('LICENSE_DIRECTORY', d, True), bn), d)
> +    try:
> +        bb.mkdirhier(bb.data.getVar('IMAGE_LICENSE_DIRECTORY', d, True))
>      except:
>          pass
> 
> -    if not generic_directory:
> -        raise bb.build.FuncFailed("COMMON_LICENSE_DIR is unset.
> Please set this in your distro config")
> -
> -    if not lic_files:
> -        # No recipe should have an invalid license file. This is checked else
> -        # where, but let's be pedantic
> -        bb.note(pn + ": Recipe file does not have license file information.")
> -        return True
> -
> -    for url in lic_files.split():
> -        (type, host, path, user, pswd, parm) = bb.decodeurl(url)
> -        # We want the license file to be copied into the destination
> -        srclicfile = os.path.join(srcdir, path)
> -        ret = bb.copyfile(srclicfile, os.path.join(destdir,
> os.path.basename(path)))
> -        # If the copy didn't occur, something horrible went wrong and
> we fail out
> -        if ret is False or ret == 0:
> -            bb.warn("%s could not be copied for some reason. It may
> not exist. WARN for now." % srclicfile)
> -
> -    gen_lic_dest = os.path.join(bb.data.getVar('LICENSE_DIRECTORY',
> d, True), "common-licenses")
> -
> -    clean_licenses = ""
> -
> -    for x in license_types.replace("(", " ( ").replace(")", " ) ").split():
> -        if ((x != "(") and (x != ")") and (x != "&") and (x != "|")):
> -            clean_licenses += "'" + x + "'"
> -        else:
> -            clean_licenses += " " + x + " "
> -
> -    # lstrip any possible indents, since ast needs python syntax.
> -    node = ast.parse(clean_licenses.lstrip())
> -    v = LicenseVisitor()
> -    v.visit(node)
> +    # Let's stop polluting the wrangled licenses with packages that
> don't go on the image
> +    if not ("-native" in bb.data.getVar('PN', d, True) ) and  not
> ("-cross" in bb.data.getVar('PN', d, True)):
> +        # All the license types for the package
> +        license_types = bb.data.getVar('LICENSE', d, True)
> +        # All the license files for the package
> +        lic_files = bb.data.getVar('LIC_FILES_CHKSUM', d, True)
> +        pn = bb.data.getVar('PN', d, True)
> +        # The base directory we wrangle licenses to
> +        destdir = os.path.join(bb.data.getVar('LICSSTATEDIR', d, True), pn)
> +        # The license files are located in S/LIC_FILE_CHECKSUM.
> +        srcdir = bb.data.getVar('S', d, True)
> +        # Directory we store the generic licenses as set in the
> distro configuration
> +        generic_directory = bb.data.getVar('COMMON_LICENSE_DIR', d, True)
> +
> +        try:
> +           bb.mkdirhier(destdir)
> +        except:
> +            pass
> +
> +        if not generic_directory:
> +            raise bb.build.FuncFailed("COMMON_LICENSE_DIR is unset.
> Please set this in your distro config")
> +
> +        if not lic_files:
> +            # No recipe should have an invalid license file. This is
> checked else
> +            # where, but let's be pedantic
> +            bb.note(pn + ": Recipe file does not have license file
> information.")
> +            return True
> +
> +        for url in lic_files.split():
> +            (type, host, path, user, pswd, parm) = bb.decodeurl(url)
> +            # We want the license file to be copied into the destination
> +            srclicfile = os.path.join(srcdir, path)
> +            ret = bb.copyfile(srclicfile, os.path.join(destdir,
> os.path.basename(path)))
> +            # If the copy didn't occur, something horrible went wrong
> and we fail out
> +            if ret is False or ret == 0:
> +                bb.warn("%s could not be copied for some reason. It
> may not exist. WARN for now." % srclicfile)
> +
> +        gen_lic_dest =
> os.path.join(bb.data.getVar('IMAGE_LICENSE_DIRECTORY', d, True),
> "common-licenses")
> +
> +        clean_licenses = ""
> +
> +        for x in license_types.replace("(", " ( ").replace(")", " ) ").split():
> +            if ((x != "(") and (x != ")") and (x != "&") and (x != "|")):
> +                clean_licenses += "'" + x + "'"
> +            else:
> +                clean_licenses += " " + x + " "
> +
> +        # lstrip any possible indents, since ast needs python syntax.
> +        node = ast.parse(clean_licenses.lstrip())
> +        v = LicenseVisitor()
> +        v.visit(node)
> +    else:
> +        shutil.rmtree(os.path.join(bb.data.getVar('LICSSTATEDIR', d,
> True), bb.data.getVar('PN', d, True)))
>  }
> 
>  SSTATETASKS += "do_populate_lic"
> +
>  do_populate_lic[sstate-name] = "populate-lic"
>  do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
> -do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
> +do_populate_lic[sstate-outputdirs] = "${IMAGE_LICENSE_DIRECTORY}/"
> 
>  python do_populate_lic_setscene () {
> -	sstate_setscene(d)
> +    sstate_setscene(d)
>  }
> -addtask do_populate_lic_setscene
> 
> +addtask do_populate_lic_setscene
Elizabeth Flanagan - July 26, 2011, 3:15 p.m.
On Tue, Jul 26, 2011 at 7:57 AM, Richard Purdie
<richard.purdie@linuxfoundation.org> wrote:
> On Mon, 2011-07-25 at 16:24 -0700, Flanagan, Elizabeth wrote:
>> Adding a bit more functionality here:
>> 1. Adding some more SPDX Maps to take care of + licenses
>> 2. Strip out -native and -cross package license wrangling.
>>    If it doesn't go on the image, we shouldn't wrangle it.
>> 3. Split out the license destination directory to a
>>    IMAGE_NAME time stamped dir in
>>    /tmp/deploy/licenses/${IMAGE_NAME}/<stamp>
>>
>> I've removed the handler from my previous Pull as license
>> manifest needs more discussion and I don't want these
>> bug fixes to be held up by an added feature.
>
> I obviously don't understand this code :/
>
> What happens when I run "bitbake core-image-minimal core-image-sato",
> i.e. when I build two images in one build?
>
> I suspect this current approach is flawed and we actually need to
> postprocess the installed package list after do_rootfs completes at
> image generation time to build the *real* list based on the installed
> packages?
>

Yes. I've found that this approach is definitely flawed. It works
great for a single image build. Outside of that it acts funny, like
you mentioned and can return incorrect results. I'm planning on
revisting this soon.

I'm suspecting that your suggested approach is the way it'll have to
be. Looking at what is generated by various runs and I see issues.

> This code is obviously still needed as it would provide the basis so the
> code can get the licenses it needs to pull together...

Yes, agreed.

>
> Cheers,
>
> Richard
>
>
>
>> Signed-off-by: Beth Flanagan <elizabeth.flanagan@intel.com>
>> ---
>>  meta/classes/license.bbclass |  140 ++++++++++++++++++++++++------------------
>>  1 files changed, 81 insertions(+), 59 deletions(-)
>>
>> diff --git a/meta/classes/license.bbclass b/meta/classes/license.bbclass
>> index 3f93bf5..7e440e5 100644
>> --- a/meta/classes/license.bbclass
>> +++ b/meta/classes/license.bbclass
>> @@ -3,15 +3,16 @@
>>  # TODO:
>>  # - We should also enable the ability to put the generated license
>> directory onto the
>>  #  rootfs
>> -# - Gather up more generic licenses
>>  # - There is a real issue revolving around license naming standards.
>> See license names
>>  #  licenses.conf and compare them to the license names in the
>> recipes. You'll see some
>>  #  differences and that should be corrected.
>>
>> -LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses"
>> +LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses/"
>> +IMAGE_LICENSE_DIRECTORY ?= ""
>>  LICSSTATEDIR = "${WORKDIR}/license-destdir/"
>>
>>  addtask populate_lic after do_patch before do_package
>> +
>>  do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}"
>>  do_populate_lic[cleandirs] = "${LICSSTATEDIR}"
>>
>> @@ -27,6 +28,8 @@ do_populate_lic[cleandirs] = "${LICSSTATEDIR}"
>>  SPDXLICENSEMAP[GPL] = "GPL-1"
>>  SPDXLICENSEMAP[GPLv2] = "GPL-2"
>>  SPDXLICENSEMAP[GPLv3] = "GPL-3"
>> +SPDXLICENSEMAP[GPLv2+] = "GPL-2+"
>> +SPDXLICENSEMAP[GPLv3+] = "GPL-3+"
>>
>>  #LGPL variations
>>  SPDXLICENSEMAP[LGPL] = "LGPL-2"
>> @@ -49,6 +52,9 @@ SPDXLICENSEMAP[openssl] = "Openssl"
>>  #Other variations
>>  SPDXLICENSEMAP[AFL2.1] = "AFL-2"
>>  SPDXLICENSEMAP[EPLv1.0] = "EPL-1"
>> +SPDXLICENSEMAP[zlib] = "Zlib"
>> +SPDXLICENSEMAP[EPLv1.0] = "EPL-1"
>> +
>>
>>  python do_populate_lic() {
>>      """
>> @@ -64,13 +70,11 @@ python do_populate_lic() {
>>              ast.NodeVisitor.generic_visit(self, node)
>>
>>          def visit_Str(self, node):
>> -            #
>>              # Until I figure out what to do with
>> -            # the two modifiers I support (or greater = +
>> -            # and "with exceptions" being *
>> +            # "with exceptions" (*)
>>              # we'll just strip out the modifier and put
>>              # the base license.
>> -            find_license(node.s.replace("+", "").replace("*", ""))
>> +            find_license(node.s.replace("*", ""))
>>              ast.NodeVisitor.generic_visit(self, node)
>>
>>          def visit_BinOp(self, node):
>> @@ -86,14 +90,14 @@ python do_populate_lic() {
>>          try:
>>              bb.copyfile(os.path.join(source, file_name),
>> os.path.join(destination, file_name))
>>          except:
>> -            bb.warn("%s: No generic license file exists for: %s at
>> %s" % (pn, file_name, source))
>> +            bb.note("%s: No generic license file exists for: %s at
>> %s" % (pn, file_name, source))
>>              pass
>>
>>      def link_license(source, destination, file_name):
>>          try:
>>              os.symlink(os.path.join(source, file_name),
>> os.path.join(destination, "generic_" + file_name))
>>          except:
>> -            bb.warn("%s: Could not symlink: %s at %s to %s at %s" %
>> (pn, file_name, source, file_name, destination))
>> +            bb.note("%s: Could not symlink: %s at %s to %s at %s" %
>> (pn, file_name, source, file_name, destination))
>>              pass
>>
>>      def find_license(license_type):
>> @@ -111,72 +115,90 @@ python do_populate_lic() {
>>                  copy_license(generic_directory, gen_lic_dest,
>> spdx_generic)
>>                  link_license(gen_lic_dest, destdir, spdx_generic)
>>              else:
>> -                # And here is where we warn people that their
>> licenses are lousy
>> -                bb.warn("%s: No generic license file exists for: %s
>> at %s" % (pn, license_type, generic_directory))
>> -                bb.warn("%s: There is also no SPDXLICENSEMAP for this
>> license type: %s at %s" % (pn, license_type, generic_directory))
>> +                # And here is where we tell people that their
>> licenses are lousy
>> +                bb.note("%s: No generic license file exists for: %s
>> at %s" % (pn, license_type, generic_directory))
>> +                bb.note("%s: There is also no SPDXLICENSEMAP for this
>> license type: %s at %s" % (pn, license_type, generic_directory))
>>                  pass
>>          elif os.path.isfile(os.path.join(generic_directory, license_type)):
>>              copy_license(generic_directory, gen_lic_dest, license_type)
>>              link_license(gen_lic_dest, destdir, license_type)
>>
>> -    # All the license types for the package
>> -    license_types = bb.data.getVar('LICENSE', d, True)
>> -    # All the license files for the package
>> -    lic_files = bb.data.getVar('LIC_FILES_CHKSUM', d, True)
>> -    pn = bb.data.getVar('PN', d, True)
>> -    # The base directory we wrangle licenses to
>> -    destdir = os.path.join(bb.data.getVar('LICSSTATEDIR', d, True), pn)
>> -    # The license files are located in S/LIC_FILE_CHECKSUM.
>> -    srcdir = bb.data.getVar('S', d, True)
>> -    # Directory we store the generic licenses as set in the distro
>> configuration
>> -    generic_directory = bb.data.getVar('COMMON_LICENSE_DIR', d, True)
>> -
>>      try:
>> -        bb.mkdirhier(destdir)
>> +        bb.mkdirhier(bb.data.getVar('LICENSE_DIRECTORY', d, True))
>> +    except:
>> +        pass
>> +    file = open(bb.data.getVar('BNFILE', d, True))
>> +    bn = file.readline()
>> +    file.close()
>> +    bb.data.setVar('IMAGE_LICENSE_DIRECTORY',
>> os.path.join(bb.data.getVar('LICENSE_DIRECTORY', d, True), bn), d)
>> +    try:
>> +        bb.mkdirhier(bb.data.getVar('IMAGE_LICENSE_DIRECTORY', d, True))
>>      except:
>>          pass
>>
>> -    if not generic_directory:
>> -        raise bb.build.FuncFailed("COMMON_LICENSE_DIR is unset.
>> Please set this in your distro config")
>> -
>> -    if not lic_files:
>> -        # No recipe should have an invalid license file. This is checked else
>> -        # where, but let's be pedantic
>> -        bb.note(pn + ": Recipe file does not have license file information.")
>> -        return True
>> -
>> -    for url in lic_files.split():
>> -        (type, host, path, user, pswd, parm) = bb.decodeurl(url)
>> -        # We want the license file to be copied into the destination
>> -        srclicfile = os.path.join(srcdir, path)
>> -        ret = bb.copyfile(srclicfile, os.path.join(destdir,
>> os.path.basename(path)))
>> -        # If the copy didn't occur, something horrible went wrong and
>> we fail out
>> -        if ret is False or ret == 0:
>> -            bb.warn("%s could not be copied for some reason. It may
>> not exist. WARN for now." % srclicfile)
>> -
>> -    gen_lic_dest = os.path.join(bb.data.getVar('LICENSE_DIRECTORY',
>> d, True), "common-licenses")
>> -
>> -    clean_licenses = ""
>> -
>> -    for x in license_types.replace("(", " ( ").replace(")", " ) ").split():
>> -        if ((x != "(") and (x != ")") and (x != "&") and (x != "|")):
>> -            clean_licenses += "'" + x + "'"
>> -        else:
>> -            clean_licenses += " " + x + " "
>> -
>> -    # lstrip any possible indents, since ast needs python syntax.
>> -    node = ast.parse(clean_licenses.lstrip())
>> -    v = LicenseVisitor()
>> -    v.visit(node)
>> +    # Let's stop polluting the wrangled licenses with packages that
>> don't go on the image
>> +    if not ("-native" in bb.data.getVar('PN', d, True) ) and  not
>> ("-cross" in bb.data.getVar('PN', d, True)):
>> +        # All the license types for the package
>> +        license_types = bb.data.getVar('LICENSE', d, True)
>> +        # All the license files for the package
>> +        lic_files = bb.data.getVar('LIC_FILES_CHKSUM', d, True)
>> +        pn = bb.data.getVar('PN', d, True)
>> +        # The base directory we wrangle licenses to
>> +        destdir = os.path.join(bb.data.getVar('LICSSTATEDIR', d, True), pn)
>> +        # The license files are located in S/LIC_FILE_CHECKSUM.
>> +        srcdir = bb.data.getVar('S', d, True)
>> +        # Directory we store the generic licenses as set in the
>> distro configuration
>> +        generic_directory = bb.data.getVar('COMMON_LICENSE_DIR', d, True)
>> +
>> +        try:
>> +           bb.mkdirhier(destdir)
>> +        except:
>> +            pass
>> +
>> +        if not generic_directory:
>> +            raise bb.build.FuncFailed("COMMON_LICENSE_DIR is unset.
>> Please set this in your distro config")
>> +
>> +        if not lic_files:
>> +            # No recipe should have an invalid license file. This is
>> checked else
>> +            # where, but let's be pedantic
>> +            bb.note(pn + ": Recipe file does not have license file
>> information.")
>> +            return True
>> +
>> +        for url in lic_files.split():
>> +            (type, host, path, user, pswd, parm) = bb.decodeurl(url)
>> +            # We want the license file to be copied into the destination
>> +            srclicfile = os.path.join(srcdir, path)
>> +            ret = bb.copyfile(srclicfile, os.path.join(destdir,
>> os.path.basename(path)))
>> +            # If the copy didn't occur, something horrible went wrong
>> and we fail out
>> +            if ret is False or ret == 0:
>> +                bb.warn("%s could not be copied for some reason. It
>> may not exist. WARN for now." % srclicfile)
>> +
>> +        gen_lic_dest =
>> os.path.join(bb.data.getVar('IMAGE_LICENSE_DIRECTORY', d, True),
>> "common-licenses")
>> +
>> +        clean_licenses = ""
>> +
>> +        for x in license_types.replace("(", " ( ").replace(")", " ) ").split():
>> +            if ((x != "(") and (x != ")") and (x != "&") and (x != "|")):
>> +                clean_licenses += "'" + x + "'"
>> +            else:
>> +                clean_licenses += " " + x + " "
>> +
>> +        # lstrip any possible indents, since ast needs python syntax.
>> +        node = ast.parse(clean_licenses.lstrip())
>> +        v = LicenseVisitor()
>> +        v.visit(node)
>> +    else:
>> +        shutil.rmtree(os.path.join(bb.data.getVar('LICSSTATEDIR', d,
>> True), bb.data.getVar('PN', d, True)))
>>  }
>>
>>  SSTATETASKS += "do_populate_lic"
>> +
>>  do_populate_lic[sstate-name] = "populate-lic"
>>  do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
>> -do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
>> +do_populate_lic[sstate-outputdirs] = "${IMAGE_LICENSE_DIRECTORY}/"
>>
>>  python do_populate_lic_setscene () {
>> -     sstate_setscene(d)
>> +    sstate_setscene(d)
>>  }
>> -addtask do_populate_lic_setscene
>>
>> +addtask do_populate_lic_setscene
>
>
>
> _______________________________________________
> Openembedded-core mailing list
> Openembedded-core@lists.openembedded.org
> http://lists.linuxtogo.org/cgi-bin/mailman/listinfo/openembedded-core
>
Richard Purdie - July 26, 2011, 11 p.m.
On Tue, 2011-07-26 at 08:15 -0700, Flanagan, Elizabeth wrote:
> On Tue, Jul 26, 2011 at 7:57 AM, Richard Purdie
> <richard.purdie@linuxfoundation.org> wrote:
> > On Mon, 2011-07-25 at 16:24 -0700, Flanagan, Elizabeth wrote:
> >> Adding a bit more functionality here:
> >> 1. Adding some more SPDX Maps to take care of + licenses
> >> 2. Strip out -native and -cross package license wrangling.
> >>    If it doesn't go on the image, we shouldn't wrangle it.
> >> 3. Split out the license destination directory to a
> >>    IMAGE_NAME time stamped dir in
> >>    /tmp/deploy/licenses/${IMAGE_NAME}/<stamp>
> >>
> >> I've removed the handler from my previous Pull as license
> >> manifest needs more discussion and I don't want these
> >> bug fixes to be held up by an added feature.
> >
> > I obviously don't understand this code :/
> >
> > What happens when I run "bitbake core-image-minimal core-image-sato",
> > i.e. when I build two images in one build?
> >
> > I suspect this current approach is flawed and we actually need to
> > postprocess the installed package list after do_rootfs completes at
> > image generation time to build the *real* list based on the installed
> > packages?
> >
> 
> Yes. I've found that this approach is definitely flawed. It works
> great for a single image build. Outside of that it acts funny, like
> you mentioned and can return incorrect results. I'm planning on
> revisting this soon.
> 
> I'm suspecting that your suggested approach is the way it'll have to
> be. Looking at what is generated by various runs and I see issues.
> 
> > This code is obviously still needed as it would provide the basis so the
> > code can get the licenses it needs to pull together...
> 
> Yes, agreed.

So with this in mind, where does that put this pull request? :)

Cheers,

Richard
Elizabeth Flanagan - July 27, 2011, 6:04 p.m.
On Tue, Jul 26, 2011 at 4:00 PM, Richard Purdie
<richard.purdie@linuxfoundation.org> wrote:
> On Tue, 2011-07-26 at 08:15 -0700, Flanagan, Elizabeth wrote:
>> On Tue, Jul 26, 2011 at 7:57 AM, Richard Purdie
>> <richard.purdie@linuxfoundation.org> wrote:
>> > On Mon, 2011-07-25 at 16:24 -0700, Flanagan, Elizabeth wrote:
>> >> Adding a bit more functionality here:
>> >> 1. Adding some more SPDX Maps to take care of + licenses
>> >> 2. Strip out -native and -cross package license wrangling.
>> >>    If it doesn't go on the image, we shouldn't wrangle it.
>> >> 3. Split out the license destination directory to a
>> >>    IMAGE_NAME time stamped dir in
>> >>    /tmp/deploy/licenses/${IMAGE_NAME}/<stamp>
>> >>
>> >> I've removed the handler from my previous Pull as license
>> >> manifest needs more discussion and I don't want these
>> >> bug fixes to be held up by an added feature.
>> >
>> > I obviously don't understand this code :/
>> >
>> > What happens when I run "bitbake core-image-minimal core-image-sato",
>> > i.e. when I build two images in one build?
>> >
>> > I suspect this current approach is flawed and we actually need to
>> > postprocess the installed package list after do_rootfs completes at
>> > image generation time to build the *real* list based on the installed
>> > packages?
>> >
>>
>> Yes. I've found that this approach is definitely flawed. It works
>> great for a single image build. Outside of that it acts funny, like
>> you mentioned and can return incorrect results. I'm planning on
>> revisting this soon.
>>
>> I'm suspecting that your suggested approach is the way it'll have to
>> be. Looking at what is generated by various runs and I see issues.
>>
>> > This code is obviously still needed as it would provide the basis so the
>> > code can get the licenses it needs to pull together...
>>
>> Yes, agreed.
>
> So with this in mind, where does that put this pull request? :)

I would still pull it. It does give us a basis to work on and splits
things out a bit.
When I get back from the conference this week, I'll fix it so that
it's a more reliable
in returning results. My guess is that I'll have to rip this all out
from being event driven
and do it, as you suggest, a postprocess right after do_rootfs

-b
Cliff Brake - July 29, 2011, 9:41 p.m.
On Wed, Jul 27, 2011 at 2:04 PM, Flanagan, Elizabeth
<elizabeth.flanagan@intel.com> wrote:

> I would still pull it. It does give us a basis to work on and splits
> things out a bit.
> When I get back from the conference this week, I'll fix it so that
> it's a more reliable
> in returning results. My guess is that I'll have to rip this all out
> from being event driven
> and do it, as you suggest, a postprocess right after do_rootfs

Khem took a pass at this (using the approach Richard suggested), so
you might want to consider building on what he did.  The testlab stuff
in OE is incredibly useful, and might be considered for OE core.

Thanks,
Cliff

http://patches.openembedded.org/patch/7587/
http://patches.openembedded.org/patch/7589/

to oe-core (these patches have been applied)

and

http://patches.openembedded.org/patch/7591/ (still being discussed)

to meta-openembedded

Then INHERIT += "testlab" in local.conf if you are using angstrom them
testlab is already inherited

bitbake console-image

and you should see a new file called installed-package-licenses.txt in
testlab directory along with other testlab results.

Patch

diff --git a/meta/classes/license.bbclass b/meta/classes/license.bbclass
index 3f93bf5..7e440e5 100644
--- a/meta/classes/license.bbclass
+++ b/meta/classes/license.bbclass
@@ -3,15 +3,16 @@ 
 # TODO:
 # - We should also enable the ability to put the generated license
directory onto the
 #  rootfs
-# - Gather up more generic licenses
 # - There is a real issue revolving around license naming standards.
See license names
 #  licenses.conf and compare them to the license names in the
recipes. You'll see some
 #  differences and that should be corrected.

-LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses"
+LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses/"
+IMAGE_LICENSE_DIRECTORY ?= ""
 LICSSTATEDIR = "${WORKDIR}/license-destdir/"

 addtask populate_lic after do_patch before do_package
+