[gnome-continuous-yocto/gnomeostree-3.28-rocko: 7969/8267] license.py: Correct selection of licenses in is_included()



commit 16f1a14f83353b809650ce5fe50b35e38b6c6d7e
Author: Peter Kjellerstedt <peter kjellerstedt axis com>
Date:   Fri Sep 29 17:52:34 2017 +0200

    license.py: Correct selection of licenses in is_included()
    
    When faced with multiple sets of licenses combined with | (OR), it was
    possible for oe.license.is_included() to choose a set of licenses with
    a blacklisted license and then report failure, even if choosing
    another set of licenses would have resulted in a successful
    result. This happened when the chosen set still contained more
    whitelisted licenses than the other set.
    
    This change makes sure a set with any blacklisted license is always
    considered with a lower weight than a set with only whitelisted
    licenses.
    
    Example: Faced with the license string "GPL-3.0 & GPL-2.0 & LGPL-2.1 |
    Proprietary" and with "GPL-3.0" being blacklisted, the old code would
    report a failure since "GPL-3.0 & GPL-2.0 & LGPL-2.1" still contains
    more whitelisted licenses than "Proprietary" does.
    
    This change also adds a unit test for oe.license.is_included().
    
    (From OE-Core rev: 312b4d6175e189852c0787ca2fe99b99ce92d1bd)
    
    Signed-off-by: Peter Kjellerstedt <peter kjellerstedt axis com>
    Signed-off-by: Ross Burton <ross burton intel com>
    Signed-off-by: Richard Purdie <richard purdie linuxfoundation org>

 meta/lib/oe/license.py                        |   18 ++++++++++----
 meta/lib/oeqa/selftest/cases/oelib/license.py |   31 +++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 5 deletions(-)
---
diff --git a/meta/lib/oe/license.py b/meta/lib/oe/license.py
index 8d2fd17..ca385d5 100644
--- a/meta/lib/oe/license.py
+++ b/meta/lib/oe/license.py
@@ -106,7 +106,8 @@ def is_included(licensestr, whitelist=None, blacklist=None):
     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)
+    licenses that were excluded if state is False, or the licenses that were
+    included if the state is True.
     """
 
     def include_license(license):
@@ -117,10 +118,17 @@ def is_included(licensestr, whitelist=None, blacklist=None):
 
     def choose_licenses(alpha, beta):
         """Select the option in an OR which is the 'best' (has the most
-        included licenses)."""
-        alpha_weight = len(list(filter(include_license, alpha)))
-        beta_weight = len(list(filter(include_license, beta)))
-        if alpha_weight > beta_weight:
+        included licenses and no excluded licenses)."""
+        # The factor 1000 below is arbitrary, just expected to be much larger
+        # that the number of licenses actually specified. That way the weight
+        # will be negative if the list of licenses contains an excluded license,
+        # but still gives a higher weight to the list with the most included
+        # licenses.
+        alpha_weight = (len(list(filter(include_license, alpha))) -
+                        1000 * (len(list(filter(exclude_license, alpha))) > 0))
+        beta_weight = (len(list(filter(include_license, beta))) -
+                       1000 * (len(list(filter(exclude_license, beta))) > 0))
+        if alpha_weight >= beta_weight:
             return alpha
         else:
             return beta
diff --git a/meta/lib/oeqa/selftest/cases/oelib/license.py b/meta/lib/oeqa/selftest/cases/oelib/license.py
index bfd9ed9..d7f91fb 100644
--- a/meta/lib/oeqa/selftest/cases/oelib/license.py
+++ b/meta/lib/oeqa/selftest/cases/oelib/license.py
@@ -66,3 +66,34 @@ class TestComplexCombinations(TestSimpleCombinations):
         "(GPL-2.0|Proprietary)&BSD-4-clause&MIT": ["GPL-2.0", "BSD-4-clause", "MIT"],
     }
     preferred = ["BAR", "OMEGA", "BETA", "GPL-2.0"]
+
+class TestIsIncluded(TestCase):
+    tests = {
+        ("FOO | BAR", None, None):
+            [True, ["FOO"]],
+        ("FOO | BAR", None, "FOO"):
+            [True, ["BAR"]],
+        ("FOO | BAR", "BAR", None):
+            [True, ["BAR"]],
+        ("FOO | BAR & FOOBAR", "*BAR", None):
+            [True, ["BAR", "FOOBAR"]],
+        ("FOO | BAR & FOOBAR", None, "FOO*"):
+            [False, ["FOOBAR"]],
+        ("(FOO | BAR) & FOOBAR | BARFOO", None, "FOO"):
+            [True, ["BAR", "FOOBAR"]],
+        ("(FOO | BAR) & FOOBAR | BAZ & MOO & BARFOO", None, "FOO"):
+            [True, ["BAZ", "MOO", "BARFOO"]],
+        ("GPL-3.0 & GPL-2.0 & LGPL-2.1 | Proprietary", None, None):
+            [True, ["GPL-3.0", "GPL-2.0", "LGPL-2.1"]],
+        ("GPL-3.0 & GPL-2.0 & LGPL-2.1 | Proprietary", None, "GPL-3.0"):
+            [True, ["Proprietary"]],
+        ("GPL-3.0 & GPL-2.0 & LGPL-2.1 | Proprietary", None, "GPL-3.0 Proprietary"):
+            [False, ["GPL-3.0"]]
+    }
+
+    def test_tests(self):
+        for args, expected in self.tests.items():
+            is_included, licenses = oe.license.is_included(
+                args[0], (args[1] or '').split(), (args[2] or '').split())
+            self.assertEqual(is_included, expected[0])
+            self.assertListEqual(licenses, expected[1])


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]