blob: 702e9f9c55a719f1cb23028d2f74dbd6e6187d7d [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
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500203 link_name = d.getVar('IMAGE_LINK_NAME')
204 if link_name:
205 lic_manifest_symlink_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
206 link_name)
207 # remove old symlink
208 if os.path.islink(lic_manifest_symlink_dir):
209 os.unlink(lic_manifest_symlink_dir)
210
211 # create the image dir symlink
212 os.symlink(lic_manifest_dir, lic_manifest_symlink_dir)
213
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800214def get_deployed_dependencies(d):
215 """
216 Get all the deployed dependencies of an image
217 """
218
219 deploy = {}
220 # Get all the dependencies for the current task (rootfs).
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800221 taskdata = d.getVar("BB_TASKDEPDATA", False)
222 depends = list(set([dep[0] for dep
223 in list(taskdata.values())
224 if not dep[0].endswith("-native")]))
225
226 # To verify what was deployed it checks the rootfs dependencies against
227 # the SSTATE_MANIFESTS for "deploy" task.
228 # The manifest file name contains the arch. Because we are not running
229 # in the recipe context it is necessary to check every arch used.
230 sstate_manifest_dir = d.getVar("SSTATE_MANIFESTS")
231 archs = list(set(d.getVar("SSTATE_ARCHS").split()))
232 for dep in depends:
233 for arch in archs:
234 sstate_manifest_file = os.path.join(sstate_manifest_dir,
235 "manifest-%s-%s.deploy" % (arch, dep))
236 if os.path.exists(sstate_manifest_file):
237 deploy[dep] = sstate_manifest_file
238 break
239
240 return deploy
241get_deployed_dependencies[vardepsexclude] = "BB_TASKDEPDATA"
242
243def get_deployed_files(man_file):
244 """
245 Get the files deployed from the sstate manifest
246 """
247
248 dep_files = []
249 excluded_files = []
250 with open(man_file, "r") as manifest:
251 all_files = manifest.read()
252 for f in all_files.splitlines():
253 if ((not (os.path.islink(f) or os.path.isdir(f))) and
254 not os.path.basename(f) in excluded_files):
255 dep_files.append(os.path.basename(f))
256 return dep_files
257
258ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest; license_create_manifest; "
259do_rootfs[recrdeptask] += "do_populate_lic"
260
261python do_populate_lic_deploy() {
262 license_deployed_manifest(d)
263}
264
265addtask populate_lic_deploy before do_build after do_image_complete
266do_populate_lic_deploy[recrdeptask] += "do_populate_lic do_deploy"
267