blob: da4fc3e1d4c72ae7732a0478f8a09cb08e13abef [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
19python write_package_manifest() {
20 # Get list of installed packages
21 license_image_dir = d.expand('${LICENSE_DIRECTORY}/${IMAGE_NAME}')
22 bb.utils.mkdirhier(license_image_dir)
23 from oe.rootfs import image_list_installed_packages
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050024 from oe.utils import format_pkg_list
25
26 pkgs = image_list_installed_packages(d)
27 output = format_pkg_list(pkgs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050028 open(os.path.join(license_image_dir, 'package.manifest'),
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050029 'w+').write(output)
30}
31
32python write_deploy_manifest() {
33 license_deployed_manifest(d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050034}
35
36python license_create_manifest() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -050037 import oe.packagedata
38 from oe.rootfs import image_list_installed_packages
39
Patrick Williamsc124f4f2015-09-15 14:41:29 -050040 build_images_from_feeds = d.getVar('BUILD_IMAGES_FROM_FEEDS', True)
41 if build_images_from_feeds == "1":
42 return 0
43
44 pkg_dic = {}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050045 for pkg in sorted(image_list_installed_packages(d)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046 pkg_info = os.path.join(d.getVar('PKGDATA_DIR', True),
47 'runtime-reverse', pkg)
48 pkg_name = os.path.basename(os.readlink(pkg_info))
49
50 pkg_dic[pkg_name] = oe.packagedata.read_pkgdatafile(pkg_info)
51 if not "LICENSE" in pkg_dic[pkg_name].keys():
52 pkg_lic_name = "LICENSE_" + pkg_name
53 pkg_dic[pkg_name]["LICENSE"] = pkg_dic[pkg_name][pkg_lic_name]
54
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050055 rootfs_license_manifest = os.path.join(d.getVar('LICENSE_DIRECTORY', True),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050056 d.getVar('IMAGE_NAME', True), 'license.manifest')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050057 write_license_files(d, rootfs_license_manifest, pkg_dic)
58}
59
60def write_license_files(d, license_manifest, pkg_dic):
61 import re
62
63 bad_licenses = (d.getVar("INCOMPATIBLE_LICENSE", True) or "").split()
64 bad_licenses = map(lambda l: canonical_license(d, l), bad_licenses)
65 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
66
Patrick Williamsc124f4f2015-09-15 14:41:29 -050067 with open(license_manifest, "w") as license_file:
68 for pkg in sorted(pkg_dic):
69 if bad_licenses:
70 try:
71 (pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \
72 oe.license.manifest_licenses(pkg_dic[pkg]["LICENSE"],
73 bad_licenses, canonical_license, d)
74 except oe.license.LicenseError as exc:
75 bb.fatal('%s: %s' % (d.getVar('P', True), exc))
76 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050077 pkg_dic[pkg]["LICENSES"] = re.sub('[|&()*]', ' ', pkg_dic[pkg]["LICENSE"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050078 pkg_dic[pkg]["LICENSES"] = re.sub(' *', ' ', pkg_dic[pkg]["LICENSES"])
79 pkg_dic[pkg]["LICENSES"] = pkg_dic[pkg]["LICENSES"].split()
80
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050081 if not "IMAGE_MANIFEST" in pkg_dic[pkg]:
82 # Rootfs manifest
83 license_file.write("PACKAGE NAME: %s\n" % pkg)
84 license_file.write("PACKAGE VERSION: %s\n" % pkg_dic[pkg]["PV"])
85 license_file.write("RECIPE NAME: %s\n" % pkg_dic[pkg]["PN"])
86 license_file.write("LICENSE: %s\n\n" % pkg_dic[pkg]["LICENSE"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050087
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050088 # If the package doesn't contain any file, that is, its size is 0, the license
89 # isn't relevant as far as the final image is concerned. So doing license check
90 # doesn't make much sense, skip it.
91 if pkg_dic[pkg]["PKGSIZE_%s" % pkg] == "0":
92 continue
93 else:
94 # Image manifest
95 license_file.write("RECIPE NAME: %s\n" % pkg_dic[pkg]["PN"])
96 license_file.write("VERSION: %s\n" % pkg_dic[pkg]["PV"])
97 license_file.write("LICENSE: %s\n" % pkg_dic[pkg]["LICENSE"])
98 license_file.write("FILES: %s\n\n" % pkg_dic[pkg]["FILES"])
Patrick Williamsc124f4f2015-09-15 14:41:29 -050099
100 for lic in pkg_dic[pkg]["LICENSES"]:
101 lic_file = os.path.join(d.getVar('LICENSE_DIRECTORY', True),
102 pkg_dic[pkg]["PN"], "generic_%s" %
103 re.sub('\+', '', lic))
104 # add explicity avoid of CLOSED license because isn't generic
105 if lic == "CLOSED":
106 continue
107
108 if not os.path.exists(lic_file):
109 bb.warn("The license listed %s was not in the "\
110 "licenses collected for recipe %s"
111 % (lic, pkg_dic[pkg]["PN"]))
112
113 # Two options here:
114 # - Just copy the manifest
115 # - Copy the manifest and the license directories
116 # With both options set we see a .5 M increase in core-image-minimal
117 copy_lic_manifest = d.getVar('COPY_LIC_MANIFEST', True)
118 copy_lic_dirs = d.getVar('COPY_LIC_DIRS', True)
119 if copy_lic_manifest == "1":
120 rootfs_license_dir = os.path.join(d.getVar('IMAGE_ROOTFS', 'True'),
121 'usr', 'share', 'common-licenses')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500122 bb.utils.mkdirhier(rootfs_license_dir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500123 rootfs_license_manifest = os.path.join(rootfs_license_dir,
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500124 os.path.split(license_manifest)[1])
125 if not os.path.exists(rootfs_license_manifest):
126 os.link(license_manifest, rootfs_license_manifest)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500127
128 if copy_lic_dirs == "1":
129 for pkg in sorted(pkg_dic):
130 pkg_rootfs_license_dir = os.path.join(rootfs_license_dir, pkg)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500131 bb.utils.mkdirhier(pkg_rootfs_license_dir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500132 pkg_license_dir = os.path.join(d.getVar('LICENSE_DIRECTORY', True),
133 pkg_dic[pkg]["PN"])
134 licenses = os.listdir(pkg_license_dir)
135 for lic in licenses:
136 rootfs_license = os.path.join(rootfs_license_dir, lic)
137 pkg_license = os.path.join(pkg_license_dir, lic)
138 pkg_rootfs_license = os.path.join(pkg_rootfs_license_dir, lic)
139
140 if re.match("^generic_.*$", lic):
141 generic_lic = re.search("^generic_(.*)$", lic).group(1)
142 if oe.license.license_ok(canonical_license(d,
143 generic_lic), bad_licenses) == False:
144 continue
145
146 if not os.path.exists(rootfs_license):
147 os.link(pkg_license, rootfs_license)
148
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500149 if not os.path.exists(pkg_rootfs_license):
150 os.symlink(os.path.join('..', lic), pkg_rootfs_license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500151 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500152 if (oe.license.license_ok(canonical_license(d,
153 lic), bad_licenses) == False or
154 os.path.exists(pkg_rootfs_license)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500155 continue
156
157 os.link(pkg_license, pkg_rootfs_license)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500158
159
160def license_deployed_manifest(d):
161 """
162 Write the license manifest for the deployed recipes.
163 The deployed recipes usually includes the bootloader
164 and extra files to boot the target.
165 """
166
167 dep_dic = {}
168 man_dic = {}
169 lic_dir = d.getVar("LICENSE_DIRECTORY", True)
170
171 dep_dic = get_deployed_dependencies(d)
172 for dep in dep_dic.keys():
173 man_dic[dep] = {}
174 # It is necessary to mark this will be used for image manifest
175 man_dic[dep]["IMAGE_MANIFEST"] = True
176 man_dic[dep]["PN"] = dep
177 man_dic[dep]["FILES"] = \
178 " ".join(get_deployed_files(dep_dic[dep]))
179 with open(os.path.join(lic_dir, dep, "recipeinfo"), "r") as f:
180 for line in f.readlines():
181 key,val = line.split(": ", 1)
182 man_dic[dep][key] = val[:-1]
183
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600184 lic_manifest_dir = os.path.join(d.getVar('LICENSE_DIRECTORY', True),
185 d.getVar('IMAGE_NAME', True))
186 bb.utils.mkdirhier(lic_manifest_dir)
187 image_license_manifest = os.path.join(lic_manifest_dir, 'image_license.manifest')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500188 write_license_files(d, image_license_manifest, man_dic)
189
190def get_deployed_dependencies(d):
191 """
192 Get all the deployed dependencies of an image
193 """
194
195 deploy = {}
196 # Get all the dependencies for the current task (rootfs).
197 # Also get EXTRA_IMAGEDEPENDS because the bootloader is
198 # usually in this var and not listed in rootfs.
199 # At last, get the dependencies from boot classes because
200 # it might contain the bootloader.
201 taskdata = d.getVar("BB_TASKDEPDATA", False)
202 depends = list(set([dep[0] for dep
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600203 in list(taskdata.values())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500204 if not dep[0].endswith("-native")]))
205 extra_depends = d.getVar("EXTRA_IMAGEDEPENDS", True)
206 boot_depends = get_boot_dependencies(d)
207 depends.extend(extra_depends.split())
208 depends.extend(boot_depends)
209 depends = list(set(depends))
210
211 # To verify what was deployed it checks the rootfs dependencies against
212 # the SSTATE_MANIFESTS for "deploy" task.
213 # The manifest file name contains the arch. Because we are not running
214 # in the recipe context it is necessary to check every arch used.
215 sstate_manifest_dir = d.getVar("SSTATE_MANIFESTS", True)
216 sstate_archs = d.getVar("SSTATE_ARCHS", True)
217 extra_archs = d.getVar("PACKAGE_EXTRA_ARCHS", True)
218 archs = list(set(("%s %s" % (sstate_archs, extra_archs)).split()))
219 for dep in depends:
220 # Some recipes have an arch on their own, so we try that first.
221 special_arch = d.getVar("PACKAGE_ARCH_pn-%s" % dep, True)
222 if special_arch:
223 sstate_manifest_file = os.path.join(sstate_manifest_dir,
224 "manifest-%s-%s.deploy" % (special_arch, dep))
225 if os.path.exists(sstate_manifest_file):
226 deploy[dep] = sstate_manifest_file
227 continue
228
229 for arch in archs:
230 sstate_manifest_file = os.path.join(sstate_manifest_dir,
231 "manifest-%s-%s.deploy" % (arch, dep))
232 if os.path.exists(sstate_manifest_file):
233 deploy[dep] = sstate_manifest_file
234 break
235
236 return deploy
237get_deployed_dependencies[vardepsexclude] = "BB_TASKDEPDATA"
238
239def get_boot_dependencies(d):
240 """
241 Return the dependencies from boot tasks
242 """
243
244 depends = []
245 boot_depends_string = ""
246 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
247 # Only bootimg and bootdirectdisk include the depends flag
248 boot_tasks = ["do_bootimg", "do_bootdirectdisk",]
249
250 for task in boot_tasks:
251 boot_depends_string = "%s %s" % (boot_depends_string,
252 d.getVarFlag(task, "depends", True) or "")
253 boot_depends = [dep.split(":")[0] for dep
254 in boot_depends_string.split()
255 if not dep.split(":")[0].endswith("-native")]
256 for dep in boot_depends:
257 info_file = os.path.join(d.getVar("LICENSE_DIRECTORY", True),
258 dep, "recipeinfo")
259 # If the recipe and dependency name is the same
260 if os.path.exists(info_file):
261 depends.append(dep)
262 # We need to search for the provider of the dependency
263 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600264 for taskdep in taskdepdata.values():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500265 # The fifth field contains what the task provides
266 if dep in taskdep[4]:
267 info_file = os.path.join(
268 d.getVar("LICENSE_DIRECTORY", True),
269 taskdep[0], "recipeinfo")
270 if os.path.exists(info_file):
271 depends.append(taskdep[0])
272 break
273 return depends
274get_boot_dependencies[vardepsexclude] = "BB_TASKDEPDATA"
275
276def get_deployed_files(man_file):
277 """
278 Get the files deployed from the sstate manifest
279 """
280
281 dep_files = []
282 excluded_files = ["README_-_DO_NOT_DELETE_FILES_IN_THIS_DIRECTORY.txt"]
283 with open(man_file, "r") as manifest:
284 all_files = manifest.read()
285 for f in all_files.splitlines():
286 if ((not (os.path.islink(f) or os.path.isdir(f))) and
287 not os.path.basename(f) in excluded_files):
288 dep_files.append(os.path.basename(f))
289 return dep_files
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500290
291python do_populate_lic() {
292 """
293 Populate LICENSE_DIRECTORY with licenses.
294 """
295 lic_files_paths = find_license_files(d)
296
297 # The base directory we wrangle licenses to
298 destdir = os.path.join(d.getVar('LICSSTATEDIR', True), d.getVar('PN', True))
299 copy_license_files(lic_files_paths, destdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500300 info = get_recipe_info(d)
301 with open(os.path.join(destdir, "recipeinfo"), "w") as f:
302 for key in sorted(info.keys()):
303 f.write("%s: %s\n" % (key, info[key]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500304}
305
306# it would be better to copy them in do_install_append, but find_license_filesa is python
307python perform_packagecopy_prepend () {
308 enabled = oe.data.typed_value('LICENSE_CREATE_PACKAGE', d)
309 if d.getVar('CLASSOVERRIDE', True) == 'class-target' and enabled:
310 lic_files_paths = find_license_files(d)
311
312 # LICENSE_FILES_DIRECTORY starts with '/' so os.path.join cannot be used to join D and LICENSE_FILES_DIRECTORY
313 destdir = d.getVar('D', True) + os.path.join(d.getVar('LICENSE_FILES_DIRECTORY', True), d.getVar('PN', True))
314 copy_license_files(lic_files_paths, destdir)
315 add_package_and_files(d)
316}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500317perform_packagecopy[vardeps] += "LICENSE_CREATE_PACKAGE"
318
319def get_recipe_info(d):
320 info = {}
321 info["PV"] = d.getVar("PV", True)
322 info["PR"] = d.getVar("PR", True)
323 info["LICENSE"] = d.getVar("LICENSE", True)
324 return info
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500325
326def add_package_and_files(d):
327 packages = d.getVar('PACKAGES', True)
328 files = d.getVar('LICENSE_FILES_DIRECTORY', True)
329 pn = d.getVar('PN', True)
330 pn_lic = "%s%s" % (pn, d.getVar('LICENSE_PACKAGE_SUFFIX', False))
331 if pn_lic in packages:
332 bb.warn("%s package already existed in %s." % (pn_lic, pn))
333 else:
334 # first in PACKAGES to be sure that nothing else gets LICENSE_FILES_DIRECTORY
335 d.setVar('PACKAGES', "%s %s" % (pn_lic, packages))
336 d.setVar('FILES_' + pn_lic, files)
337 rrecommends_pn = d.getVar('RRECOMMENDS_' + pn, True)
338 if rrecommends_pn:
339 d.setVar('RRECOMMENDS_' + pn, "%s %s" % (pn_lic, rrecommends_pn))
340 else:
341 d.setVar('RRECOMMENDS_' + pn, "%s" % (pn_lic))
342
343def copy_license_files(lic_files_paths, destdir):
344 import shutil
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600345 import errno
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500346
347 bb.utils.mkdirhier(destdir)
348 for (basename, path) in lic_files_paths:
349 try:
350 src = path
351 dst = os.path.join(destdir, basename)
352 if os.path.exists(dst):
353 os.remove(dst)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600354 canlink = os.access(src, os.W_OK) and (os.stat(src).st_dev == os.stat(destdir).st_dev)
355 if canlink:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500356 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600357 os.link(src, dst)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500358 except OSError as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600359 if err.errno == errno.EXDEV:
360 # Copy license files if hard-link is not possible even if st_dev is the
361 # same on source and destination (docker container with device-mapper?)
362 canlink = False
363 else:
364 raise
365 try:
366 if canlink:
367 os.chown(dst,0,0)
368 except OSError as err:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500369 if err.errno in (errno.EPERM, errno.EINVAL):
370 # Suppress "Operation not permitted" error, as
371 # sometimes this function is not executed under pseudo.
372 # Also ignore "Invalid argument" errors that happen in
373 # some (unprivileged) container environments (no root).
374 pass
375 else:
376 raise
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600377 if not canlink:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500378 shutil.copyfile(src, dst)
379 except Exception as e:
380 bb.warn("Could not copy license file %s to %s: %s" % (src, dst, e))
381
382def find_license_files(d):
383 """
384 Creates list of files used in LIC_FILES_CHKSUM and generic LICENSE files.
385 """
386 import shutil
387 import oe.license
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600388 from collections import defaultdict, OrderedDict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500389
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500390 # All the license files for the package
391 lic_files = d.getVar('LIC_FILES_CHKSUM', True)
392 pn = d.getVar('PN', True)
393 # The license files are located in S/LIC_FILE_CHECKSUM.
394 srcdir = d.getVar('S', True)
395 # Directory we store the generic licenses as set in the distro configuration
396 generic_directory = d.getVar('COMMON_LICENSE_DIR', True)
397 # List of basename, path tuples
398 lic_files_paths = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600399 # Entries from LIC_FILES_CHKSUM
400 lic_chksums = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500401 license_source_dirs = []
402 license_source_dirs.append(generic_directory)
403 try:
404 additional_lic_dirs = d.getVar('LICENSE_PATH', True).split()
405 for lic_dir in additional_lic_dirs:
406 license_source_dirs.append(lic_dir)
407 except:
408 pass
409
410 class FindVisitor(oe.license.LicenseVisitor):
411 def visit_Str(self, node):
412 #
413 # Until I figure out what to do with
414 # the two modifiers I support (or greater = +
415 # and "with exceptions" being *
416 # we'll just strip out the modifier and put
417 # the base license.
418 find_license(node.s.replace("+", "").replace("*", ""))
419 self.generic_visit(node)
420
421 def find_license(license_type):
422 try:
423 bb.utils.mkdirhier(gen_lic_dest)
424 except:
425 pass
426 spdx_generic = None
427 license_source = None
428 # If the generic does not exist we need to check to see if there is an SPDX mapping to it,
429 # unless NO_GENERIC_LICENSE is set.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500430 for lic_dir in license_source_dirs:
431 if not os.path.isfile(os.path.join(lic_dir, license_type)):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500432 if d.getVarFlag('SPDXLICENSEMAP', license_type, True) != None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500433 # Great, there is an SPDXLICENSEMAP. We can copy!
434 bb.debug(1, "We need to use a SPDXLICENSEMAP for %s" % (license_type))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500435 spdx_generic = d.getVarFlag('SPDXLICENSEMAP', license_type, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500436 license_source = lic_dir
437 break
438 elif os.path.isfile(os.path.join(lic_dir, license_type)):
439 spdx_generic = license_type
440 license_source = lic_dir
441 break
442
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600443 non_generic_lic = d.getVarFlag('NO_GENERIC_LICENSE', license_type, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444 if spdx_generic and license_source:
445 # we really should copy to generic_ + spdx_generic, however, that ends up messing the manifest
446 # audit up. This should be fixed in emit_pkgdata (or, we actually got and fix all the recipes)
447
448 lic_files_paths.append(("generic_" + license_type, os.path.join(license_source, spdx_generic)))
449
450 # The user may attempt to use NO_GENERIC_LICENSE for a generic license which doesn't make sense
451 # and should not be allowed, warn the user in this case.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500452 if d.getVarFlag('NO_GENERIC_LICENSE', license_type, True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500453 bb.warn("%s: %s is a generic license, please don't use NO_GENERIC_LICENSE for it." % (pn, license_type))
454
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600455 elif non_generic_lic and non_generic_lic in lic_chksums:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500456 # if NO_GENERIC_LICENSE is set, we copy the license files from the fetched source
457 # of the package rather than the license_source_dirs.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600458 lic_files_paths.append(("generic_" + license_type,
459 os.path.join(srcdir, non_generic_lic)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500460 else:
461 # Add explicity avoid of CLOSED license because this isn't generic
462 if license_type != 'CLOSED':
463 # And here is where we warn people that their licenses are lousy
464 bb.warn("%s: No generic license file exists for: %s in any provider" % (pn, license_type))
465 pass
466
467 if not generic_directory:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600468 bb.fatal("COMMON_LICENSE_DIR is unset. Please set this in your distro config")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500469
470 if not lic_files:
471 # No recipe should have an invalid license file. This is checked else
472 # where, but let's be pedantic
473 bb.note(pn + ": Recipe file does not have license file information.")
474 return lic_files_paths
475
476 for url in lic_files.split():
477 try:
478 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
479 except bb.fetch.MalformedUrl:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600480 bb.fatal("%s: LIC_FILES_CHKSUM contains an invalid URL: %s" % (d.getVar('PF', True), url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500481 # We want the license filename and path
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600482 chksum = parm['md5'] if 'md5' in parm else parm['sha256']
483 lic_chksums[path] = chksum
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500484
485 v = FindVisitor()
486 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600487 v.visit_string(d.getVar('LICENSE', True))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500488 except oe.license.InvalidLicense as exc:
489 bb.fatal('%s: %s' % (d.getVar('PF', True), exc))
490 except SyntaxError:
491 bb.warn("%s: Failed to parse it's LICENSE field." % (d.getVar('PF', True)))
492
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600493 # Add files from LIC_FILES_CHKSUM to list of license files
494 lic_chksum_paths = defaultdict(OrderedDict)
495 for path, chksum in lic_chksums.items():
496 lic_chksum_paths[os.path.basename(path)][chksum] = os.path.join(srcdir, path)
497 for basename, files in lic_chksum_paths.items():
498 if len(files) == 1:
499 lic_files_paths.append((basename, list(files.values())[0]))
500 else:
501 # If there are multiple different license files with identical
502 # basenames we rename them to <file>.0, <file>.1, ...
503 for i, path in enumerate(files.values()):
504 lic_files_paths.append(("%s.%d" % (basename, i), path))
505
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500506 return lic_files_paths
507
508def return_spdx(d, license):
509 """
510 This function returns the spdx mapping of a license if it exists.
511 """
512 return d.getVarFlag('SPDXLICENSEMAP', license, True)
513
514def canonical_license(d, license):
515 """
516 Return the canonical (SPDX) form of the license if available (so GPLv3
517 becomes GPL-3.0), for the license named 'X+', return canonical form of
518 'X' if availabel and the tailing '+' (so GPLv3+ becomes GPL-3.0+),
519 or the passed license if there is no canonical form.
520 """
521 lic = d.getVarFlag('SPDXLICENSEMAP', license, True) or ""
522 if not lic and license.endswith('+'):
523 lic = d.getVarFlag('SPDXLICENSEMAP', license.rstrip('+'), True)
524 if lic:
525 lic += '+'
526 return lic or license
527
528def expand_wildcard_licenses(d, wildcard_licenses):
529 """
530 Return actual spdx format license names if wildcard used. We expand
531 wildcards from SPDXLICENSEMAP flags and SRC_DISTRIBUTE_LICENSES values.
532 """
533 import fnmatch
534 licenses = []
535 spdxmapkeys = d.getVarFlags('SPDXLICENSEMAP').keys()
536 for wld_lic in wildcard_licenses:
537 spdxflags = fnmatch.filter(spdxmapkeys, wld_lic)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500538 licenses += [d.getVarFlag('SPDXLICENSEMAP', flag, True) for flag in spdxflags]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500539
540 spdx_lics = (d.getVar('SRC_DISTRIBUTE_LICENSES', False) or '').split()
541 for wld_lic in wildcard_licenses:
542 licenses += fnmatch.filter(spdx_lics, wld_lic)
543
544 licenses = list(set(licenses))
545 return licenses
546
547def incompatible_license_contains(license, truevalue, falsevalue, d):
548 license = canonical_license(d, license)
549 bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE', True) or "").split()
550 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
551 return truevalue if license in bad_licenses else falsevalue
552
553def incompatible_license(d, dont_want_licenses, package=None):
554 """
555 This function checks if a recipe has only incompatible licenses. It also
556 take into consideration 'or' operand. dont_want_licenses should be passed
557 as canonical (SPDX) names.
558 """
559 import oe.license
560 license = d.getVar("LICENSE_%s" % package, True) if package else None
561 if not license:
562 license = d.getVar('LICENSE', True)
563
564 # Handles an "or" or two license sets provided by
565 # flattened_licenses(), pick one that works if possible.
566 def choose_lic_set(a, b):
567 return a if all(oe.license.license_ok(canonical_license(d, lic),
568 dont_want_licenses) for lic in a) else b
569
570 try:
571 licenses = oe.license.flattened_licenses(license, choose_lic_set)
572 except oe.license.LicenseError as exc:
573 bb.fatal('%s: %s' % (d.getVar('P', True), exc))
574 return any(not oe.license.license_ok(canonical_license(d, l), \
575 dont_want_licenses) for l in licenses)
576
577def check_license_flags(d):
578 """
579 This function checks if a recipe has any LICENSE_FLAGS that
580 aren't whitelisted.
581
582 If it does, it returns the first LICENSE_FLAGS item missing from the
583 whitelist, or all of the LICENSE_FLAGS if there is no whitelist.
584
585 If everything is is properly whitelisted, it returns None.
586 """
587
588 def license_flag_matches(flag, whitelist, pn):
589 """
590 Return True if flag matches something in whitelist, None if not.
591
592 Before we test a flag against the whitelist, we append _${PN}
593 to it. We then try to match that string against the
594 whitelist. This covers the normal case, where we expect
595 LICENSE_FLAGS to be a simple string like 'commercial', which
596 the user typically matches exactly in the whitelist by
597 explicitly appending the package name e.g 'commercial_foo'.
598 If we fail the match however, we then split the flag across
599 '_' and append each fragment and test until we either match or
600 run out of fragments.
601 """
602 flag_pn = ("%s_%s" % (flag, pn))
603 for candidate in whitelist:
604 if flag_pn == candidate:
605 return True
606
607 flag_cur = ""
608 flagments = flag_pn.split("_")
609 flagments.pop() # we've already tested the full string
610 for flagment in flagments:
611 if flag_cur:
612 flag_cur += "_"
613 flag_cur += flagment
614 for candidate in whitelist:
615 if flag_cur == candidate:
616 return True
617 return False
618
619 def all_license_flags_match(license_flags, whitelist):
620 """ Return first unmatched flag, None if all flags match """
621 pn = d.getVar('PN', True)
622 split_whitelist = whitelist.split()
623 for flag in license_flags.split():
624 if not license_flag_matches(flag, split_whitelist, pn):
625 return flag
626 return None
627
628 license_flags = d.getVar('LICENSE_FLAGS', True)
629 if license_flags:
630 whitelist = d.getVar('LICENSE_FLAGS_WHITELIST', True)
631 if not whitelist:
632 return license_flags
633 unmatched_flag = all_license_flags_match(license_flags, whitelist)
634 if unmatched_flag:
635 return unmatched_flag
636 return None
637
638def check_license_format(d):
639 """
640 This function checks if LICENSE is well defined,
641 Validate operators in LICENSES.
642 No spaces are allowed between LICENSES.
643 """
644 pn = d.getVar('PN', True)
645 licenses = d.getVar('LICENSE', True)
646 from oe.license import license_operator, license_operator_chars, license_pattern
647
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600648 elements = list(filter(lambda x: x.strip(), license_operator.split(licenses)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500649 for pos, element in enumerate(elements):
650 if license_pattern.match(element):
651 if pos > 0 and license_pattern.match(elements[pos - 1]):
652 bb.warn('%s: LICENSE value "%s" has an invalid format - license names ' \
653 'must be separated by the following characters to indicate ' \
654 'the license selection: %s' %
655 (pn, licenses, license_operator_chars))
656 elif not license_operator.match(element):
657 bb.warn('%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \
658 'in the valid list of separators (%s)' %
659 (pn, licenses, element, license_operator_chars))
660
661SSTATETASKS += "do_populate_lic"
662do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
663do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
664
665ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest; license_create_manifest; "
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500666do_rootfs[recrdeptask] += "do_populate_lic"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500667
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500668IMAGE_POSTPROCESS_COMMAND_prepend = "write_deploy_manifest; "
669do_image[recrdeptask] += "do_populate_lic"
670
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500671python do_populate_lic_setscene () {
672 sstate_setscene(d)
673}
674addtask do_populate_lic_setscene