blob: 4cf7f074fc22e8bae4e1086d2985ee280952ddb8 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# Populates LICENSE_DIRECTORY as set in distro config with the license files as set by
2# LIC_FILES_CHKSUM.
3# TODO:
4# - There is a real issue revolving around license naming standards.
5
6LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses"
7LICSSTATEDIR = "${WORKDIR}/license-destdir/"
8
9# Create extra package with license texts and add it to RRECOMMENDS_${PN}
10LICENSE_CREATE_PACKAGE[type] = "boolean"
11LICENSE_CREATE_PACKAGE ??= "0"
12LICENSE_PACKAGE_SUFFIX ??= "-lic"
13LICENSE_FILES_DIRECTORY ??= "${datadir}/licenses/"
14
15addtask populate_lic after do_patch before do_build
16do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}"
17do_populate_lic[cleandirs] = "${LICSSTATEDIR}"
18
Patrick Williamsc124f4f2015-09-15 14:41:29 -050019python do_populate_lic() {
20 """
21 Populate LICENSE_DIRECTORY with licenses.
22 """
23 lic_files_paths = find_license_files(d)
24
25 # The base directory we wrangle licenses to
Brad Bishop6e60e8b2018-02-01 10:27:11 -050026 destdir = os.path.join(d.getVar('LICSSTATEDIR'), d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050027 copy_license_files(lic_files_paths, destdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050028 info = get_recipe_info(d)
29 with open(os.path.join(destdir, "recipeinfo"), "w") as f:
30 for key in sorted(info.keys()):
31 f.write("%s: %s\n" % (key, info[key]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032}
33
34# it would be better to copy them in do_install_append, but find_license_filesa is python
35python perform_packagecopy_prepend () {
36 enabled = oe.data.typed_value('LICENSE_CREATE_PACKAGE', d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -050037 if d.getVar('CLASSOVERRIDE') == 'class-target' and enabled:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050038 lic_files_paths = find_license_files(d)
39
40 # LICENSE_FILES_DIRECTORY starts with '/' so os.path.join cannot be used to join D and LICENSE_FILES_DIRECTORY
Brad Bishop6e60e8b2018-02-01 10:27:11 -050041 destdir = d.getVar('D') + os.path.join(d.getVar('LICENSE_FILES_DIRECTORY'), d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042 copy_license_files(lic_files_paths, destdir)
43 add_package_and_files(d)
44}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050045perform_packagecopy[vardeps] += "LICENSE_CREATE_PACKAGE"
46
47def get_recipe_info(d):
48 info = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -050049 info["PV"] = d.getVar("PV")
50 info["PR"] = d.getVar("PR")
51 info["LICENSE"] = d.getVar("LICENSE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050052 return info
Patrick Williamsc124f4f2015-09-15 14:41:29 -050053
54def add_package_and_files(d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050055 packages = d.getVar('PACKAGES')
56 files = d.getVar('LICENSE_FILES_DIRECTORY')
57 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058 pn_lic = "%s%s" % (pn, d.getVar('LICENSE_PACKAGE_SUFFIX', False))
Brad Bishop316dfdd2018-06-25 12:45:53 -040059 if pn_lic in packages.split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060 bb.warn("%s package already existed in %s." % (pn_lic, pn))
61 else:
62 # first in PACKAGES to be sure that nothing else gets LICENSE_FILES_DIRECTORY
63 d.setVar('PACKAGES', "%s %s" % (pn_lic, packages))
64 d.setVar('FILES_' + pn_lic, files)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080065 for pn in packages.split():
66 if pn == pn_lic:
67 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -050068 rrecommends_pn = d.getVar('RRECOMMENDS_' + pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 if rrecommends_pn:
70 d.setVar('RRECOMMENDS_' + pn, "%s %s" % (pn_lic, rrecommends_pn))
71 else:
72 d.setVar('RRECOMMENDS_' + pn, "%s" % (pn_lic))
73
74def copy_license_files(lic_files_paths, destdir):
75 import shutil
Patrick Williamsc0f7c042017-02-23 20:41:17 -060076 import errno
Patrick Williamsc124f4f2015-09-15 14:41:29 -050077
78 bb.utils.mkdirhier(destdir)
Brad Bishop6e60e8b2018-02-01 10:27:11 -050079 for (basename, path, beginline, endline) in lic_files_paths:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080 try:
81 src = path
82 dst = os.path.join(destdir, basename)
83 if os.path.exists(dst):
84 os.remove(dst)
Brad Bishop37a0e4d2017-12-04 01:01:44 -050085 if os.path.islink(src):
86 src = os.path.realpath(src)
Brad Bishop6e60e8b2018-02-01 10:27:11 -050087 canlink = os.access(src, os.W_OK) and (os.stat(src).st_dev == os.stat(destdir).st_dev) and beginline is None and endline is None
Patrick Williamsc0f7c042017-02-23 20:41:17 -060088 if canlink:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050089 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060090 os.link(src, dst)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050091 except OSError as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060092 if err.errno == errno.EXDEV:
93 # Copy license files if hard-link is not possible even if st_dev is the
94 # same on source and destination (docker container with device-mapper?)
95 canlink = False
96 else:
97 raise
Brad Bishop6e60e8b2018-02-01 10:27:11 -050098 # Only chown if we did hardling, and, we're running under pseudo
99 if canlink and os.environ.get('PSEUDO_DISABLED') == '0':
100 os.chown(dst,0,0)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600101 if not canlink:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500102 begin_idx = int(beginline)-1 if beginline is not None else None
103 end_idx = int(endline) if endline is not None else None
104 if begin_idx is None and end_idx is None:
105 shutil.copyfile(src, dst)
106 else:
107 with open(src, 'rb') as src_f:
108 with open(dst, 'wb') as dst_f:
109 dst_f.write(b''.join(src_f.readlines()[begin_idx:end_idx]))
110
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500111 except Exception as e:
112 bb.warn("Could not copy license file %s to %s: %s" % (src, dst, e))
113
114def find_license_files(d):
115 """
116 Creates list of files used in LIC_FILES_CHKSUM and generic LICENSE files.
117 """
118 import shutil
119 import oe.license
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600120 from collections import defaultdict, OrderedDict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500122 # All the license files for the package
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500123 lic_files = d.getVar('LIC_FILES_CHKSUM') or ""
124 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125 # The license files are located in S/LIC_FILE_CHECKSUM.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500126 srcdir = d.getVar('S')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500127 # Directory we store the generic licenses as set in the distro configuration
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500128 generic_directory = d.getVar('COMMON_LICENSE_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 # List of basename, path tuples
130 lic_files_paths = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500131 # hash for keep track generic lics mappings
132 non_generic_lics = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600133 # Entries from LIC_FILES_CHKSUM
134 lic_chksums = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500135 license_source_dirs = []
136 license_source_dirs.append(generic_directory)
137 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500138 additional_lic_dirs = d.getVar('LICENSE_PATH').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500139 for lic_dir in additional_lic_dirs:
140 license_source_dirs.append(lic_dir)
141 except:
142 pass
143
144 class FindVisitor(oe.license.LicenseVisitor):
145 def visit_Str(self, node):
146 #
147 # Until I figure out what to do with
148 # the two modifiers I support (or greater = +
149 # and "with exceptions" being *
150 # we'll just strip out the modifier and put
151 # the base license.
152 find_license(node.s.replace("+", "").replace("*", ""))
153 self.generic_visit(node)
154
155 def find_license(license_type):
156 try:
157 bb.utils.mkdirhier(gen_lic_dest)
158 except:
159 pass
160 spdx_generic = None
161 license_source = None
162 # If the generic does not exist we need to check to see if there is an SPDX mapping to it,
163 # unless NO_GENERIC_LICENSE is set.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500164 for lic_dir in license_source_dirs:
165 if not os.path.isfile(os.path.join(lic_dir, license_type)):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500166 if d.getVarFlag('SPDXLICENSEMAP', license_type) != None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500167 # Great, there is an SPDXLICENSEMAP. We can copy!
168 bb.debug(1, "We need to use a SPDXLICENSEMAP for %s" % (license_type))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500169 spdx_generic = d.getVarFlag('SPDXLICENSEMAP', license_type)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500170 license_source = lic_dir
171 break
172 elif os.path.isfile(os.path.join(lic_dir, license_type)):
173 spdx_generic = license_type
174 license_source = lic_dir
175 break
176
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500177 non_generic_lic = d.getVarFlag('NO_GENERIC_LICENSE', license_type)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500178 if spdx_generic and license_source:
179 # we really should copy to generic_ + spdx_generic, however, that ends up messing the manifest
180 # audit up. This should be fixed in emit_pkgdata (or, we actually got and fix all the recipes)
181
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500182 lic_files_paths.append(("generic_" + license_type, os.path.join(license_source, spdx_generic),
183 None, None))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500184
185 # The user may attempt to use NO_GENERIC_LICENSE for a generic license which doesn't make sense
186 # and should not be allowed, warn the user in this case.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500187 if d.getVarFlag('NO_GENERIC_LICENSE', license_type):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500188 bb.warn("%s: %s is a generic license, please don't use NO_GENERIC_LICENSE for it." % (pn, license_type))
189
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 elif non_generic_lic and non_generic_lic in lic_chksums:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500191 # if NO_GENERIC_LICENSE is set, we copy the license files from the fetched source
192 # of the package rather than the license_source_dirs.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600193 lic_files_paths.append(("generic_" + license_type,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500194 os.path.join(srcdir, non_generic_lic), None, None))
195 non_generic_lics[non_generic_lic] = license_type
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500196 else:
197 # Add explicity avoid of CLOSED license because this isn't generic
198 if license_type != 'CLOSED':
199 # And here is where we warn people that their licenses are lousy
200 bb.warn("%s: No generic license file exists for: %s in any provider" % (pn, license_type))
201 pass
202
203 if not generic_directory:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600204 bb.fatal("COMMON_LICENSE_DIR is unset. Please set this in your distro config")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500205
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500206 for url in lic_files.split():
207 try:
Brad Bishop220d5532018-08-14 00:59:39 +0100208 (method, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
209 if method != "file" or not path:
210 raise bb.fetch.MalformedUrl()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500211 except bb.fetch.MalformedUrl:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500212 bb.fatal("%s: LIC_FILES_CHKSUM contains an invalid URL: %s" % (d.getVar('PF'), url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500213 # We want the license filename and path
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500214 chksum = parm.get('md5', None)
215 beginline = parm.get('beginline')
216 endline = parm.get('endline')
217 lic_chksums[path] = (chksum, beginline, endline)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500218
219 v = FindVisitor()
220 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500221 v.visit_string(d.getVar('LICENSE'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500222 except oe.license.InvalidLicense as exc:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500223 bb.fatal('%s: %s' % (d.getVar('PF'), exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224 except SyntaxError:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500225 bb.warn("%s: Failed to parse it's LICENSE field." % (d.getVar('PF')))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600226 # Add files from LIC_FILES_CHKSUM to list of license files
227 lic_chksum_paths = defaultdict(OrderedDict)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500228 for path, data in sorted(lic_chksums.items()):
229 lic_chksum_paths[os.path.basename(path)][data] = (os.path.join(srcdir, path), data[1], data[2])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600230 for basename, files in lic_chksum_paths.items():
231 if len(files) == 1:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500232 # Don't copy again a LICENSE already handled as non-generic
233 if basename in non_generic_lics:
234 continue
235 data = list(files.values())[0]
236 lic_files_paths.append(tuple([basename] + list(data)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600237 else:
238 # If there are multiple different license files with identical
239 # basenames we rename them to <file>.0, <file>.1, ...
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500240 for i, data in enumerate(files.values()):
241 lic_files_paths.append(tuple(["%s.%d" % (basename, i)] + list(data)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600242
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243 return lic_files_paths
244
245def return_spdx(d, license):
246 """
247 This function returns the spdx mapping of a license if it exists.
248 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500249 return d.getVarFlag('SPDXLICENSEMAP', license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500250
251def canonical_license(d, license):
252 """
253 Return the canonical (SPDX) form of the license if available (so GPLv3
254 becomes GPL-3.0), for the license named 'X+', return canonical form of
255 'X' if availabel and the tailing '+' (so GPLv3+ becomes GPL-3.0+),
256 or the passed license if there is no canonical form.
257 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500258 lic = d.getVarFlag('SPDXLICENSEMAP', license) or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500259 if not lic and license.endswith('+'):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500260 lic = d.getVarFlag('SPDXLICENSEMAP', license.rstrip('+'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500261 if lic:
262 lic += '+'
263 return lic or license
264
265def expand_wildcard_licenses(d, wildcard_licenses):
266 """
267 Return actual spdx format license names if wildcard used. We expand
268 wildcards from SPDXLICENSEMAP flags and SRC_DISTRIBUTE_LICENSES values.
269 """
270 import fnmatch
271 licenses = []
272 spdxmapkeys = d.getVarFlags('SPDXLICENSEMAP').keys()
273 for wld_lic in wildcard_licenses:
274 spdxflags = fnmatch.filter(spdxmapkeys, wld_lic)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500275 licenses += [d.getVarFlag('SPDXLICENSEMAP', flag) for flag in spdxflags]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500276
277 spdx_lics = (d.getVar('SRC_DISTRIBUTE_LICENSES', False) or '').split()
278 for wld_lic in wildcard_licenses:
279 licenses += fnmatch.filter(spdx_lics, wld_lic)
280
281 licenses = list(set(licenses))
282 return licenses
283
284def incompatible_license_contains(license, truevalue, falsevalue, d):
285 license = canonical_license(d, license)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500286 bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500287 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
288 return truevalue if license in bad_licenses else falsevalue
289
290def incompatible_license(d, dont_want_licenses, package=None):
291 """
292 This function checks if a recipe has only incompatible licenses. It also
293 take into consideration 'or' operand. dont_want_licenses should be passed
294 as canonical (SPDX) names.
295 """
296 import oe.license
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500297 license = d.getVar("LICENSE_%s" % package) if package else None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500298 if not license:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500299 license = d.getVar('LICENSE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500300
301 # Handles an "or" or two license sets provided by
302 # flattened_licenses(), pick one that works if possible.
303 def choose_lic_set(a, b):
304 return a if all(oe.license.license_ok(canonical_license(d, lic),
305 dont_want_licenses) for lic in a) else b
306
307 try:
308 licenses = oe.license.flattened_licenses(license, choose_lic_set)
309 except oe.license.LicenseError as exc:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500310 bb.fatal('%s: %s' % (d.getVar('P'), exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500311 return any(not oe.license.license_ok(canonical_license(d, l), \
312 dont_want_licenses) for l in licenses)
313
314def check_license_flags(d):
315 """
316 This function checks if a recipe has any LICENSE_FLAGS that
317 aren't whitelisted.
318
319 If it does, it returns the first LICENSE_FLAGS item missing from the
320 whitelist, or all of the LICENSE_FLAGS if there is no whitelist.
321
322 If everything is is properly whitelisted, it returns None.
323 """
324
325 def license_flag_matches(flag, whitelist, pn):
326 """
327 Return True if flag matches something in whitelist, None if not.
328
329 Before we test a flag against the whitelist, we append _${PN}
330 to it. We then try to match that string against the
331 whitelist. This covers the normal case, where we expect
332 LICENSE_FLAGS to be a simple string like 'commercial', which
333 the user typically matches exactly in the whitelist by
334 explicitly appending the package name e.g 'commercial_foo'.
335 If we fail the match however, we then split the flag across
336 '_' and append each fragment and test until we either match or
337 run out of fragments.
338 """
339 flag_pn = ("%s_%s" % (flag, pn))
340 for candidate in whitelist:
341 if flag_pn == candidate:
342 return True
343
344 flag_cur = ""
345 flagments = flag_pn.split("_")
346 flagments.pop() # we've already tested the full string
347 for flagment in flagments:
348 if flag_cur:
349 flag_cur += "_"
350 flag_cur += flagment
351 for candidate in whitelist:
352 if flag_cur == candidate:
353 return True
354 return False
355
356 def all_license_flags_match(license_flags, whitelist):
357 """ Return first unmatched flag, None if all flags match """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500358 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500359 split_whitelist = whitelist.split()
360 for flag in license_flags.split():
361 if not license_flag_matches(flag, split_whitelist, pn):
362 return flag
363 return None
364
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500365 license_flags = d.getVar('LICENSE_FLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500366 if license_flags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500367 whitelist = d.getVar('LICENSE_FLAGS_WHITELIST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500368 if not whitelist:
369 return license_flags
370 unmatched_flag = all_license_flags_match(license_flags, whitelist)
371 if unmatched_flag:
372 return unmatched_flag
373 return None
374
375def check_license_format(d):
376 """
377 This function checks if LICENSE is well defined,
378 Validate operators in LICENSES.
379 No spaces are allowed between LICENSES.
380 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500381 pn = d.getVar('PN')
382 licenses = d.getVar('LICENSE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500383 from oe.license import license_operator, license_operator_chars, license_pattern
384
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600385 elements = list(filter(lambda x: x.strip(), license_operator.split(licenses)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500386 for pos, element in enumerate(elements):
387 if license_pattern.match(element):
388 if pos > 0 and license_pattern.match(elements[pos - 1]):
389 bb.warn('%s: LICENSE value "%s" has an invalid format - license names ' \
390 'must be separated by the following characters to indicate ' \
391 'the license selection: %s' %
392 (pn, licenses, license_operator_chars))
393 elif not license_operator.match(element):
394 bb.warn('%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \
395 'in the valid list of separators (%s)' %
396 (pn, licenses, element, license_operator_chars))
397
398SSTATETASKS += "do_populate_lic"
399do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
400do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
401
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800402IMAGE_CLASSES_append = " license_image"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500403
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500404python do_populate_lic_setscene () {
405 sstate_setscene(d)
406}
407addtask do_populate_lic_setscene