blob: b1fffe70fe36bab1a470f4c9e48b49d06a90f3e4 [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
Brad Bishop6e60e8b2018-02-01 10:27:11 -050040 build_images_from_feeds = d.getVar('BUILD_IMAGES_FROM_FEEDS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041 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)):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050046 pkg_info = os.path.join(d.getVar('PKGDATA_DIR'),
Patrick Williamsc124f4f2015-09-15 14:41:29 -050047 '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
Brad Bishop6e60e8b2018-02-01 10:27:11 -050055 rootfs_license_manifest = os.path.join(d.getVar('LICENSE_DIRECTORY'),
56 d.getVar('IMAGE_NAME'), '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
Brad Bishop6e60e8b2018-02-01 10:27:11 -050063 bad_licenses = (d.getVar("INCOMPATIBLE_LICENSE") or "").split()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050064 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:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050075 bb.fatal('%s: %s' % (d.getVar('P'), exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050076 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"]:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500101 lic_file = os.path.join(d.getVar('LICENSE_DIRECTORY'),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500102 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
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500117 copy_lic_manifest = d.getVar('COPY_LIC_MANIFEST')
118 copy_lic_dirs = d.getVar('COPY_LIC_DIRS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500119 if copy_lic_manifest == "1":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500120 rootfs_license_dir = os.path.join(d.getVar('IMAGE_ROOTFS'),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121 '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)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500132 pkg_license_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500133 pkg_dic[pkg]["PN"])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500134
135 pkg_manifest_licenses = [canonical_license(d, lic) \
136 for lic in pkg_dic[pkg]["LICENSES"]]
137
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500138 licenses = os.listdir(pkg_license_dir)
139 for lic in licenses:
140 rootfs_license = os.path.join(rootfs_license_dir, lic)
141 pkg_license = os.path.join(pkg_license_dir, lic)
142 pkg_rootfs_license = os.path.join(pkg_rootfs_license_dir, lic)
143
144 if re.match("^generic_.*$", lic):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500145 generic_lic = canonical_license(d,
146 re.search("^generic_(.*)$", lic).group(1))
147
148 # Do not copy generic license into package if isn't
149 # declared into LICENSES of the package.
150 if not re.sub('\+$', '', generic_lic) in \
151 [re.sub('\+', '', lic) for lic in \
152 pkg_manifest_licenses]:
153 continue
154
155 if oe.license.license_ok(generic_lic,
156 bad_licenses) == False:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157 continue
158
159 if not os.path.exists(rootfs_license):
160 os.link(pkg_license, rootfs_license)
161
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500162 if not os.path.exists(pkg_rootfs_license):
163 os.symlink(os.path.join('..', lic), pkg_rootfs_license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500164 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500165 if (oe.license.license_ok(canonical_license(d,
166 lic), bad_licenses) == False or
167 os.path.exists(pkg_rootfs_license)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500168 continue
169
170 os.link(pkg_license, pkg_rootfs_license)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500171
172
173def license_deployed_manifest(d):
174 """
175 Write the license manifest for the deployed recipes.
176 The deployed recipes usually includes the bootloader
177 and extra files to boot the target.
178 """
179
180 dep_dic = {}
181 man_dic = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500182 lic_dir = d.getVar("LICENSE_DIRECTORY")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500183
184 dep_dic = get_deployed_dependencies(d)
185 for dep in dep_dic.keys():
186 man_dic[dep] = {}
187 # It is necessary to mark this will be used for image manifest
188 man_dic[dep]["IMAGE_MANIFEST"] = True
189 man_dic[dep]["PN"] = dep
190 man_dic[dep]["FILES"] = \
191 " ".join(get_deployed_files(dep_dic[dep]))
192 with open(os.path.join(lic_dir, dep, "recipeinfo"), "r") as f:
193 for line in f.readlines():
194 key,val = line.split(": ", 1)
195 man_dic[dep][key] = val[:-1]
196
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500197 lic_manifest_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
198 d.getVar('IMAGE_NAME'))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600199 bb.utils.mkdirhier(lic_manifest_dir)
200 image_license_manifest = os.path.join(lic_manifest_dir, 'image_license.manifest')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500201 write_license_files(d, image_license_manifest, man_dic)
202
203def get_deployed_dependencies(d):
204 """
205 Get all the deployed dependencies of an image
206 """
207
208 deploy = {}
209 # Get all the dependencies for the current task (rootfs).
210 # Also get EXTRA_IMAGEDEPENDS because the bootloader is
211 # usually in this var and not listed in rootfs.
212 # At last, get the dependencies from boot classes because
213 # it might contain the bootloader.
214 taskdata = d.getVar("BB_TASKDEPDATA", False)
215 depends = list(set([dep[0] for dep
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600216 in list(taskdata.values())
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500217 if not dep[0].endswith("-native")]))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500218 extra_depends = d.getVar("EXTRA_IMAGEDEPENDS")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500219 boot_depends = get_boot_dependencies(d)
220 depends.extend(extra_depends.split())
221 depends.extend(boot_depends)
222 depends = list(set(depends))
223
224 # To verify what was deployed it checks the rootfs dependencies against
225 # the SSTATE_MANIFESTS for "deploy" task.
226 # The manifest file name contains the arch. Because we are not running
227 # in the recipe context it is necessary to check every arch used.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500228 sstate_manifest_dir = d.getVar("SSTATE_MANIFESTS")
229 sstate_archs = d.getVar("SSTATE_ARCHS")
230 extra_archs = d.getVar("PACKAGE_EXTRA_ARCHS")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500231 archs = list(set(("%s %s" % (sstate_archs, extra_archs)).split()))
232 for dep in depends:
233 # Some recipes have an arch on their own, so we try that first.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500234 special_arch = d.getVar("PACKAGE_ARCH_pn-%s" % dep)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500235 if special_arch:
236 sstate_manifest_file = os.path.join(sstate_manifest_dir,
237 "manifest-%s-%s.deploy" % (special_arch, dep))
238 if os.path.exists(sstate_manifest_file):
239 deploy[dep] = sstate_manifest_file
240 continue
241
242 for arch in archs:
243 sstate_manifest_file = os.path.join(sstate_manifest_dir,
244 "manifest-%s-%s.deploy" % (arch, dep))
245 if os.path.exists(sstate_manifest_file):
246 deploy[dep] = sstate_manifest_file
247 break
248
249 return deploy
250get_deployed_dependencies[vardepsexclude] = "BB_TASKDEPDATA"
251
252def get_boot_dependencies(d):
253 """
254 Return the dependencies from boot tasks
255 """
256
257 depends = []
258 boot_depends_string = ""
259 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
260 # Only bootimg and bootdirectdisk include the depends flag
261 boot_tasks = ["do_bootimg", "do_bootdirectdisk",]
262
263 for task in boot_tasks:
264 boot_depends_string = "%s %s" % (boot_depends_string,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500265 d.getVarFlag(task, "depends") or "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500266 boot_depends = [dep.split(":")[0] for dep
267 in boot_depends_string.split()
268 if not dep.split(":")[0].endswith("-native")]
269 for dep in boot_depends:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500270 info_file = os.path.join(d.getVar("LICENSE_DIRECTORY"),
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500271 dep, "recipeinfo")
272 # If the recipe and dependency name is the same
273 if os.path.exists(info_file):
274 depends.append(dep)
275 # We need to search for the provider of the dependency
276 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600277 for taskdep in taskdepdata.values():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500278 # The fifth field contains what the task provides
279 if dep in taskdep[4]:
280 info_file = os.path.join(
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500281 d.getVar("LICENSE_DIRECTORY"),
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500282 taskdep[0], "recipeinfo")
283 if os.path.exists(info_file):
284 depends.append(taskdep[0])
285 break
286 return depends
287get_boot_dependencies[vardepsexclude] = "BB_TASKDEPDATA"
288
289def get_deployed_files(man_file):
290 """
291 Get the files deployed from the sstate manifest
292 """
293
294 dep_files = []
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500295 excluded_files = []
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500296 with open(man_file, "r") as manifest:
297 all_files = manifest.read()
298 for f in all_files.splitlines():
299 if ((not (os.path.islink(f) or os.path.isdir(f))) and
300 not os.path.basename(f) in excluded_files):
301 dep_files.append(os.path.basename(f))
302 return dep_files
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500303
304python do_populate_lic() {
305 """
306 Populate LICENSE_DIRECTORY with licenses.
307 """
308 lic_files_paths = find_license_files(d)
309
310 # The base directory we wrangle licenses to
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500311 destdir = os.path.join(d.getVar('LICSSTATEDIR'), d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500312 copy_license_files(lic_files_paths, destdir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500313 info = get_recipe_info(d)
314 with open(os.path.join(destdir, "recipeinfo"), "w") as f:
315 for key in sorted(info.keys()):
316 f.write("%s: %s\n" % (key, info[key]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500317}
318
319# it would be better to copy them in do_install_append, but find_license_filesa is python
320python perform_packagecopy_prepend () {
321 enabled = oe.data.typed_value('LICENSE_CREATE_PACKAGE', d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500322 if d.getVar('CLASSOVERRIDE') == 'class-target' and enabled:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500323 lic_files_paths = find_license_files(d)
324
325 # 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 -0500326 destdir = d.getVar('D') + os.path.join(d.getVar('LICENSE_FILES_DIRECTORY'), d.getVar('PN'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500327 copy_license_files(lic_files_paths, destdir)
328 add_package_and_files(d)
329}
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500330perform_packagecopy[vardeps] += "LICENSE_CREATE_PACKAGE"
331
332def get_recipe_info(d):
333 info = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500334 info["PV"] = d.getVar("PV")
335 info["PR"] = d.getVar("PR")
336 info["LICENSE"] = d.getVar("LICENSE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500337 return info
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500338
339def add_package_and_files(d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500340 packages = d.getVar('PACKAGES')
341 files = d.getVar('LICENSE_FILES_DIRECTORY')
342 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500343 pn_lic = "%s%s" % (pn, d.getVar('LICENSE_PACKAGE_SUFFIX', False))
344 if pn_lic in packages:
345 bb.warn("%s package already existed in %s." % (pn_lic, pn))
346 else:
347 # first in PACKAGES to be sure that nothing else gets LICENSE_FILES_DIRECTORY
348 d.setVar('PACKAGES', "%s %s" % (pn_lic, packages))
349 d.setVar('FILES_' + pn_lic, files)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500350 rrecommends_pn = d.getVar('RRECOMMENDS_' + pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500351 if rrecommends_pn:
352 d.setVar('RRECOMMENDS_' + pn, "%s %s" % (pn_lic, rrecommends_pn))
353 else:
354 d.setVar('RRECOMMENDS_' + pn, "%s" % (pn_lic))
355
356def copy_license_files(lic_files_paths, destdir):
357 import shutil
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600358 import errno
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500359
360 bb.utils.mkdirhier(destdir)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500361 for (basename, path, beginline, endline) in lic_files_paths:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500362 try:
363 src = path
364 dst = os.path.join(destdir, basename)
365 if os.path.exists(dst):
366 os.remove(dst)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500367 if os.path.islink(src):
368 src = os.path.realpath(src)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500369 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 -0600370 if canlink:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500371 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600372 os.link(src, dst)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500373 except OSError as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600374 if err.errno == errno.EXDEV:
375 # Copy license files if hard-link is not possible even if st_dev is the
376 # same on source and destination (docker container with device-mapper?)
377 canlink = False
378 else:
379 raise
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500380 # Only chown if we did hardling, and, we're running under pseudo
381 if canlink and os.environ.get('PSEUDO_DISABLED') == '0':
382 os.chown(dst,0,0)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600383 if not canlink:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500384 begin_idx = int(beginline)-1 if beginline is not None else None
385 end_idx = int(endline) if endline is not None else None
386 if begin_idx is None and end_idx is None:
387 shutil.copyfile(src, dst)
388 else:
389 with open(src, 'rb') as src_f:
390 with open(dst, 'wb') as dst_f:
391 dst_f.write(b''.join(src_f.readlines()[begin_idx:end_idx]))
392
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500393 except Exception as e:
394 bb.warn("Could not copy license file %s to %s: %s" % (src, dst, e))
395
396def find_license_files(d):
397 """
398 Creates list of files used in LIC_FILES_CHKSUM and generic LICENSE files.
399 """
400 import shutil
401 import oe.license
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600402 from collections import defaultdict, OrderedDict
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500404 # All the license files for the package
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500405 lic_files = d.getVar('LIC_FILES_CHKSUM') or ""
406 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500407 # The license files are located in S/LIC_FILE_CHECKSUM.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500408 srcdir = d.getVar('S')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500409 # Directory we store the generic licenses as set in the distro configuration
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500410 generic_directory = d.getVar('COMMON_LICENSE_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500411 # List of basename, path tuples
412 lic_files_paths = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500413 # hash for keep track generic lics mappings
414 non_generic_lics = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600415 # Entries from LIC_FILES_CHKSUM
416 lic_chksums = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500417 license_source_dirs = []
418 license_source_dirs.append(generic_directory)
419 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500420 additional_lic_dirs = d.getVar('LICENSE_PATH').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500421 for lic_dir in additional_lic_dirs:
422 license_source_dirs.append(lic_dir)
423 except:
424 pass
425
426 class FindVisitor(oe.license.LicenseVisitor):
427 def visit_Str(self, node):
428 #
429 # Until I figure out what to do with
430 # the two modifiers I support (or greater = +
431 # and "with exceptions" being *
432 # we'll just strip out the modifier and put
433 # the base license.
434 find_license(node.s.replace("+", "").replace("*", ""))
435 self.generic_visit(node)
436
437 def find_license(license_type):
438 try:
439 bb.utils.mkdirhier(gen_lic_dest)
440 except:
441 pass
442 spdx_generic = None
443 license_source = None
444 # If the generic does not exist we need to check to see if there is an SPDX mapping to it,
445 # unless NO_GENERIC_LICENSE is set.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500446 for lic_dir in license_source_dirs:
447 if not os.path.isfile(os.path.join(lic_dir, license_type)):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500448 if d.getVarFlag('SPDXLICENSEMAP', license_type) != None:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500449 # Great, there is an SPDXLICENSEMAP. We can copy!
450 bb.debug(1, "We need to use a SPDXLICENSEMAP for %s" % (license_type))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500451 spdx_generic = d.getVarFlag('SPDXLICENSEMAP', license_type)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500452 license_source = lic_dir
453 break
454 elif os.path.isfile(os.path.join(lic_dir, license_type)):
455 spdx_generic = license_type
456 license_source = lic_dir
457 break
458
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500459 non_generic_lic = d.getVarFlag('NO_GENERIC_LICENSE', license_type)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500460 if spdx_generic and license_source:
461 # we really should copy to generic_ + spdx_generic, however, that ends up messing the manifest
462 # audit up. This should be fixed in emit_pkgdata (or, we actually got and fix all the recipes)
463
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500464 lic_files_paths.append(("generic_" + license_type, os.path.join(license_source, spdx_generic),
465 None, None))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466
467 # The user may attempt to use NO_GENERIC_LICENSE for a generic license which doesn't make sense
468 # and should not be allowed, warn the user in this case.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500469 if d.getVarFlag('NO_GENERIC_LICENSE', license_type):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500470 bb.warn("%s: %s is a generic license, please don't use NO_GENERIC_LICENSE for it." % (pn, license_type))
471
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600472 elif non_generic_lic and non_generic_lic in lic_chksums:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500473 # if NO_GENERIC_LICENSE is set, we copy the license files from the fetched source
474 # of the package rather than the license_source_dirs.
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600475 lic_files_paths.append(("generic_" + license_type,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500476 os.path.join(srcdir, non_generic_lic), None, None))
477 non_generic_lics[non_generic_lic] = license_type
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500478 else:
479 # Add explicity avoid of CLOSED license because this isn't generic
480 if license_type != 'CLOSED':
481 # And here is where we warn people that their licenses are lousy
482 bb.warn("%s: No generic license file exists for: %s in any provider" % (pn, license_type))
483 pass
484
485 if not generic_directory:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600486 bb.fatal("COMMON_LICENSE_DIR is unset. Please set this in your distro config")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500487
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500488 for url in lic_files.split():
489 try:
490 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
491 except bb.fetch.MalformedUrl:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500492 bb.fatal("%s: LIC_FILES_CHKSUM contains an invalid URL: %s" % (d.getVar('PF'), url))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500493 # We want the license filename and path
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500494 chksum = parm.get('md5', None)
495 beginline = parm.get('beginline')
496 endline = parm.get('endline')
497 lic_chksums[path] = (chksum, beginline, endline)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500498
499 v = FindVisitor()
500 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500501 v.visit_string(d.getVar('LICENSE'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500502 except oe.license.InvalidLicense as exc:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500503 bb.fatal('%s: %s' % (d.getVar('PF'), exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500504 except SyntaxError:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500505 bb.warn("%s: Failed to parse it's LICENSE field." % (d.getVar('PF')))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600506 # Add files from LIC_FILES_CHKSUM to list of license files
507 lic_chksum_paths = defaultdict(OrderedDict)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500508 for path, data in sorted(lic_chksums.items()):
509 lic_chksum_paths[os.path.basename(path)][data] = (os.path.join(srcdir, path), data[1], data[2])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600510 for basename, files in lic_chksum_paths.items():
511 if len(files) == 1:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500512 # Don't copy again a LICENSE already handled as non-generic
513 if basename in non_generic_lics:
514 continue
515 data = list(files.values())[0]
516 lic_files_paths.append(tuple([basename] + list(data)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600517 else:
518 # If there are multiple different license files with identical
519 # basenames we rename them to <file>.0, <file>.1, ...
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500520 for i, data in enumerate(files.values()):
521 lic_files_paths.append(tuple(["%s.%d" % (basename, i)] + list(data)))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600522
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500523 return lic_files_paths
524
525def return_spdx(d, license):
526 """
527 This function returns the spdx mapping of a license if it exists.
528 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500529 return d.getVarFlag('SPDXLICENSEMAP', license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500530
531def canonical_license(d, license):
532 """
533 Return the canonical (SPDX) form of the license if available (so GPLv3
534 becomes GPL-3.0), for the license named 'X+', return canonical form of
535 'X' if availabel and the tailing '+' (so GPLv3+ becomes GPL-3.0+),
536 or the passed license if there is no canonical form.
537 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500538 lic = d.getVarFlag('SPDXLICENSEMAP', license) or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500539 if not lic and license.endswith('+'):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500540 lic = d.getVarFlag('SPDXLICENSEMAP', license.rstrip('+'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500541 if lic:
542 lic += '+'
543 return lic or license
544
545def expand_wildcard_licenses(d, wildcard_licenses):
546 """
547 Return actual spdx format license names if wildcard used. We expand
548 wildcards from SPDXLICENSEMAP flags and SRC_DISTRIBUTE_LICENSES values.
549 """
550 import fnmatch
551 licenses = []
552 spdxmapkeys = d.getVarFlags('SPDXLICENSEMAP').keys()
553 for wld_lic in wildcard_licenses:
554 spdxflags = fnmatch.filter(spdxmapkeys, wld_lic)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500555 licenses += [d.getVarFlag('SPDXLICENSEMAP', flag) for flag in spdxflags]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500556
557 spdx_lics = (d.getVar('SRC_DISTRIBUTE_LICENSES', False) or '').split()
558 for wld_lic in wildcard_licenses:
559 licenses += fnmatch.filter(spdx_lics, wld_lic)
560
561 licenses = list(set(licenses))
562 return licenses
563
564def incompatible_license_contains(license, truevalue, falsevalue, d):
565 license = canonical_license(d, license)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500566 bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500567 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
568 return truevalue if license in bad_licenses else falsevalue
569
570def incompatible_license(d, dont_want_licenses, package=None):
571 """
572 This function checks if a recipe has only incompatible licenses. It also
573 take into consideration 'or' operand. dont_want_licenses should be passed
574 as canonical (SPDX) names.
575 """
576 import oe.license
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500577 license = d.getVar("LICENSE_%s" % package) if package else None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500578 if not license:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500579 license = d.getVar('LICENSE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500580
581 # Handles an "or" or two license sets provided by
582 # flattened_licenses(), pick one that works if possible.
583 def choose_lic_set(a, b):
584 return a if all(oe.license.license_ok(canonical_license(d, lic),
585 dont_want_licenses) for lic in a) else b
586
587 try:
588 licenses = oe.license.flattened_licenses(license, choose_lic_set)
589 except oe.license.LicenseError as exc:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500590 bb.fatal('%s: %s' % (d.getVar('P'), exc))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500591 return any(not oe.license.license_ok(canonical_license(d, l), \
592 dont_want_licenses) for l in licenses)
593
594def check_license_flags(d):
595 """
596 This function checks if a recipe has any LICENSE_FLAGS that
597 aren't whitelisted.
598
599 If it does, it returns the first LICENSE_FLAGS item missing from the
600 whitelist, or all of the LICENSE_FLAGS if there is no whitelist.
601
602 If everything is is properly whitelisted, it returns None.
603 """
604
605 def license_flag_matches(flag, whitelist, pn):
606 """
607 Return True if flag matches something in whitelist, None if not.
608
609 Before we test a flag against the whitelist, we append _${PN}
610 to it. We then try to match that string against the
611 whitelist. This covers the normal case, where we expect
612 LICENSE_FLAGS to be a simple string like 'commercial', which
613 the user typically matches exactly in the whitelist by
614 explicitly appending the package name e.g 'commercial_foo'.
615 If we fail the match however, we then split the flag across
616 '_' and append each fragment and test until we either match or
617 run out of fragments.
618 """
619 flag_pn = ("%s_%s" % (flag, pn))
620 for candidate in whitelist:
621 if flag_pn == candidate:
622 return True
623
624 flag_cur = ""
625 flagments = flag_pn.split("_")
626 flagments.pop() # we've already tested the full string
627 for flagment in flagments:
628 if flag_cur:
629 flag_cur += "_"
630 flag_cur += flagment
631 for candidate in whitelist:
632 if flag_cur == candidate:
633 return True
634 return False
635
636 def all_license_flags_match(license_flags, whitelist):
637 """ Return first unmatched flag, None if all flags match """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500638 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500639 split_whitelist = whitelist.split()
640 for flag in license_flags.split():
641 if not license_flag_matches(flag, split_whitelist, pn):
642 return flag
643 return None
644
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500645 license_flags = d.getVar('LICENSE_FLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500646 if license_flags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500647 whitelist = d.getVar('LICENSE_FLAGS_WHITELIST')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500648 if not whitelist:
649 return license_flags
650 unmatched_flag = all_license_flags_match(license_flags, whitelist)
651 if unmatched_flag:
652 return unmatched_flag
653 return None
654
655def check_license_format(d):
656 """
657 This function checks if LICENSE is well defined,
658 Validate operators in LICENSES.
659 No spaces are allowed between LICENSES.
660 """
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500661 pn = d.getVar('PN')
662 licenses = d.getVar('LICENSE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500663 from oe.license import license_operator, license_operator_chars, license_pattern
664
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600665 elements = list(filter(lambda x: x.strip(), license_operator.split(licenses)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500666 for pos, element in enumerate(elements):
667 if license_pattern.match(element):
668 if pos > 0 and license_pattern.match(elements[pos - 1]):
669 bb.warn('%s: LICENSE value "%s" has an invalid format - license names ' \
670 'must be separated by the following characters to indicate ' \
671 'the license selection: %s' %
672 (pn, licenses, license_operator_chars))
673 elif not license_operator.match(element):
674 bb.warn('%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \
675 'in the valid list of separators (%s)' %
676 (pn, licenses, element, license_operator_chars))
677
678SSTATETASKS += "do_populate_lic"
679do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}"
680do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/"
681
682ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest; license_create_manifest; "
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500683do_rootfs[recrdeptask] += "do_populate_lic"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500685IMAGE_POSTPROCESS_COMMAND_prepend = "write_deploy_manifest; "
686do_image[recrdeptask] += "do_populate_lic"
687
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500688python do_populate_lic_setscene () {
689 sstate_setscene(d)
690}
691addtask do_populate_lic_setscene