Patchwork [3/4] oe.license: add is_included convenience function

login
register
mail settings
Submitter Christopher Larson
Date Jan. 10, 2012, 4:31 p.m.
Message ID <3e27bba7364827ad64c5aef71d66d6c9ba29d060.1326213043.git.chris_larson@mentor.com>
Download mbox | patch
Permalink /patch/18937/
State Accepted
Commit 7903433898b4683a1c09cc9a6a379421bc9bbd58
Headers show

Comments

Christopher Larson - Jan. 10, 2012, 4:31 p.m.
From: Christopher Larson <chris_larson@mentor.com>

Given a license string and whitelist and blacklist, determine if the
license string matches the whitelist and does not match the blacklist.

When encountering an OR, it prefers the side with the highest weight (more
included licenses). It then checks the inclusion of the flattened list of
licenses from there.

Returns a tuple holding the boolean state and a list of the applicable
licenses which were excluded (or None, if the state is True)

Examples:

    is_included, excluded = oe.license.is_included(licensestr, ['GPL*', 'LGPL*'])
    is_included, excluded = oe.license.is_included(licensestr, blacklist=['Proprietary', 'CLOSED'])

Signed-off-by: Christopher Larson <chris_larson@mentor.com>
---
 meta/classes/copyleft_compliance.bbclass |   23 +++---------------
 meta/lib/oe/license.py                   |   36 ++++++++++++++++++++++++++++++
 meta/lib/test.py                         |    3 ++
 3 files changed, 43 insertions(+), 19 deletions(-)
 create mode 100644 meta/lib/test.py

Patch

diff --git a/meta/classes/copyleft_compliance.bbclass b/meta/classes/copyleft_compliance.bbclass
index fd04638..6f058e0 100644
--- a/meta/classes/copyleft_compliance.bbclass
+++ b/meta/classes/copyleft_compliance.bbclass
@@ -46,32 +46,17 @@  def copyleft_should_include(d):
     include = oe.data.typed_value('COPYLEFT_LICENSE_INCLUDE', d)
     exclude = oe.data.typed_value('COPYLEFT_LICENSE_EXCLUDE', d)
 
-    def include_license(license):
-        if any(fnmatch(license, pattern) for pattern in exclude):
-            return False
-        if any(fnmatch(license, pattern) for pattern in include):
-            return True
-        return False
-
-    def choose_licenses(a, b):
-        """Select the left option in an OR if all its licenses are to be included"""
-        if all(include_license(lic) for lic in a):
-            return a
-        else:
-            return b
-
     try:
-        licenses = oe.license.flattened_licenses(d.getVar('LICENSE', True), choose_licenses)
+        is_included, excluded = oe.license.is_included(d.getVar('LICENSE', True), include, exclude)
     except oe.license.InvalidLicense as exc:
         bb.fatal('%s: %s' % (d.getVar('PF', True), exc))
     except SyntaxError as exc:
         bb.warn('%s: error when parsing the LICENSE variable: %s' % (d.getVar('P', True), exc))
     else:
-        excluded = filter(lambda lic: not include_license(lic), licenses)
-        if excluded:
-            return False, 'recipe has excluded licenses: %s' % ', '.join(excluded)
-        else:
+        if is_included:
             return True, None
+        else:
+            return False, 'recipe has excluded licenses: %s' % ', '.join(excluded)
 
 python do_prepare_copyleft_sources () {
     """Populate a tree of the recipe sources and emit patch series files"""
diff --git a/meta/lib/oe/license.py b/meta/lib/oe/license.py
index 7ab66e7..3543cfe 100644
--- a/meta/lib/oe/license.py
+++ b/meta/lib/oe/license.py
@@ -3,6 +3,7 @@ 
 
 import ast
 import re
+from fnmatch import fnmatchcase as fnmatch
 
 class InvalidLicense(StandardError):
     def __init__(self, license):
@@ -60,3 +61,38 @@  def flattened_licenses(licensestr, choose_licenses):
     flatten = FlattenVisitor(choose_licenses)
     flatten.visit_string(licensestr)
     return flatten.licenses
+
+def is_included(licensestr, whitelist=None, blacklist=None):
+    """Given a license string and whitelist and blacklist, determine if the
+    license string matches the whitelist and does not match the blacklist.
+
+    Returns a tuple holding the boolean state and a list of the applicable
+    licenses which were excluded (or None, if the state is True)
+    """
+
+    def include_license(license):
+        return (any(fnmatch(license, pattern) for pattern in whitelist) and not
+                any(fnmatch(license, pattern) for pattern in blacklist))
+
+    def choose_licenses(alpha, beta):
+        """Select the option in an OR which is the 'best' (has the most
+        included licenses)."""
+        alpha_weight = len(filter(include_license, alpha))
+        beta_weight = len(filter(include_license, beta))
+        if alpha_weight > beta_weight:
+            return alpha
+        else:
+            return beta
+
+    if not whitelist:
+        whitelist = ['*']
+
+    if not blacklist:
+        blacklist = []
+
+    licenses = flattened_licenses(licensestr, choose_licenses)
+    excluded = filter(lambda lic: not include_license(lic), licenses)
+    if excluded:
+        return False, excluded
+    else:
+        return True, None
diff --git a/meta/lib/test.py b/meta/lib/test.py
new file mode 100644
index 0000000..12f4d83
--- /dev/null
+++ b/meta/lib/test.py
@@ -0,0 +1,3 @@ 
+import oe.license
+
+print(oe.license.is_included('LGPLv2.1 | GPLv3', ['*'], []))