blob: a8c72da3cbe7a8c242551dbcb7d5978752549a5d [file] [log] [blame]
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001python write_package_manifest() {
2 # Get list of installed packages
3 license_image_dir = d.expand('${LICENSE_DIRECTORY}/${IMAGE_NAME}')
4 bb.utils.mkdirhier(license_image_dir)
5 from oe.rootfs import image_list_installed_packages
6 from oe.utils import format_pkg_list
7
8 pkgs = image_list_installed_packages(d)
9 output = format_pkg_list(pkgs)
10 open(os.path.join(license_image_dir, 'package.manifest'),
11 'w+').write(output)
12}
13
14python license_create_manifest() {
15 import oe.packagedata
16 from oe.rootfs import image_list_installed_packages
17
18 build_images_from_feeds = d.getVar('BUILD_IMAGES_FROM_FEEDS')
19 if build_images_from_feeds == "1":
20 return 0
21
22 pkg_dic = {}
23 for pkg in sorted(image_list_installed_packages(d)):
24 pkg_info = os.path.join(d.getVar('PKGDATA_DIR'),
25 'runtime-reverse', pkg)
26 pkg_name = os.path.basename(os.readlink(pkg_info))
27
28 pkg_dic[pkg_name] = oe.packagedata.read_pkgdatafile(pkg_info)
29 if not "LICENSE" in pkg_dic[pkg_name].keys():
30 pkg_lic_name = "LICENSE_" + pkg_name
31 pkg_dic[pkg_name]["LICENSE"] = pkg_dic[pkg_name][pkg_lic_name]
32
33 rootfs_license_manifest = os.path.join(d.getVar('LICENSE_DIRECTORY'),
34 d.getVar('IMAGE_NAME'), 'license.manifest')
Brad Bishop19323692019-04-05 15:28:33 -040035 write_license_files(d, rootfs_license_manifest, pkg_dic, rootfs=True)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080036}
37
Brad Bishop19323692019-04-05 15:28:33 -040038def write_license_files(d, license_manifest, pkg_dic, rootfs=True):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080039 import re
Brad Bishop19323692019-04-05 15:28:33 -040040 import stat
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080041
42 bad_licenses = (d.getVar("INCOMPATIBLE_LICENSE") or "").split()
Brad Bishop15ae2502019-06-18 21:44:24 -040043 bad_licenses = [canonical_license(d, l) for l in bad_licenses]
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080044 bad_licenses = expand_wildcard_licenses(d, bad_licenses)
45
Brad Bishopf3f93bb2019-10-16 14:33:32 -040046 whitelist = []
47 for lic in bad_licenses:
48 whitelist.extend((d.getVar("WHITELIST_" + lic) or "").split())
49
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080050 with open(license_manifest, "w") as license_file:
51 for pkg in sorted(pkg_dic):
Brad Bishopf3f93bb2019-10-16 14:33:32 -040052 if bad_licenses and pkg not in whitelist:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080053 try:
Andrew Geissler82c905d2020-04-13 13:39:40 -050054 licenses = incompatible_pkg_license(d, bad_licenses, pkg_dic[pkg]["LICENSE"])
55 if licenses:
56 bb.fatal("Package %s cannot be installed into the image because it has incompatible license(s): %s" %(pkg, ' '.join(licenses)))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080057 (pkg_dic[pkg]["LICENSE"], pkg_dic[pkg]["LICENSES"]) = \
58 oe.license.manifest_licenses(pkg_dic[pkg]["LICENSE"],
59 bad_licenses, canonical_license, d)
60 except oe.license.LicenseError as exc:
61 bb.fatal('%s: %s' % (d.getVar('P'), exc))
62 else:
Brad Bishop977dc1a2019-02-06 16:01:43 -050063 pkg_dic[pkg]["LICENSES"] = re.sub(r'[|&()*]', ' ', pkg_dic[pkg]["LICENSE"])
64 pkg_dic[pkg]["LICENSES"] = re.sub(r' *', ' ', pkg_dic[pkg]["LICENSES"])
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080065 pkg_dic[pkg]["LICENSES"] = pkg_dic[pkg]["LICENSES"].split()
Brad Bishopf3f93bb2019-10-16 14:33:32 -040066 if pkg in whitelist:
67 bb.warn("Including %s with an incompatible license %s into the image, because it has been whitelisted." %(pkg, pkg_dic[pkg]["LICENSE"]))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080068
69 if not "IMAGE_MANIFEST" in pkg_dic[pkg]:
70 # Rootfs manifest
71 license_file.write("PACKAGE NAME: %s\n" % pkg)
72 license_file.write("PACKAGE VERSION: %s\n" % pkg_dic[pkg]["PV"])
73 license_file.write("RECIPE NAME: %s\n" % pkg_dic[pkg]["PN"])
74 license_file.write("LICENSE: %s\n\n" % pkg_dic[pkg]["LICENSE"])
75
76 # If the package doesn't contain any file, that is, its size is 0, the license
77 # isn't relevant as far as the final image is concerned. So doing license check
78 # doesn't make much sense, skip it.
79 if pkg_dic[pkg]["PKGSIZE_%s" % pkg] == "0":
80 continue
81 else:
82 # Image manifest
83 license_file.write("RECIPE NAME: %s\n" % pkg_dic[pkg]["PN"])
84 license_file.write("VERSION: %s\n" % pkg_dic[pkg]["PV"])
85 license_file.write("LICENSE: %s\n" % pkg_dic[pkg]["LICENSE"])
86 license_file.write("FILES: %s\n\n" % pkg_dic[pkg]["FILES"])
87
88 for lic in pkg_dic[pkg]["LICENSES"]:
89 lic_file = os.path.join(d.getVar('LICENSE_DIRECTORY'),
90 pkg_dic[pkg]["PN"], "generic_%s" %
Brad Bishop977dc1a2019-02-06 16:01:43 -050091 re.sub(r'\+', '', lic))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080092 # add explicity avoid of CLOSED license because isn't generic
93 if lic == "CLOSED":
94 continue
95
96 if not os.path.exists(lic_file):
97 bb.warn("The license listed %s was not in the "\
98 "licenses collected for recipe %s"
99 % (lic, pkg_dic[pkg]["PN"]))
100
101 # Two options here:
102 # - Just copy the manifest
103 # - Copy the manifest and the license directories
104 # With both options set we see a .5 M increase in core-image-minimal
105 copy_lic_manifest = d.getVar('COPY_LIC_MANIFEST')
106 copy_lic_dirs = d.getVar('COPY_LIC_DIRS')
Brad Bishop19323692019-04-05 15:28:33 -0400107 if rootfs and copy_lic_manifest == "1":
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800108 rootfs_license_dir = os.path.join(d.getVar('IMAGE_ROOTFS'),
109 'usr', 'share', 'common-licenses')
110 bb.utils.mkdirhier(rootfs_license_dir)
111 rootfs_license_manifest = os.path.join(rootfs_license_dir,
112 os.path.split(license_manifest)[1])
113 if not os.path.exists(rootfs_license_manifest):
Brad Bishopc342db32019-05-15 21:57:59 -0400114 oe.path.copyhardlink(license_manifest, rootfs_license_manifest)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800115
116 if copy_lic_dirs == "1":
117 for pkg in sorted(pkg_dic):
118 pkg_rootfs_license_dir = os.path.join(rootfs_license_dir, pkg)
119 bb.utils.mkdirhier(pkg_rootfs_license_dir)
120 pkg_license_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
121 pkg_dic[pkg]["PN"])
122
123 pkg_manifest_licenses = [canonical_license(d, lic) \
124 for lic in pkg_dic[pkg]["LICENSES"]]
125
126 licenses = os.listdir(pkg_license_dir)
127 for lic in licenses:
128 rootfs_license = os.path.join(rootfs_license_dir, lic)
129 pkg_license = os.path.join(pkg_license_dir, lic)
130 pkg_rootfs_license = os.path.join(pkg_rootfs_license_dir, lic)
131
Brad Bishop977dc1a2019-02-06 16:01:43 -0500132 if re.match(r"^generic_.*$", lic):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800133 generic_lic = canonical_license(d,
Brad Bishop977dc1a2019-02-06 16:01:43 -0500134 re.search(r"^generic_(.*)$", lic).group(1))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800135
136 # Do not copy generic license into package if isn't
137 # declared into LICENSES of the package.
Brad Bishop977dc1a2019-02-06 16:01:43 -0500138 if not re.sub(r'\+$', '', generic_lic) in \
139 [re.sub(r'\+', '', lic) for lic in \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800140 pkg_manifest_licenses]:
141 continue
142
143 if oe.license.license_ok(generic_lic,
144 bad_licenses) == False:
145 continue
146
147 if not os.path.exists(rootfs_license):
Brad Bishopc342db32019-05-15 21:57:59 -0400148 oe.path.copyhardlink(pkg_license, rootfs_license)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800149
150 if not os.path.exists(pkg_rootfs_license):
151 os.symlink(os.path.join('..', lic), pkg_rootfs_license)
152 else:
153 if (oe.license.license_ok(canonical_license(d,
154 lic), bad_licenses) == False or
155 os.path.exists(pkg_rootfs_license)):
156 continue
157
Brad Bishopc342db32019-05-15 21:57:59 -0400158 oe.path.copyhardlink(pkg_license, pkg_rootfs_license)
Brad Bishop19323692019-04-05 15:28:33 -0400159 # Fixup file ownership and permissions
160 for walkroot, dirs, files in os.walk(rootfs_license_dir):
161 for f in files:
162 p = os.path.join(walkroot, f)
163 os.lchown(p, 0, 0)
164 if not os.path.islink(p):
165 os.chmod(p, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
166 for dir in dirs:
167 p = os.path.join(walkroot, dir)
168 os.lchown(p, 0, 0)
169 os.chmod(p, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
170
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800171
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 = {}
182 lic_dir = d.getVar("LICENSE_DIRECTORY")
183
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
197 lic_manifest_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
198 d.getVar('IMAGE_NAME'))
199 bb.utils.mkdirhier(lic_manifest_dir)
200 image_license_manifest = os.path.join(lic_manifest_dir, 'image_license.manifest')
Brad Bishop19323692019-04-05 15:28:33 -0400201 write_license_files(d, image_license_manifest, man_dic, rootfs=False)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800202
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).
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800210 taskdata = d.getVar("BB_TASKDEPDATA", False)
211 depends = list(set([dep[0] for dep
212 in list(taskdata.values())
213 if not dep[0].endswith("-native")]))
214
215 # To verify what was deployed it checks the rootfs dependencies against
216 # the SSTATE_MANIFESTS for "deploy" task.
217 # The manifest file name contains the arch. Because we are not running
218 # in the recipe context it is necessary to check every arch used.
219 sstate_manifest_dir = d.getVar("SSTATE_MANIFESTS")
220 archs = list(set(d.getVar("SSTATE_ARCHS").split()))
221 for dep in depends:
222 for arch in archs:
223 sstate_manifest_file = os.path.join(sstate_manifest_dir,
224 "manifest-%s-%s.deploy" % (arch, dep))
225 if os.path.exists(sstate_manifest_file):
226 deploy[dep] = sstate_manifest_file
227 break
228
229 return deploy
230get_deployed_dependencies[vardepsexclude] = "BB_TASKDEPDATA"
231
232def get_deployed_files(man_file):
233 """
234 Get the files deployed from the sstate manifest
235 """
236
237 dep_files = []
238 excluded_files = []
239 with open(man_file, "r") as manifest:
240 all_files = manifest.read()
241 for f in all_files.splitlines():
242 if ((not (os.path.islink(f) or os.path.isdir(f))) and
243 not os.path.basename(f) in excluded_files):
244 dep_files.append(os.path.basename(f))
245 return dep_files
246
247ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest; license_create_manifest; "
248do_rootfs[recrdeptask] += "do_populate_lic"
249
250python do_populate_lic_deploy() {
251 license_deployed_manifest(d)
252}
253
254addtask populate_lic_deploy before do_build after do_image_complete
255do_populate_lic_deploy[recrdeptask] += "do_populate_lic do_deploy"
256