summaryrefslogtreecommitdiffstats
path: root/meta/lib
diff options
context:
space:
mode:
authorJoshua Watt <JPEWhacker@gmail.com>2024-10-24 13:03:07 -0600
committerRichard Purdie <richard.purdie@linuxfoundation.org>2024-10-25 15:37:10 +0100
commit71760081f782cdf1e53c3ff03a6376fac3605196 (patch)
tree5976208e344a0ec405cd19942468571349a70874 /meta/lib
parentde1fa1e0b0a01ae8a30bbb848e681f0fa2db7ad4 (diff)
downloadpoky-71760081f782cdf1e53c3ff03a6376fac3605196.tar.gz
classes-global/license: Move functions to library code
Moves several of the functions in license.bbclass to be library code New function dependencies were manually verified using bitbake-dumpsigs to ensure that bitbake identified the same dependencies even though they are now in library code (although the new function names mean that the task hashes still change) (From OE-Core rev: 0333e04e353991260c5f67a72f80f3ab9dcf526a) Signed-off-by: Joshua Watt <JPEWhacker@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib')
-rw-r--r--meta/lib/oe/license.py163
1 files changed, 163 insertions, 0 deletions
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)