summaryrefslogtreecommitdiffstats
path: root/meta/classes-global/license.bbclass
diff options
context:
space:
mode:
Diffstat (limited to 'meta/classes-global/license.bbclass')
-rw-r--r--meta/classes-global/license.bbclass184
1 files changed, 12 insertions, 172 deletions
diff --git a/meta/classes-global/license.bbclass b/meta/classes-global/license.bbclass
index b2e0d3faba..af5f1ed41d 100644
--- a/meta/classes-global/license.bbclass
+++ b/meta/classes-global/license.bbclass
@@ -18,8 +18,14 @@ LICENSE_CREATE_PACKAGE ??= "0"
18LICENSE_PACKAGE_SUFFIX ??= "-lic" 18LICENSE_PACKAGE_SUFFIX ??= "-lic"
19LICENSE_FILES_DIRECTORY ??= "${datadir}/licenses/" 19LICENSE_FILES_DIRECTORY ??= "${datadir}/licenses/"
20 20
21LICENSE_DEPLOY_PATHCOMPONENT = "${SSTATE_PKGARCH}"
22LICENSE_DEPLOY_PATHCOMPONENT:class-cross = "native"
23LICENSE_DEPLOY_PATHCOMPONENT:class-native = "native"
24# Ensure the *value* of SSTATE_PKGARCH is captured as it is used in the output paths
25LICENSE_DEPLOY_PATHCOMPONENT[vardepvalue] += "${LICENSE_DEPLOY_PATHCOMPONENT}"
26
21addtask populate_lic after do_patch before do_build 27addtask populate_lic after do_patch before do_build
22do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}" 28do_populate_lic[dirs] = "${LICSSTATEDIR}/${LICENSE_DEPLOY_PATHCOMPONENT}/${PN}"
23do_populate_lic[cleandirs] = "${LICSSTATEDIR}" 29do_populate_lic[cleandirs] = "${LICSSTATEDIR}"
24 30
25python do_populate_lic() { 31python do_populate_lic() {
@@ -29,7 +35,7 @@ python do_populate_lic() {
29 lic_files_paths = find_license_files(d) 35 lic_files_paths = find_license_files(d)
30 36
31 # The base directory we wrangle licenses to 37 # The base directory we wrangle licenses to
32 destdir = os.path.join(d.getVar('LICSSTATEDIR'), d.getVar('SSTATE_PKGARCH'), d.getVar('PN')) 38 destdir = os.path.join(d.getVar('LICSSTATEDIR'), d.getVar('LICENSE_DEPLOY_PATHCOMPONENT'), d.getVar('PN'))
33 copy_license_files(lic_files_paths, destdir) 39 copy_license_files(lic_files_paths, destdir)
34 info = get_recipe_info(d) 40 info = get_recipe_info(d)
35 with open(os.path.join(destdir, "recipeinfo"), "w") as f: 41 with open(os.path.join(destdir, "recipeinfo"), "w") as f:
@@ -38,8 +44,7 @@ python do_populate_lic() {
38 oe.qa.exit_if_errors(d) 44 oe.qa.exit_if_errors(d)
39} 45}
40 46
41PSEUDO_IGNORE_PATHS .= ",${@','.join(((d.getVar('COMMON_LICENSE_DIR') or '') + ' ' + (d.getVar('LICENSE_PATH') or '') + ' ' + d.getVar('COREBASE') + '/meta/COPYING').split())}" 47# it would be better to copy them in do_install:append, but find_license_files is python
42# it would be better to copy them in do_install:append, but find_license_filesa is python
43python perform_packagecopy:prepend () { 48python perform_packagecopy:prepend () {
44 enabled = oe.data.typed_value('LICENSE_CREATE_PACKAGE', d) 49 enabled = oe.data.typed_value('LICENSE_CREATE_PACKAGE', d)
45 if d.getVar('CLASSOVERRIDE') == 'class-target' and enabled: 50 if d.getVar('CLASSOVERRIDE') == 'class-target' and enabled:
@@ -149,14 +154,14 @@ def find_license_files(d):
149 # and "with exceptions" being * 154 # and "with exceptions" being *
150 # we'll just strip out the modifier and put 155 # we'll just strip out the modifier and put
151 # the base license. 156 # the base license.
152 find_license(node.s.replace("+", "").replace("*", "")) 157 find_licenses(node.s.replace("+", "").replace("*", ""))
153 self.generic_visit(node) 158 self.generic_visit(node)
154 159
155 def visit_Constant(self, node): 160 def visit_Constant(self, node):
156 find_license(node.value.replace("+", "").replace("*", "")) 161 find_licenses(node.value.replace("+", "").replace("*", ""))
157 self.generic_visit(node) 162 self.generic_visit(node)
158 163
159 def find_license(license_type): 164 def find_licenses(license_type):
160 try: 165 try:
161 bb.utils.mkdirhier(gen_lic_dest) 166 bb.utils.mkdirhier(gen_lic_dest)
162 except: 167 except:
@@ -249,171 +254,6 @@ def find_license_files(d):
249 254
250 return lic_files_paths 255 return lic_files_paths
251 256
252def return_spdx(d, license):
253 """
254 This function returns the spdx mapping of a license if it exists.
255 """
256 return d.getVarFlag('SPDXLICENSEMAP', license)
257
258def canonical_license(d, license):
259 """
260 Return the canonical (SPDX) form of the license if available (so GPLv3
261 becomes GPL-3.0-only) or the passed license if there is no canonical form.
262 """
263 return d.getVarFlag('SPDXLICENSEMAP', license) or license
264
265def expand_wildcard_licenses(d, wildcard_licenses):
266 """
267 There are some common wildcard values users may want to use. Support them
268 here.
269 """
270 licenses = set(wildcard_licenses)
271 mapping = {
272 "AGPL-3.0*" : ["AGPL-3.0-only", "AGPL-3.0-or-later"],
273 "GPL-3.0*" : ["GPL-3.0-only", "GPL-3.0-or-later"],
274 "LGPL-3.0*" : ["LGPL-3.0-only", "LGPL-3.0-or-later"],
275 }
276 for k in mapping:
277 if k in wildcard_licenses:
278 licenses.remove(k)
279 for item in mapping[k]:
280 licenses.add(item)
281
282 for l in licenses:
283 if l in oe.license.obsolete_license_list():
284 bb.fatal("Error, %s is an obsolete license, please use an SPDX reference in INCOMPATIBLE_LICENSE" % l)
285 if "*" in l:
286 bb.fatal("Error, %s is an invalid license wildcard entry" % l)
287
288 return list(licenses)
289
290def incompatible_license_contains(license, truevalue, falsevalue, d):
291 license = canonical_license(d, license)
292 bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE') or "").split()
293 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
294 return truevalue if license in bad_licenses else falsevalue
295
296def incompatible_pkg_license(d, dont_want_licenses, license):
297 # Handles an "or" or two license sets provided by
298 # flattened_licenses(), pick one that works if possible.
299 def choose_lic_set(a, b):
300 return a if all(oe.license.license_ok(canonical_license(d, lic),
301 dont_want_licenses) for lic in a) else b
302
303 try:
304 licenses = oe.license.flattened_licenses(license, choose_lic_set)
305 except oe.license.LicenseError as exc:
306 bb.fatal('%s: %s' % (d.getVar('P'), exc))
307
308 incompatible_lic = []
309 for l in licenses:
310 license = canonical_license(d, l)
311 if not oe.license.license_ok(license, dont_want_licenses):
312 incompatible_lic.append(license)
313
314 return sorted(incompatible_lic)
315
316def incompatible_license(d, dont_want_licenses, package=None):
317 """
318 This function checks if a recipe has only incompatible licenses. It also
319 take into consideration 'or' operand. dont_want_licenses should be passed
320 as canonical (SPDX) names.
321 """
322 import oe.license
323 license = d.getVar("LICENSE:%s" % package) if package else None
324 if not license:
325 license = d.getVar('LICENSE')
326
327 return incompatible_pkg_license(d, dont_want_licenses, license)
328
329def check_license_flags(d):
330 """
331 This function checks if a recipe has any LICENSE_FLAGS that
332 aren't acceptable.
333
334 If it does, it returns the all LICENSE_FLAGS missing from the list
335 of acceptable license flags, or all of the LICENSE_FLAGS if there
336 is no list of acceptable flags.
337
338 If everything is is acceptable, it returns None.
339 """
340
341 def license_flag_matches(flag, acceptlist, pn):
342 """
343 Return True if flag matches something in acceptlist, None if not.
344
345 Before we test a flag against the acceptlist, we append _${PN}
346 to it. We then try to match that string against the
347 acceptlist. This covers the normal case, where we expect
348 LICENSE_FLAGS to be a simple string like 'commercial', which
349 the user typically matches exactly in the acceptlist by
350 explicitly appending the package name e.g 'commercial_foo'.
351 If we fail the match however, we then split the flag across
352 '_' and append each fragment and test until we either match or
353 run out of fragments.
354 """
355 flag_pn = ("%s_%s" % (flag, pn))
356 for candidate in acceptlist:
357 if flag_pn == candidate:
358 return True
359
360 flag_cur = ""
361 flagments = flag_pn.split("_")
362 flagments.pop() # we've already tested the full string
363 for flagment in flagments:
364 if flag_cur:
365 flag_cur += "_"
366 flag_cur += flagment
367 for candidate in acceptlist:
368 if flag_cur == candidate:
369 return True
370 return False
371
372 def all_license_flags_match(license_flags, acceptlist):
373 """ Return all unmatched flags, None if all flags match """
374 pn = d.getVar('PN')
375 split_acceptlist = acceptlist.split()
376 flags = []
377 for flag in license_flags.split():
378 if not license_flag_matches(flag, split_acceptlist, pn):
379 flags.append(flag)
380 return flags if flags else None
381
382 license_flags = d.getVar('LICENSE_FLAGS')
383 if license_flags:
384 acceptlist = d.getVar('LICENSE_FLAGS_ACCEPTED')
385 if not acceptlist:
386 return license_flags.split()
387 unmatched_flags = all_license_flags_match(license_flags, acceptlist)
388 if unmatched_flags:
389 return unmatched_flags
390 return None
391
392def check_license_format(d):
393 """
394 This function checks if LICENSE is well defined,
395 Validate operators in LICENSES.
396 No spaces are allowed between LICENSES.
397 """
398 pn = d.getVar('PN')
399 licenses = d.getVar('LICENSE')
400 from oe.license import license_operator, license_operator_chars, license_pattern
401
402 elements = list(filter(lambda x: x.strip(), license_operator.split(licenses)))
403 for pos, element in enumerate(elements):
404 if license_pattern.match(element):
405 if pos > 0 and license_pattern.match(elements[pos - 1]):
406 oe.qa.handle_error('license-format',
407 '%s: LICENSE value "%s" has an invalid format - license names ' \
408 'must be separated by the following characters to indicate ' \
409 'the license selection: %s' %
410 (pn, licenses, license_operator_chars), d)
411 elif not license_operator.match(element):
412 oe.qa.handle_error('license-format',
413 '%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \
414 'in the valid list of separators (%s)' %
415 (pn, licenses, element, license_operator_chars), d)
416
417SSTATETASKS += "do_populate_lic" 257SSTATETASKS += "do_populate_lic"
418do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}" 258do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
419do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/" 259do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"