blob: 119c8dfc869bd8489aa90c45ccef93a1987e87b0 [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:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800128 pkg_license = os.path.join(pkg_license_dir, lic)
129 pkg_rootfs_license = os.path.join(pkg_rootfs_license_dir, lic)
130
Brad Bishop977dc1a2019-02-06 16:01:43 -0500131 if re.match(r"^generic_.*$", lic):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800132 generic_lic = canonical_license(d,
Brad Bishop977dc1a2019-02-06 16:01:43 -0500133 re.search(r"^generic_(.*)$", lic).group(1))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800134
135 # Do not copy generic license into package if isn't
136 # declared into LICENSES of the package.
Brad Bishop977dc1a2019-02-06 16:01:43 -0500137 if not re.sub(r'\+$', '', generic_lic) in \
138 [re.sub(r'\+', '', lic) for lic in \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800139 pkg_manifest_licenses]:
140 continue
141
142 if oe.license.license_ok(generic_lic,
143 bad_licenses) == False:
144 continue
145
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600146 # Make sure we use only canonical name for the license file
147 rootfs_license = os.path.join(rootfs_license_dir, "generic_%s" % generic_lic)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800148 if not os.path.exists(rootfs_license):
Brad Bishopc342db32019-05-15 21:57:59 -0400149 oe.path.copyhardlink(pkg_license, rootfs_license)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800150
151 if not os.path.exists(pkg_rootfs_license):
152 os.symlink(os.path.join('..', lic), pkg_rootfs_license)
153 else:
154 if (oe.license.license_ok(canonical_license(d,
155 lic), bad_licenses) == False or
156 os.path.exists(pkg_rootfs_license)):
157 continue
158
Brad Bishopc342db32019-05-15 21:57:59 -0400159 oe.path.copyhardlink(pkg_license, pkg_rootfs_license)
Brad Bishop19323692019-04-05 15:28:33 -0400160 # Fixup file ownership and permissions
161 for walkroot, dirs, files in os.walk(rootfs_license_dir):
162 for f in files:
163 p = os.path.join(walkroot, f)
164 os.lchown(p, 0, 0)
165 if not os.path.islink(p):
166 os.chmod(p, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
167 for dir in dirs:
168 p = os.path.join(walkroot, dir)
169 os.lchown(p, 0, 0)
170 os.chmod(p, stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH)
171
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800172
173
174def license_deployed_manifest(d):
175 """
176 Write the license manifest for the deployed recipes.
177 The deployed recipes usually includes the bootloader
178 and extra files to boot the target.
179 """
180
181 dep_dic = {}
182 man_dic = {}
183 lic_dir = d.getVar("LICENSE_DIRECTORY")
184
185 dep_dic = get_deployed_dependencies(d)
186 for dep in dep_dic.keys():
187 man_dic[dep] = {}
188 # It is necessary to mark this will be used for image manifest
189 man_dic[dep]["IMAGE_MANIFEST"] = True
190 man_dic[dep]["PN"] = dep
191 man_dic[dep]["FILES"] = \
192 " ".join(get_deployed_files(dep_dic[dep]))
193 with open(os.path.join(lic_dir, dep, "recipeinfo"), "r") as f:
194 for line in f.readlines():
195 key,val = line.split(": ", 1)
196 man_dic[dep][key] = val[:-1]
197
198 lic_manifest_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
199 d.getVar('IMAGE_NAME'))
200 bb.utils.mkdirhier(lic_manifest_dir)
201 image_license_manifest = os.path.join(lic_manifest_dir, 'image_license.manifest')
Brad Bishop19323692019-04-05 15:28:33 -0400202 write_license_files(d, image_license_manifest, man_dic, rootfs=False)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800203
Andrew Geisslerc9f78652020-09-18 14:11:35 -0500204 link_name = d.getVar('IMAGE_LINK_NAME')
205 if link_name:
206 lic_manifest_symlink_dir = os.path.join(d.getVar('LICENSE_DIRECTORY'),
207 link_name)
208 # remove old symlink
209 if os.path.islink(lic_manifest_symlink_dir):
210 os.unlink(lic_manifest_symlink_dir)
211
212 # create the image dir symlink
213 os.symlink(lic_manifest_dir, lic_manifest_symlink_dir)
214
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800215def get_deployed_dependencies(d):
216 """
217 Get all the deployed dependencies of an image
218 """
219
220 deploy = {}
221 # Get all the dependencies for the current task (rootfs).
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800222 taskdata = d.getVar("BB_TASKDEPDATA", False)
223 depends = list(set([dep[0] for dep
224 in list(taskdata.values())
225 if not dep[0].endswith("-native")]))
226
227 # To verify what was deployed it checks the rootfs dependencies against
228 # the SSTATE_MANIFESTS for "deploy" task.
229 # The manifest file name contains the arch. Because we are not running
230 # in the recipe context it is necessary to check every arch used.
231 sstate_manifest_dir = d.getVar("SSTATE_MANIFESTS")
232 archs = list(set(d.getVar("SSTATE_ARCHS").split()))
233 for dep in depends:
234 for arch in archs:
235 sstate_manifest_file = os.path.join(sstate_manifest_dir,
236 "manifest-%s-%s.deploy" % (arch, dep))
237 if os.path.exists(sstate_manifest_file):
238 deploy[dep] = sstate_manifest_file
239 break
240
241 return deploy
242get_deployed_dependencies[vardepsexclude] = "BB_TASKDEPDATA"
243
244def get_deployed_files(man_file):
245 """
246 Get the files deployed from the sstate manifest
247 """
248
249 dep_files = []
250 excluded_files = []
251 with open(man_file, "r") as manifest:
252 all_files = manifest.read()
253 for f in all_files.splitlines():
254 if ((not (os.path.islink(f) or os.path.isdir(f))) and
255 not os.path.basename(f) in excluded_files):
256 dep_files.append(os.path.basename(f))
257 return dep_files
258
259ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest; license_create_manifest; "
260do_rootfs[recrdeptask] += "do_populate_lic"
261
262python do_populate_lic_deploy() {
263 license_deployed_manifest(d)
264}
265
266addtask populate_lic_deploy before do_build after do_image_complete
267do_populate_lic_deploy[recrdeptask] += "do_populate_lic do_deploy"
268