base/license: Rework INCOMPATIBLE_LICENSE variable handling

This re-writes the INCOMPATIBLE_LICENSE checking code to replace
the WHITELIST_<lic> with
INCOMPATIBLE_LICENSE_EXCEPTIONS = '<pkg>:<lic> <pkg>:<lic> ...'

This initial change leaves most of the code structure in place,
but the code in base.bbclass needs to be re-written to make
the check more consistent around packages (PKGS) and not recipe
names (PN). This also is taking into account the changes for SPDX
licenses.

The aim is to provide a mode consistent variable where the variable
name is known and can easily be queried.

(From OE-Core rev: 0d19c45ba6cf43518f380ca5afe9753a2eda0691)

Signed-off-by: Saul Wold <saul.wold@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Saul Wold
2022-02-23 17:26:59 -08:00
committed by Richard Purdie
parent 9ead8e762e
commit d6449581c9
6 changed files with 61 additions and 61 deletions

View File

@@ -595,46 +595,35 @@ python () {
if check_license and bad_licenses:
bad_licenses = expand_wildcard_licenses(d, bad_licenses)
whitelist = []
for lic in bad_licenses:
spdx_license = return_spdx(d, lic)
whitelist.extend((d.getVar("WHITELIST_" + lic) or "").split())
if spdx_license:
whitelist.extend((d.getVar("WHITELIST_" + spdx_license) or "").split())
exceptions = (d.getVar("INCOMPATIBLE_LICENSE_EXCEPTIONS") or "").split()
if pn in whitelist:
'''
We need to track what we are whitelisting and why. If pn is
incompatible we need to be able to note that the image that
is created may infact contain incompatible licenses despite
INCOMPATIBLE_LICENSE being set.
'''
bb.note("Including %s as buildable despite it having an incompatible license because it has been whitelisted" % pn)
else:
pkgs = d.getVar('PACKAGES').split()
skipped_pkgs = {}
unskipped_pkgs = []
for pkg in pkgs:
incompatible_lic = incompatible_license(d, bad_licenses, pkg)
if incompatible_lic:
skipped_pkgs[pkg] = incompatible_lic
else:
unskipped_pkgs.append(pkg)
if unskipped_pkgs:
for pkg in skipped_pkgs:
bb.debug(1, "Skipping the package %s at do_rootfs because of incompatible license(s): %s" % (pkg, ' '.join(skipped_pkgs[pkg])))
d.setVar('_exclude_incompatible-' + pkg, ' '.join(skipped_pkgs[pkg]))
for pkg in unskipped_pkgs:
bb.debug(1, "Including the package %s" % pkg)
pkgs = d.getVar('PACKAGES').split()
skipped_pkgs = {}
unskipped_pkgs = []
for pkg in pkgs:
remaining_bad_licenses = oe.license.apply_pkg_license_exception(pkg, bad_licenses, exceptions)
incompatible_lic = incompatible_license(d, remaining_bad_licenses, pkg)
if incompatible_lic:
skipped_pkgs[pkg] = incompatible_lic
else:
incompatible_lic = incompatible_license(d, bad_licenses)
for pkg in skipped_pkgs:
incompatible_lic += skipped_pkgs[pkg]
incompatible_lic = sorted(list(set(incompatible_lic)))
unskipped_pkgs.append(pkg)
if incompatible_lic:
bb.debug(1, "Skipping recipe %s because of incompatible license(s): %s" % (pn, ' '.join(incompatible_lic)))
raise bb.parse.SkipRecipe("it has incompatible license(s): %s" % ' '.join(incompatible_lic))
if unskipped_pkgs:
for pkg in skipped_pkgs:
bb.debug(1, "Skipping the package %s at do_rootfs because of incompatible license(s): %s" % (pkg, ' '.join(skipped_pkgs[pkg])))
d.setVar('_exclude_incompatible-' + pkg, ' '.join(skipped_pkgs[pkg]))
for pkg in unskipped_pkgs:
bb.debug(1, "Including the package %s" % pkg)
else:
incompatible_lic = incompatible_license(d, bad_licenses)
for pkg in skipped_pkgs:
incompatible_lic += skipped_pkgs[pkg]
incompatible_lic = sorted(list(set(incompatible_lic)))
if incompatible_lic:
bb.debug(1, "Skipping recipe %s because of incompatible license(s): %s" % (pn, ' '.join(incompatible_lic)))
raise bb.parse.SkipRecipe("it has incompatible license(s): %s" % ' '.join(incompatible_lic))
needsrcrev = False
srcuri = d.getVar('SRC_URI')

View File

@@ -54,28 +54,23 @@ def write_license_files(d, license_manifest, pkg_dic, rootfs=True):
bad_licenses = (d.getVar("INCOMPATIBLE_LICENSE") or "").split()
bad_licenses = expand_wildcard_licenses(d, bad_licenses)
whitelist = []
for lic in bad_licenses:
whitelist.extend((d.getVar("WHITELIST_" + lic) or "").split())
exceptions = (d.getVar("INCOMPATIBLE_LICENSE_EXCEPTIONS") or "").split()
with open(license_manifest, "w") as license_file:
for pkg in sorted(pkg_dic):
if bad_licenses and pkg not in whitelist:
try:
licenses = incompatible_pkg_license(d, bad_licenses, pkg_dic[pkg]["LICENSE"])
if licenses:
bb.fatal("Package %s cannot be installed into the image because it has incompatible license(s): %s" %(pkg, ' '.join(licenses)))
(pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \
oe.license.manifest_licenses(pkg_dic[pkg]["LICENSE"],
bad_licenses, canonical_license, d)
except oe.license.LicenseError as exc:
bb.fatal('%s: %s' % (d.getVar('P'), exc))
remaining_bad_licenses = oe.license.apply_pkg_license_exception(pkg, bad_licenses, exceptions)
incompatible_licenses = incompatible_pkg_license(d, remaining_bad_licenses, pkg_dic[pkg]["LICENSE"])
if incompatible_licenses:
bb.fatal("Package %s cannot be installed into the image because it has incompatible license(s): %s" %(pkg, ' '.join(incompatible_licenses)))
else:
pkg_dic[pkg]["LICENSES"] = re.sub(r'[|&()*]', ' ', pkg_dic[pkg]["LICENSE"])
pkg_dic[pkg]["LICENSES"] = re.sub(r' *', ' ', pkg_dic[pkg]["LICENSES"])
pkg_dic[pkg]["LICENSES"] = pkg_dic[pkg]["LICENSES"].split()
if pkg in whitelist:
oe.qa.handle_error('license-incompatible', "Including %s with an incompatible license %s into the image, because it has been whitelisted." %(pkg, pkg_dic[pkg]["LICENSE"]), d)
incompatible_licenses = incompatible_pkg_license(d, bad_licenses, pkg_dic[pkg]["LICENSE"])
if incompatible_licenses:
oe.qa.handle_error('license-incompatible', "Including %s with incompatible license(s) %s into the image, because it has been allowed by exception list." %(pkg, ' '.join(incompatible_licenses)), d)
try:
(pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \
oe.license.manifest_licenses(pkg_dic[pkg]["LICENSE"],
remaining_bad_licenses, canonical_license, d)
except oe.license.LicenseError as exc:
bb.fatal('%s: %s' % (d.getVar('P'), exc))
if not "IMAGE_MANIFEST" in pkg_dic[pkg]:
# Rootfs manifest

View File

@@ -75,12 +75,12 @@ python multilib_virtclass_handler () {
e.data.setVar("PN", variant + "-" + e.data.getVar("PN", False))
e.data.setVar("OVERRIDES", e.data.getVar("OVERRIDES", False) + override)
# Expand WHITELIST_GPL-3.0 with multilib prefix
pkgs = e.data.getVar("WHITELIST_GPL-3.0")
# Expand INCOMPATIBLE_LICENSE_EXCEPTIONS with multilib prefix
pkgs = e.data.getVar("INCOMPATIBLE_LICENSE_EXCEPTIONS")
if pkgs:
for pkg in pkgs.split():
pkgs += " " + variant + "-" + pkg
e.data.setVar("WHITELIST_GPL-3.0", pkgs)
e.data.setVar("INCOMPATIBLE_LICENSE_EXCEPTIONS", pkgs)
# DEFAULTTUNE can change TARGET_ARCH override so expand this now before update_data
newtune = e.data.getVar("DEFAULTTUNE:" + "virtclass-multilib-" + variant, False)

View File

@@ -110,6 +110,17 @@ BB_RENAMED_VARIABLES[INHERIT_BLACKLIST] = "is a deprecated variable and no longe
BB_RENAMED_VARIABLES[TUNEABI_WHITELIST] = "is a deprecated variable and support has been removed"
BB_RENAMED_VARIABLES[LICENSE_FLAGS_WHITELIST] = "LICENSE_FLAGS_ACCEPTED"
BB_RENAMED_VARIABLES[WHITELIST_GPL-3.0-only] = "INCOMPATIBLE_LICENSE_EXCEPTIONS"
BB_RENAMED_VARIABLES[WHITELIST_GPL-3.0-or-later] = "INCOMPATIBLE_LICENSE_EXCEPTIONS"
BB_RENAMED_VARIABLES[WHITELIST_LGPL-3.0-only] = "INCOMPATIBLE_LICENSE_EXCEPTIONS"
BB_RENAMED_VARIABLES[WHITELIST_LGPL-3.0-or-later] = "INCOMPATIBLE_LICENSE_EXCEPTIONS"
# These are deprecated version and should be updated to approved names
BB_RENAMED_VARIABLES[WHITELIST_GPL-3.0] = "is deprecated, convert to INCOMPATIBLE_LICENSE_EXCEPTIONS = '<pkg>:GPL-3.0-only'"
BB_RENAMED_VARIABLES[WHITELIST_GPL-3.0+] = "is deprecated, convert to INCOMPATIBLE_LICENSE_EXCEPTIONS = '<pkg>:GPL-3.0-or-later'"
BB_RENAMED_VARIABLES[WHITELIST_LGPL-3.0] = "is deprecated, convert to INCOMPATIBLE_LICENSE_EXCEPTIONS = '<pkg>:LGPL-3.0-only'"
BB_RENAMED_VARIABLES[WHITELIST_LGPL-3.0+] = "is deprecated, convert to INCOMPATIBLE_LICENSE_EXCEPTIONS = '<pkg>:LGPL-3.0-or-later'"
##################################################################
# Architecture-dependent build variables.
##################################################################

View File

@@ -242,3 +242,8 @@ def list_licenses(licensestr):
except SyntaxError as exc:
raise LicenseSyntaxError(licensestr, exc)
return visitor.licenses
def apply_pkg_license_exception(pkg, bad_licenses, exceptions):
"""Return remaining bad licenses after removing any package exceptions"""
return [lic for lic in bad_licenses if pkg + ':' + lic not in exceptions]

View File

@@ -110,8 +110,8 @@ INCOMPATIBLE_LICENSE:pn-core-image-minimal = "GPL-3.0 LGPL-3.0"
bitbake('core-image-minimal')
def test_bash_whitelist(self):
self.write_config(self.default_config() + '\nWHITELIST_GPL-3.0:pn-core-image-minimal = "bash"')
def test_bash_license_exceptions(self):
self.write_config(self.default_config() + '\nINCOMPATIBLE_LICENSE_EXCEPTIONS:pn-core-image-minimal = "bash:GPL-3.0-or-later"')
bitbake('core-image-minimal')