summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/classes-global/base.bbclass10
-rw-r--r--meta/classes-global/license.bbclass165
-rw-r--r--meta/classes-recipe/license_image.bbclass14
-rw-r--r--meta/lib/oe/license.py163
4 files changed, 175 insertions, 177 deletions
diff --git a/meta/classes-global/base.bbclass b/meta/classes-global/base.bbclass
index b6940bbb6f..88b932fc3f 100644
--- a/meta/classes-global/base.bbclass
+++ b/meta/classes-global/base.bbclass
@@ -528,8 +528,8 @@ python () {
528 bb.fatal('This recipe does not have the LICENSE field set (%s)' % pn) 528 bb.fatal('This recipe does not have the LICENSE field set (%s)' % pn)
529 529
530 if bb.data.inherits_class('license', d): 530 if bb.data.inherits_class('license', d):
531 check_license_format(d) 531 oe.license.check_license_format(d)
532 unmatched_license_flags = check_license_flags(d) 532 unmatched_license_flags = oe.license.check_license_flags(d)
533 if unmatched_license_flags: 533 if unmatched_license_flags:
534 for unmatched in unmatched_license_flags: 534 for unmatched in unmatched_license_flags:
535 message = "Has a restricted license '%s' which is not listed in your LICENSE_FLAGS_ACCEPTED." % unmatched 535 message = "Has a restricted license '%s' which is not listed in your LICENSE_FLAGS_ACCEPTED." % unmatched
@@ -583,7 +583,7 @@ python () {
583 check_license = False 583 check_license = False
584 584
585 if check_license and bad_licenses: 585 if check_license and bad_licenses:
586 bad_licenses = expand_wildcard_licenses(d, bad_licenses) 586 bad_licenses = oe.license.expand_wildcard_licenses(d, bad_licenses)
587 587
588 exceptions = (d.getVar("INCOMPATIBLE_LICENSE_EXCEPTIONS") or "").split() 588 exceptions = (d.getVar("INCOMPATIBLE_LICENSE_EXCEPTIONS") or "").split()
589 589
@@ -599,7 +599,7 @@ python () {
599 for pkg in pkgs: 599 for pkg in pkgs:
600 remaining_bad_licenses = oe.license.apply_pkg_license_exception(pkg, bad_licenses, exceptions) 600 remaining_bad_licenses = oe.license.apply_pkg_license_exception(pkg, bad_licenses, exceptions)
601 601
602 incompatible_lic = incompatible_license(d, remaining_bad_licenses, pkg) 602 incompatible_lic = oe.license.incompatible_license(d, remaining_bad_licenses, pkg)
603 if incompatible_lic: 603 if incompatible_lic:
604 skipped_pkgs[pkg] = incompatible_lic 604 skipped_pkgs[pkg] = incompatible_lic
605 else: 605 else:
@@ -612,7 +612,7 @@ python () {
612 for pkg in unskipped_pkgs: 612 for pkg in unskipped_pkgs:
613 bb.debug(1, "Including the package %s" % pkg) 613 bb.debug(1, "Including the package %s" % pkg)
614 else: 614 else:
615 incompatible_lic = incompatible_license(d, bad_licenses) 615 incompatible_lic = oe.license.incompatible_license(d, bad_licenses)
616 for pkg in skipped_pkgs: 616 for pkg in skipped_pkgs:
617 incompatible_lic += skipped_pkgs[pkg] 617 incompatible_lic += skipped_pkgs[pkg]
618 incompatible_lic = sorted(list(set(incompatible_lic))) 618 incompatible_lic = sorted(list(set(incompatible_lic)))
diff --git a/meta/classes-global/license.bbclass b/meta/classes-global/license.bbclass
index 043715fcc3..94dcc7f331 100644
--- a/meta/classes-global/license.bbclass
+++ b/meta/classes-global/license.bbclass
@@ -255,171 +255,6 @@ def find_license_files(d):
255 255
256 return lic_files_paths 256 return lic_files_paths
257 257
258def return_spdx(d, license):
259 """
260 This function returns the spdx mapping of a license if it exists.
261 """
262 return d.getVarFlag('SPDXLICENSEMAP', license)
263
264def canonical_license(d, license):
265 """
266 Return the canonical (SPDX) form of the license if available (so GPLv3
267 becomes GPL-3.0-only) or the passed license if there is no canonical form.
268 """
269 return d.getVarFlag('SPDXLICENSEMAP', license) or license
270
271def expand_wildcard_licenses(d, wildcard_licenses):
272 """
273 There are some common wildcard values users may want to use. Support them
274 here.
275 """
276 licenses = set(wildcard_licenses)
277 mapping = {
278 "AGPL-3.0*" : ["AGPL-3.0-only", "AGPL-3.0-or-later"],
279 "GPL-3.0*" : ["GPL-3.0-only", "GPL-3.0-or-later"],
280 "LGPL-3.0*" : ["LGPL-3.0-only", "LGPL-3.0-or-later"],
281 }
282 for k in mapping:
283 if k in wildcard_licenses:
284 licenses.remove(k)
285 for item in mapping[k]:
286 licenses.add(item)
287
288 for l in licenses:
289 if l in oe.license.obsolete_license_list():
290 bb.fatal("Error, %s is an obsolete license, please use an SPDX reference in INCOMPATIBLE_LICENSE" % l)
291 if "*" in l:
292 bb.fatal("Error, %s is an invalid license wildcard entry" % l)
293
294 return list(licenses)
295
296def incompatible_license_contains(license, truevalue, falsevalue, d):
297 license = canonical_license(d, license)
298 bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE') or "").split()
299 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
300 return truevalue if license in bad_licenses else falsevalue
301
302def incompatible_pkg_license(d, dont_want_licenses, license):
303 # Handles an "or" or two license sets provided by
304 # flattened_licenses(), pick one that works if possible.
305 def choose_lic_set(a, b):
306 return a if all(oe.license.license_ok(canonical_license(d, lic),
307 dont_want_licenses) for lic in a) else b
308
309 try:
310 licenses = oe.license.flattened_licenses(license, choose_lic_set)
311 except oe.license.LicenseError as exc:
312 bb.fatal('%s: %s' % (d.getVar('P'), exc))
313
314 incompatible_lic = []
315 for l in licenses:
316 license = canonical_license(d, l)
317 if not oe.license.license_ok(license, dont_want_licenses):
318 incompatible_lic.append(license)
319
320 return sorted(incompatible_lic)
321
322def incompatible_license(d, dont_want_licenses, package=None):
323 """
324 This function checks if a recipe has only incompatible licenses. It also
325 take into consideration 'or' operand. dont_want_licenses should be passed
326 as canonical (SPDX) names.
327 """
328 import oe.license
329 license = d.getVar("LICENSE:%s" % package) if package else None
330 if not license:
331 license = d.getVar('LICENSE')
332
333 return incompatible_pkg_license(d, dont_want_licenses, license)
334
335def check_license_flags(d):
336 """
337 This function checks if a recipe has any LICENSE_FLAGS that
338 aren't acceptable.
339
340 If it does, it returns the all LICENSE_FLAGS missing from the list
341 of acceptable license flags, or all of the LICENSE_FLAGS if there
342 is no list of acceptable flags.
343
344 If everything is is acceptable, it returns None.
345 """
346
347 def license_flag_matches(flag, acceptlist, pn):
348 """
349 Return True if flag matches something in acceptlist, None if not.
350
351 Before we test a flag against the acceptlist, we append _${PN}
352 to it. We then try to match that string against the
353 acceptlist. This covers the normal case, where we expect
354 LICENSE_FLAGS to be a simple string like 'commercial', which
355 the user typically matches exactly in the acceptlist by
356 explicitly appending the package name e.g 'commercial_foo'.
357 If we fail the match however, we then split the flag across
358 '_' and append each fragment and test until we either match or
359 run out of fragments.
360 """
361 flag_pn = ("%s_%s" % (flag, pn))
362 for candidate in acceptlist:
363 if flag_pn == candidate:
364 return True
365
366 flag_cur = ""
367 flagments = flag_pn.split("_")
368 flagments.pop() # we've already tested the full string
369 for flagment in flagments:
370 if flag_cur:
371 flag_cur += "_"
372 flag_cur += flagment
373 for candidate in acceptlist:
374 if flag_cur == candidate:
375 return True
376 return False
377
378 def all_license_flags_match(license_flags, acceptlist):
379 """ Return all unmatched flags, None if all flags match """
380 pn = d.getVar('PN')
381 split_acceptlist = acceptlist.split()
382 flags = []
383 for flag in license_flags.split():
384 if not license_flag_matches(flag, split_acceptlist, pn):
385 flags.append(flag)
386 return flags if flags else None
387
388 license_flags = d.getVar('LICENSE_FLAGS')
389 if license_flags:
390 acceptlist = d.getVar('LICENSE_FLAGS_ACCEPTED')
391 if not acceptlist:
392 return license_flags.split()
393 unmatched_flags = all_license_flags_match(license_flags, acceptlist)
394 if unmatched_flags:
395 return unmatched_flags
396 return None
397
398def check_license_format(d):
399 """
400 This function checks if LICENSE is well defined,
401 Validate operators in LICENSES.
402 No spaces are allowed between LICENSES.
403 """
404 pn = d.getVar('PN')
405 licenses = d.getVar('LICENSE')
406 from oe.license import license_operator, license_operator_chars, license_pattern
407
408 elements = list(filter(lambda x: x.strip(), license_operator.split(licenses)))
409 for pos, element in enumerate(elements):
410 if license_pattern.match(element):
411 if pos > 0 and license_pattern.match(elements[pos - 1]):
412 oe.qa.handle_error('license-format',
413 '%s: LICENSE value "%s" has an invalid format - license names ' \
414 'must be separated by the following characters to indicate ' \
415 'the license selection: %s' %
416 (pn, licenses, license_operator_chars), d)
417 elif not license_operator.match(element):
418 oe.qa.handle_error('license-format',
419 '%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \
420 'in the valid list of separators (%s)' %
421 (pn, licenses, element, license_operator_chars), d)
422
423SSTATETASKS += "do_populate_lic" 258SSTATETASKS += "do_populate_lic"
424do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}" 259do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
425do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/" 260do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
diff --git a/meta/classes-recipe/license_image.bbclass b/meta/classes-recipe/license_image.bbclass
index 0e953856a6..d2c5ab902c 100644
--- a/meta/classes-recipe/license_image.bbclass
+++ b/meta/classes-recipe/license_image.bbclass
@@ -58,7 +58,7 @@ def write_license_files(d, license_manifest, pkg_dic, rootfs=True):
58 import stat 58 import stat
59 59
60 bad_licenses = (d.getVar("INCOMPATIBLE_LICENSE") or "").split() 60 bad_licenses = (d.getVar("INCOMPATIBLE_LICENSE") or "").split()
61 bad_licenses = expand_wildcard_licenses(d, bad_licenses) 61 bad_licenses = oe.license.expand_wildcard_licenses(d, bad_licenses)
62 pkgarchs = d.getVar("SSTATE_ARCHS").split() 62 pkgarchs = d.getVar("SSTATE_ARCHS").split()
63 pkgarchs.reverse() 63 pkgarchs.reverse()
64 64
@@ -66,17 +66,17 @@ def write_license_files(d, license_manifest, pkg_dic, rootfs=True):
66 with open(license_manifest, "w") as license_file: 66 with open(license_manifest, "w") as license_file:
67 for pkg in sorted(pkg_dic): 67 for pkg in sorted(pkg_dic):
68 remaining_bad_licenses = oe.license.apply_pkg_license_exception(pkg, bad_licenses, exceptions) 68 remaining_bad_licenses = oe.license.apply_pkg_license_exception(pkg, bad_licenses, exceptions)
69 incompatible_licenses = incompatible_pkg_license(d, remaining_bad_licenses, pkg_dic[pkg]["LICENSE"]) 69 incompatible_licenses = oe.license.incompatible_pkg_license(d, remaining_bad_licenses, pkg_dic[pkg]["LICENSE"])
70 if incompatible_licenses: 70 if incompatible_licenses:
71 bb.fatal("Package %s cannot be installed into the image because it has incompatible license(s): %s" %(pkg, ' '.join(incompatible_licenses))) 71 bb.fatal("Package %s cannot be installed into the image because it has incompatible license(s): %s" %(pkg, ' '.join(incompatible_licenses)))
72 else: 72 else:
73 incompatible_licenses = incompatible_pkg_license(d, bad_licenses, pkg_dic[pkg]["LICENSE"]) 73 incompatible_licenses = oe.license.incompatible_pkg_license(d, bad_licenses, pkg_dic[pkg]["LICENSE"])
74 if incompatible_licenses: 74 if incompatible_licenses:
75 oe.qa.handle_error('license-exception', "Including %s with incompatible license(s) %s into the image, because it has been allowed by exception list." %(pkg, ' '.join(incompatible_licenses)), d) 75 oe.qa.handle_error('license-exception', "Including %s with incompatible license(s) %s into the image, because it has been allowed by exception list." %(pkg, ' '.join(incompatible_licenses)), d)
76 try: 76 try:
77 (pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \ 77 (pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \
78 oe.license.manifest_licenses(pkg_dic[pkg]["LICENSE"], 78 oe.license.manifest_licenses(pkg_dic[pkg]["LICENSE"],
79 remaining_bad_licenses, canonical_license, d) 79 remaining_bad_licenses, oe.license.canonical_license, d)
80 except oe.license.LicenseError as exc: 80 except oe.license.LicenseError as exc:
81 bb.fatal('%s: %s' % (d.getVar('P'), exc)) 81 bb.fatal('%s: %s' % (d.getVar('P'), exc))
82 82
@@ -144,7 +144,7 @@ def write_license_files(d, license_manifest, pkg_dic, rootfs=True):
144 if not os.path.exists(pkg_license_dir ): 144 if not os.path.exists(pkg_license_dir ):
145 bb.fatal("Couldn't find license information for dependency %s" % pkg) 145 bb.fatal("Couldn't find license information for dependency %s" % pkg)
146 146
147 pkg_manifest_licenses = [canonical_license(d, lic) \ 147 pkg_manifest_licenses = [oe.license.canonical_license(d, lic) \
148 for lic in pkg_dic[pkg]["LICENSES"]] 148 for lic in pkg_dic[pkg]["LICENSES"]]
149 149
150 licenses = os.listdir(pkg_license_dir) 150 licenses = os.listdir(pkg_license_dir)
@@ -153,7 +153,7 @@ def write_license_files(d, license_manifest, pkg_dic, rootfs=True):
153 pkg_rootfs_license = os.path.join(pkg_rootfs_license_dir, lic) 153 pkg_rootfs_license = os.path.join(pkg_rootfs_license_dir, lic)
154 154
155 if re.match(r"^generic_.*$", lic): 155 if re.match(r"^generic_.*$", lic):
156 generic_lic = canonical_license(d, 156 generic_lic = oe.license.canonical_license(d,
157 re.search(r"^generic_(.*)$", lic).group(1)) 157 re.search(r"^generic_(.*)$", lic).group(1))
158 158
159 # Do not copy generic license into package if isn't 159 # Do not copy generic license into package if isn't
@@ -176,7 +176,7 @@ def write_license_files(d, license_manifest, pkg_dic, rootfs=True):
176 if not os.path.exists(pkg_rootfs_license): 176 if not os.path.exists(pkg_rootfs_license):
177 os.symlink(os.path.join('..', generic_lic_file), pkg_rootfs_license) 177 os.symlink(os.path.join('..', generic_lic_file), pkg_rootfs_license)
178 else: 178 else:
179 if (oe.license.license_ok(canonical_license(d, 179 if (oe.license.license_ok(oe.license.canonical_license(d,
180 lic), bad_licenses) == False or 180 lic), bad_licenses) == False or
181 os.path.exists(pkg_rootfs_license)): 181 os.path.exists(pkg_rootfs_license)):
182 continue 182 continue
diff --git a/meta/lib/oe/license.py b/meta/lib/oe/license.py
index d9c8d94da4..7739697c40 100644
--- a/meta/lib/oe/license.py
+++ b/meta/lib/oe/license.py
@@ -259,3 +259,166 @@ def apply_pkg_license_exception(pkg, bad_licenses, exceptions):
259 """Return remaining bad licenses after removing any package exceptions""" 259 """Return remaining bad licenses after removing any package exceptions"""
260 260
261 return [lic for lic in bad_licenses if pkg + ':' + lic not in exceptions] 261 return [lic for lic in bad_licenses if pkg + ':' + lic not in exceptions]
262
263def return_spdx(d, license):
264 """
265 This function returns the spdx mapping of a license if it exists.
266 """
267 return d.getVarFlag('SPDXLICENSEMAP', license)
268
269def canonical_license(d, license):
270 """
271 Return the canonical (SPDX) form of the license if available (so GPLv3
272 becomes GPL-3.0-only) or the passed license if there is no canonical form.
273 """
274 return d.getVarFlag('SPDXLICENSEMAP', license) or license
275
276def expand_wildcard_licenses(d, wildcard_licenses):
277 """
278 There are some common wildcard values users may want to use. Support them
279 here.
280 """
281 licenses = set(wildcard_licenses)
282 mapping = {
283 "AGPL-3.0*" : ["AGPL-3.0-only", "AGPL-3.0-or-later"],
284 "GPL-3.0*" : ["GPL-3.0-only", "GPL-3.0-or-later"],
285 "LGPL-3.0*" : ["LGPL-3.0-only", "LGPL-3.0-or-later"],
286 }
287 for k in mapping:
288 if k in wildcard_licenses:
289 licenses.remove(k)
290 for item in mapping[k]:
291 licenses.add(item)
292
293 for l in licenses:
294 if l in obsolete_license_list():
295 bb.fatal("Error, %s is an obsolete license, please use an SPDX reference in INCOMPATIBLE_LICENSE" % l)
296 if "*" in l:
297 bb.fatal("Error, %s is an invalid license wildcard entry" % l)
298
299 return list(licenses)
300
301def incompatible_license_contains(license, truevalue, falsevalue, d):
302 license = canonical_license(d, license)
303 bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE') or "").split()
304 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
305 return truevalue if license in bad_licenses else falsevalue
306
307def incompatible_pkg_license(d, dont_want_licenses, license):
308 # Handles an "or" or two license sets provided by
309 # flattened_licenses(), pick one that works if possible.
310 def choose_lic_set(a, b):
311 return a if all(license_ok(canonical_license(d, lic),
312 dont_want_licenses) for lic in a) else b
313
314 try:
315 licenses = flattened_licenses(license, choose_lic_set)
316 except LicenseError as exc:
317 bb.fatal('%s: %s' % (d.getVar('P'), exc))
318
319 incompatible_lic = []
320 for l in licenses:
321 license = canonical_license(d, l)
322 if not license_ok(license, dont_want_licenses):
323 incompatible_lic.append(license)
324
325 return sorted(incompatible_lic)
326
327def incompatible_license(d, dont_want_licenses, package=None):
328 """
329 This function checks if a recipe has only incompatible licenses. It also
330 take into consideration 'or' operand. dont_want_licenses should be passed
331 as canonical (SPDX) names.
332 """
333 license = d.getVar("LICENSE:%s" % package) if package else None
334 if not license:
335 license = d.getVar('LICENSE')
336
337 return incompatible_pkg_license(d, dont_want_licenses, license)
338
339def check_license_flags(d):
340 """
341 This function checks if a recipe has any LICENSE_FLAGS that
342 aren't acceptable.
343
344 If it does, it returns the all LICENSE_FLAGS missing from the list
345 of acceptable license flags, or all of the LICENSE_FLAGS if there
346 is no list of acceptable flags.
347
348 If everything is is acceptable, it returns None.
349 """
350
351 def license_flag_matches(flag, acceptlist, pn):
352 """
353 Return True if flag matches something in acceptlist, None if not.
354
355 Before we test a flag against the acceptlist, we append _${PN}
356 to it. We then try to match that string against the
357 acceptlist. This covers the normal case, where we expect
358 LICENSE_FLAGS to be a simple string like 'commercial', which
359 the user typically matches exactly in the acceptlist by
360 explicitly appending the package name e.g 'commercial_foo'.
361 If we fail the match however, we then split the flag across
362 '_' and append each fragment and test until we either match or
363 run out of fragments.
364 """
365 flag_pn = ("%s_%s" % (flag, pn))
366 for candidate in acceptlist:
367 if flag_pn == candidate:
368 return True
369
370 flag_cur = ""
371 flagments = flag_pn.split("_")
372 flagments.pop() # we've already tested the full string
373 for flagment in flagments:
374 if flag_cur:
375 flag_cur += "_"
376 flag_cur += flagment
377 for candidate in acceptlist:
378 if flag_cur == candidate:
379 return True
380 return False
381
382 def all_license_flags_match(license_flags, acceptlist):
383 """ Return all unmatched flags, None if all flags match """
384 pn = d.getVar('PN')
385 split_acceptlist = acceptlist.split()
386 flags = []
387 for flag in license_flags.split():
388 if not license_flag_matches(flag, split_acceptlist, pn):
389 flags.append(flag)
390 return flags if flags else None
391
392 license_flags = d.getVar('LICENSE_FLAGS')
393 if license_flags:
394 acceptlist = d.getVar('LICENSE_FLAGS_ACCEPTED')
395 if not acceptlist:
396 return license_flags.split()
397 unmatched_flags = all_license_flags_match(license_flags, acceptlist)
398 if unmatched_flags:
399 return unmatched_flags
400 return None
401
402def check_license_format(d):
403 """
404 This function checks if LICENSE is well defined,
405 Validate operators in LICENSES.
406 No spaces are allowed between LICENSES.
407 """
408 pn = d.getVar('PN')
409 licenses = d.getVar('LICENSE')
410
411 elements = list(filter(lambda x: x.strip(), license_operator.split(licenses)))
412 for pos, element in enumerate(elements):
413 if license_pattern.match(element):
414 if pos > 0 and license_pattern.match(elements[pos - 1]):
415 oe.qa.handle_error('license-format',
416 '%s: LICENSE value "%s" has an invalid format - license names ' \
417 'must be separated by the following characters to indicate ' \
418 'the license selection: %s' %
419 (pn, licenses, license_operator_chars), d)
420 elif not license_operator.match(element):
421 oe.qa.handle_error('license-format',
422 '%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \
423 'in the valid list of separators (%s)' %
424 (pn, licenses, element, license_operator_chars), d)