blob: 721343d0f45f55f07d21a72cb7f1179ad021905c [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 = []
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500282 excluded_files = []
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500283 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)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500354 if os.path.islink(src):
355 src = os.path.realpath(src)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600356 canlink = os.access(src, os.W_OK) and (os.stat(src).st_dev == os.stat(destdir).st_dev)
357 if canlink:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500358 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600359 os.link(src, dst)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500360 except OSError as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600361 if err.errno == errno.EXDEV:
362 # Copy license files if hard-link is not possible even if st_dev is the
363 # same on source and destination (docker container with device-mapper?)
364 canlink = False
365 else:
366 raise
367 try:
368 if canlink:
369 os.chown(dst,0,0)
370 except OSError as err:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500371 if err.errno in (errno.EPERM, errno.EINVAL):
372 # Suppress "Operation not permitted" error, as
373 # sometimes this function is not executed under pseudo.
374 # Also ignore "Invalid argument" errors that happen in
375 # some (unprivileged) container environments (no root).
376 pass
377 else:
378 raise
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600379 if not canlink:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500380 shutil.copyfile(src, dst)
381 except Exception as e:
382 bb.warn("Could not copy license file %s to %s: %s" % (src, dst, e))
383
384def find_license_files(d):
385 """
386 Creates list of files used in LIC_FILES_CHKSUM and generic LICENSE files.
387 """
388 import shutil
389 import oe.license
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600390 from collections import defaultdict, OrderedDict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500391
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500392 # All the license files for the package
393 lic_files = d.getVar('LIC_FILES_CHKSUM', True)
394 pn = d.getVar('PN', True)
395 # The license files are located in S/LIC_FILE_CHECKSUM.
396 srcdir = d.getVar('S', True)
397 # Directory we store the generic licenses as set in the distro configuration
398 generic_directory = d.getVar('COMMON_LICENSE_DIR', True)
399 # List of basename, path tuples
400 lic_files_paths = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600401 # Entries from LIC_FILES_CHKSUM
402 lic_chksums = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403 license_source_dirs = []
404 license_source_dirs.append(generic_directory)
405 try:
406 additional_lic_dirs = d.getVar('LICENSE_PATH', True).split()
407 for lic_dir in additional_lic_dirs:
408 license_source_dirs.append(lic_dir)
409 except:
410 pass
411
412 class FindVisitor(oe.license.LicenseVisitor):
413 def visit_Str(self, node):
414 #
415 # Until I figure out what to do with
416 # the two modifiers I support (or greater = +
417 # and "with exceptions" being *
418 # we'll just strip out the modifier and put
419 # the base license.
420 find_license(node.s.replace("+", "").replace("*", ""))
421 self.generic_visit(node)
422
423 def find_license(license_type):
424 try:
425 bb.utils.mkdirhier(gen_lic_dest)
426 except:
427 pass
428 spdx_generic = None
429 license_source = None
430 # If the generic does not exist we need to check to see if there is an SPDX mapping to it,
431 # unless NO_GENERIC_LICENSE is set.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500432 for lic_dir in license_source_dirs:
433 if not os.path.isfile(os.path.join(lic_dir, license_type)):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500434 if d.getVarFlag('SPDXLICENSEMAP', license_type, True) != None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435 # Great, there is an SPDXLICENSEMAP. We can copy!
436 bb.debug(1, "We need to use a SPDXLICENSEMAP for %s" % (license_type))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500437 spdx_generic = d.getVarFlag('SPDXLICENSEMAP', license_type, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500438 license_source = lic_dir
439 break
440 elif os.path.isfile(os.path.join(lic_dir, license_type)):
441 spdx_generic = license_type
442 license_source = lic_dir
443 break
444
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600445 non_generic_lic = d.getVarFlag('NO_GENERIC_LICENSE', license_type, True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500446 if spdx_generic and license_source:
447 # we really should copy to generic_ + spdx_generic, however, that ends up messing the manifest
448 # audit up. This should be fixed in emit_pkgdata (or, we actually got and fix all the recipes)
449
450 lic_files_paths.append(("generic_" + license_type, os.path.join(license_source, spdx_generic)))
451
452 # The user may attempt to use NO_GENERIC_LICENSE for a generic license which doesn't make sense
453 # and should not be allowed, warn the user in this case.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500454 if d.getVarFlag('NO_GENERIC_LICENSE', license_type, True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500455 bb.warn("%s: %s is a generic license, please don't use NO_GENERIC_LICENSE for it." % (pn, license_type))
456
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600457 elif non_generic_lic and non_generic_lic in lic_chksums:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500458 # if NO_GENERIC_LICENSE is set, we copy the license files from the fetched source
459 # of the package rather than the license_source_dirs.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600460 lic_files_paths.append(("generic_" + license_type,
461 os.path.join(srcdir, non_generic_lic)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500462 else:
463 # Add explicity avoid of CLOSED license because this isn't generic
464 if license_type != 'CLOSED':
465 # And here is where we warn people that their licenses are lousy
466 bb.warn("%s: No generic license file exists for: %s in any provider" % (pn, license_type))
467 pass
468
469 if not generic_directory:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600470 bb.fatal("COMMON_LICENSE_DIR is unset. Please set this in your distro config")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500471
472 if not lic_files:
473 # No recipe should have an invalid license file. This is checked else
474 # where, but let's be pedantic
475 bb.note(pn + ": Recipe file does not have license file information.")
476 return lic_files_paths
477
478 for url in lic_files.split():
479 try:
480 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
481 except bb.fetch.MalformedUrl:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600482 bb.fatal("%s: LIC_FILES_CHKSUM contains an invalid URL: %s" % (d.getVar('PF', True), url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483 # We want the license filename and path
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600484 chksum = parm['md5'] if 'md5' in parm else parm['sha256']
485 lic_chksums[path] = chksum
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500486
487 v = FindVisitor()
488 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600489 v.visit_string(d.getVar('LICENSE', True))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500490 except oe.license.InvalidLicense as exc:
491 bb.fatal('%s: %s' % (d.getVar('PF', True), exc))
492 except SyntaxError:
493 bb.warn("%s: Failed to parse it's LICENSE field." % (d.getVar('PF', True)))
494
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600495 # Add files from LIC_FILES_CHKSUM to list of license files
496 lic_chksum_paths = defaultdict(OrderedDict)
497 for path, chksum in lic_chksums.items():
498 lic_chksum_paths[os.path.basename(path)][chksum] = os.path.join(srcdir, path)
499 for basename, files in lic_chksum_paths.items():
500 if len(files) == 1:
501 lic_files_paths.append((basename, list(files.values())[0]))
502 else:
503 # If there are multiple different license files with identical
504 # basenames we rename them to <file>.0, <file>.1, ...
505 for i, path in enumerate(files.values()):
506 lic_files_paths.append(("%s.%d" % (basename, i), path))
507
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500508 return lic_files_paths
509
510def return_spdx(d, license):
511 """
512 This function returns the spdx mapping of a license if it exists.
513 """
514 return d.getVarFlag('SPDXLICENSEMAP', license, True)
515
516def canonical_license(d, license):
517 """
518 Return the canonical (SPDX) form of the license if available (so GPLv3
519 becomes GPL-3.0), for the license named 'X+', return canonical form of
520 'X' if availabel and the tailing '+' (so GPLv3+ becomes GPL-3.0+),
521 or the passed license if there is no canonical form.
522 """
523 lic = d.getVarFlag('SPDXLICENSEMAP', license, True) or ""
524 if not lic and license.endswith('+'):
525 lic = d.getVarFlag('SPDXLICENSEMAP', license.rstrip('+'), True)
526 if lic:
527 lic += '+'
528 return lic or license
529
530def expand_wildcard_licenses(d, wildcard_licenses):
531 """
532 Return actual spdx format license names if wildcard used. We expand
533 wildcards from SPDXLICENSEMAP flags and SRC_DISTRIBUTE_LICENSES values.
534 """
535 import fnmatch
536 licenses = []
537 spdxmapkeys = d.getVarFlags('SPDXLICENSEMAP').keys()
538 for wld_lic in wildcard_licenses:
539 spdxflags = fnmatch.filter(spdxmapkeys, wld_lic)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500540 licenses += [d.getVarFlag('SPDXLICENSEMAP', flag, True) for flag in spdxflags]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500541
542 spdx_lics = (d.getVar('SRC_DISTRIBUTE_LICENSES', False) or '').split()
543 for wld_lic in wildcard_licenses:
544 licenses += fnmatch.filter(spdx_lics, wld_lic)
545
546 licenses = list(set(licenses))
547 return licenses
548
549def incompatible_license_contains(license, truevalue, falsevalue, d):
550 license = canonical_license(d, license)
551 bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE', True) or "").split()
552 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
553 return truevalue if license in bad_licenses else falsevalue
554
555def incompatible_license(d, dont_want_licenses, package=None):
556 """
557 This function checks if a recipe has only incompatible licenses. It also
558 take into consideration 'or' operand. dont_want_licenses should be passed
559 as canonical (SPDX) names.
560 """
561 import oe.license
562 license = d.getVar("LICENSE_%s" % package, True) if package else None
563 if not license:
564 license = d.getVar('LICENSE', True)
565
566 # Handles an "or" or two license sets provided by
567 # flattened_licenses(), pick one that works if possible.
568 def choose_lic_set(a, b):
569 return a if all(oe.license.license_ok(canonical_license(d, lic),
570 dont_want_licenses) for lic in a) else b
571
572 try:
573 licenses = oe.license.flattened_licenses(license, choose_lic_set)
574 except oe.license.LicenseError as exc:
575 bb.fatal('%s: %s' % (d.getVar('P', True), exc))
576 return any(not oe.license.license_ok(canonical_license(d, l), \
577 dont_want_licenses) for l in licenses)
578
579def check_license_flags(d):
580 """
581 This function checks if a recipe has any LICENSE_FLAGS that
582 aren't whitelisted.
583
584 If it does, it returns the first LICENSE_FLAGS item missing from the
585 whitelist, or all of the LICENSE_FLAGS if there is no whitelist.
586
587 If everything is is properly whitelisted, it returns None.
588 """
589
590 def license_flag_matches(flag, whitelist, pn):
591 """
592 Return True if flag matches something in whitelist, None if not.
593
594 Before we test a flag against the whitelist, we append _${PN}
595 to it. We then try to match that string against the
596 whitelist. This covers the normal case, where we expect
597 LICENSE_FLAGS to be a simple string like 'commercial', which
598 the user typically matches exactly in the whitelist by
599 explicitly appending the package name e.g 'commercial_foo'.
600 If we fail the match however, we then split the flag across
601 '_' and append each fragment and test until we either match or
602 run out of fragments.
603 """
604 flag_pn = ("%s_%s" % (flag, pn))
605 for candidate in whitelist:
606 if flag_pn == candidate:
607 return True
608
609 flag_cur = ""
610 flagments = flag_pn.split("_")
611 flagments.pop() # we've already tested the full string
612 for flagment in flagments:
613 if flag_cur:
614 flag_cur += "_"
615 flag_cur += flagment
616 for candidate in whitelist:
617 if flag_cur == candidate:
618 return True
619 return False
620
621 def all_license_flags_match(license_flags, whitelist):
622 """ Return first unmatched flag, None if all flags match """
623 pn = d.getVar('PN', True)
624 split_whitelist = whitelist.split()
625 for flag in license_flags.split():
626 if not license_flag_matches(flag, split_whitelist, pn):
627 return flag
628 return None
629
630 license_flags = d.getVar('LICENSE_FLAGS', True)
631 if license_flags:
632 whitelist = d.getVar('LICENSE_FLAGS_WHITELIST', True)
633 if not whitelist:
634 return license_flags
635 unmatched_flag = all_license_flags_match(license_flags, whitelist)
636 if unmatched_flag:
637 return unmatched_flag
638 return None
639
640def check_license_format(d):
641 """
642 This function checks if LICENSE is well defined,
643 Validate operators in LICENSES.
644 No spaces are allowed between LICENSES.
645 """
646 pn = d.getVar('PN', True)
647 licenses = d.getVar('LICENSE', True)
648 from oe.license import license_operator, license_operator_chars, license_pattern
649
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600650 elements = list(filter(lambda x: x.strip(), license_operator.split(licenses)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500651 for pos, element in enumerate(elements):
652 if license_pattern.match(element):
653 if pos > 0 and license_pattern.match(elements[pos - 1]):
654 bb.warn('%s: LICENSE value "%s" has an invalid format - license names ' \
655 'must be separated by the following characters to indicate ' \
656 'the license selection: %s' %
657 (pn, licenses, license_operator_chars))
658 elif not license_operator.match(element):
659 bb.warn('%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \
660 'in the valid list of separators (%s)' %
661 (pn, licenses, element, license_operator_chars))
662
663SSTATETASKS += "do_populate_lic"
664do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
665do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
666
667ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest; license_create_manifest; "
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500668do_rootfs[recrdeptask] += "do_populate_lic"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500669
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500670IMAGE_POSTPROCESS_COMMAND_prepend = "write_deploy_manifest; "
671do_image[recrdeptask] += "do_populate_lic"
672
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500673python do_populate_lic_setscene () {
674 sstate_setscene(d)
675}
676addtask do_populate_lic_setscene