| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | # 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 |  | 
 | 6 | LICENSE_DIRECTORY ??= "${DEPLOY_DIR}/licenses" | 
 | 7 | LICSSTATEDIR = "${WORKDIR}/license-destdir/" | 
 | 8 |  | 
 | 9 | # Create extra package with license texts and add it to RRECOMMENDS_${PN} | 
 | 10 | LICENSE_CREATE_PACKAGE[type] = "boolean" | 
 | 11 | LICENSE_CREATE_PACKAGE ??= "0" | 
 | 12 | LICENSE_PACKAGE_SUFFIX ??= "-lic" | 
 | 13 | LICENSE_FILES_DIRECTORY ??= "${datadir}/licenses/" | 
 | 14 |  | 
 | 15 | addtask populate_lic after do_patch before do_build | 
 | 16 | do_populate_lic[dirs] = "${LICSSTATEDIR}/${PN}" | 
 | 17 | do_populate_lic[cleandirs] = "${LICSSTATEDIR}" | 
 | 18 |  | 
 | 19 | python 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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 24 |     from oe.utils import format_pkg_list | 
 | 25 |  | 
 | 26 |     pkgs = image_list_installed_packages(d) | 
 | 27 |     output = format_pkg_list(pkgs) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 28 |     open(os.path.join(license_image_dir, 'package.manifest'), | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 29 |         'w+').write(output) | 
 | 30 | } | 
 | 31 |  | 
 | 32 | python write_deploy_manifest() { | 
 | 33 |     license_deployed_manifest(d) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 34 | } | 
 | 35 |  | 
 | 36 | python license_create_manifest() { | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 37 |     import oe.packagedata | 
 | 38 |     from oe.rootfs import image_list_installed_packages | 
 | 39 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 40 |     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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 45 |     for pkg in sorted(image_list_installed_packages(d)): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 46 |         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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 55 |     rootfs_license_manifest = os.path.join(d.getVar('LICENSE_DIRECTORY', True), | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 56 |                         d.getVar('IMAGE_NAME', True), 'license.manifest') | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 57 |     write_license_files(d, rootfs_license_manifest, pkg_dic) | 
 | 58 | } | 
 | 59 |  | 
 | 60 | def 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 Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 67 |     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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 77 |                 pkg_dic[pkg]["LICENSES"] = re.sub('[|&()*]', ' ', pkg_dic[pkg]["LICENSE"]) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 78 |                 pkg_dic[pkg]["LICENSES"] = re.sub('  *', ' ', pkg_dic[pkg]["LICENSES"]) | 
 | 79 |                 pkg_dic[pkg]["LICENSES"] = pkg_dic[pkg]["LICENSES"].split() | 
 | 80 |  | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 81 |             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 Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 87 |  | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 88 |                 # 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 Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 99 |  | 
 | 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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 122 |         bb.utils.mkdirhier(rootfs_license_dir) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 123 |         rootfs_license_manifest = os.path.join(rootfs_license_dir, | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 124 |                 os.path.split(license_manifest)[1]) | 
 | 125 |         if not os.path.exists(rootfs_license_manifest): | 
 | 126 |             os.link(license_manifest, rootfs_license_manifest) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 127 |  | 
 | 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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 131 |                 bb.utils.mkdirhier(pkg_rootfs_license_dir) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 132 |                 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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 149 |                         if not os.path.exists(pkg_rootfs_license): | 
 | 150 |                             os.symlink(os.path.join('..', lic), pkg_rootfs_license) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 151 |                     else: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 152 |                         if (oe.license.license_ok(canonical_license(d, | 
 | 153 |                                 lic), bad_licenses) == False or | 
 | 154 |                                 os.path.exists(pkg_rootfs_license)): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 155 |                             continue | 
 | 156 |  | 
 | 157 |                         os.link(pkg_license, pkg_rootfs_license) | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 158 |  | 
 | 159 |  | 
 | 160 | def 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 Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 184 |     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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 188 |     write_license_files(d, image_license_manifest, man_dic) | 
 | 189 |  | 
 | 190 | def 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 Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 203 |                     in list(taskdata.values()) | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 204 |                     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 | 
 | 237 | get_deployed_dependencies[vardepsexclude] = "BB_TASKDEPDATA" | 
 | 238 |  | 
 | 239 | def 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 Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 264 |             for taskdep in taskdepdata.values(): | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 265 |                 # 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 | 
 | 274 | get_boot_dependencies[vardepsexclude] = "BB_TASKDEPDATA" | 
 | 275 |  | 
 | 276 | def get_deployed_files(man_file): | 
 | 277 |     """ | 
 | 278 |     Get the files deployed from the sstate manifest | 
 | 279 |     """ | 
 | 280 |  | 
 | 281 |     dep_files = [] | 
 | 282 |     excluded_files = ["README_-_DO_NOT_DELETE_FILES_IN_THIS_DIRECTORY.txt"] | 
 | 283 |     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 Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 290 |  | 
 | 291 | python 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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 300 |     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 Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 304 | } | 
 | 305 |  | 
 | 306 | # it would be better to copy them in do_install_append, but find_license_filesa is python | 
 | 307 | python 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 Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 317 | perform_packagecopy[vardeps] += "LICENSE_CREATE_PACKAGE" | 
 | 318 |  | 
 | 319 | def 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 Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 325 |  | 
 | 326 | def 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 |  | 
 | 343 | def copy_license_files(lic_files_paths, destdir): | 
 | 344 |     import shutil | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 345 |     import errno | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 346 |  | 
 | 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) | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 354 |             canlink = os.access(src, os.W_OK) and (os.stat(src).st_dev == os.stat(destdir).st_dev) | 
 | 355 |             if canlink: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 356 |                 try: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 357 |                     os.link(src, dst) | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 358 |                 except OSError as err: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 359 |                     if err.errno == errno.EXDEV: | 
 | 360 |                         # Copy license files if hard-link is not possible even if st_dev is the | 
 | 361 |                         # same on source and destination (docker container with device-mapper?) | 
 | 362 |                         canlink = False | 
 | 363 |                     else: | 
 | 364 |                         raise | 
 | 365 |                 try: | 
 | 366 |                     if canlink: | 
 | 367 |                         os.chown(dst,0,0) | 
 | 368 |                 except OSError as err: | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 369 |                     if err.errno in (errno.EPERM, errno.EINVAL): | 
 | 370 |                         # Suppress "Operation not permitted" error, as | 
 | 371 |                         # sometimes this function is not executed under pseudo. | 
 | 372 |                         # Also ignore "Invalid argument" errors that happen in | 
 | 373 |                         # some (unprivileged) container environments (no root). | 
 | 374 |                         pass | 
 | 375 |                     else: | 
 | 376 |                         raise | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 377 |             if not canlink: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 378 |                 shutil.copyfile(src, dst) | 
 | 379 |         except Exception as e: | 
 | 380 |             bb.warn("Could not copy license file %s to %s: %s" % (src, dst, e)) | 
 | 381 |  | 
 | 382 | def find_license_files(d): | 
 | 383 |     """ | 
 | 384 |     Creates list of files used in LIC_FILES_CHKSUM and generic LICENSE files. | 
 | 385 |     """ | 
 | 386 |     import shutil | 
 | 387 |     import oe.license | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 388 |     from collections import defaultdict, OrderedDict | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 389 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 390 |     # All the license files for the package | 
 | 391 |     lic_files = d.getVar('LIC_FILES_CHKSUM', True) | 
 | 392 |     pn = d.getVar('PN', True) | 
 | 393 |     # The license files are located in S/LIC_FILE_CHECKSUM. | 
 | 394 |     srcdir = d.getVar('S', True) | 
 | 395 |     # Directory we store the generic licenses as set in the distro configuration | 
 | 396 |     generic_directory = d.getVar('COMMON_LICENSE_DIR', True) | 
 | 397 |     # List of basename, path tuples | 
 | 398 |     lic_files_paths = [] | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 399 |     # Entries from LIC_FILES_CHKSUM | 
 | 400 |     lic_chksums = {} | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 401 |     license_source_dirs = [] | 
 | 402 |     license_source_dirs.append(generic_directory) | 
 | 403 |     try: | 
 | 404 |         additional_lic_dirs = d.getVar('LICENSE_PATH', True).split() | 
 | 405 |         for lic_dir in additional_lic_dirs: | 
 | 406 |             license_source_dirs.append(lic_dir) | 
 | 407 |     except: | 
 | 408 |         pass | 
 | 409 |  | 
 | 410 |     class FindVisitor(oe.license.LicenseVisitor): | 
 | 411 |         def visit_Str(self, node): | 
 | 412 |             # | 
 | 413 |             # Until I figure out what to do with | 
 | 414 |             # the two modifiers I support (or greater = + | 
 | 415 |             # and "with exceptions" being * | 
 | 416 |             # we'll just strip out the modifier and put | 
 | 417 |             # the base license. | 
 | 418 |             find_license(node.s.replace("+", "").replace("*", "")) | 
 | 419 |             self.generic_visit(node) | 
 | 420 |  | 
 | 421 |     def find_license(license_type): | 
 | 422 |         try: | 
 | 423 |             bb.utils.mkdirhier(gen_lic_dest) | 
 | 424 |         except: | 
 | 425 |             pass | 
 | 426 |         spdx_generic = None | 
 | 427 |         license_source = None | 
 | 428 |         # If the generic does not exist we need to check to see if there is an SPDX mapping to it, | 
 | 429 |         # unless NO_GENERIC_LICENSE is set. | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 430 |         for lic_dir in license_source_dirs: | 
 | 431 |             if not os.path.isfile(os.path.join(lic_dir, license_type)): | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 432 |                 if d.getVarFlag('SPDXLICENSEMAP', license_type, True) != None: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 433 |                     # Great, there is an SPDXLICENSEMAP. We can copy! | 
 | 434 |                     bb.debug(1, "We need to use a SPDXLICENSEMAP for %s" % (license_type)) | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 435 |                     spdx_generic = d.getVarFlag('SPDXLICENSEMAP', license_type, True) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 436 |                     license_source = lic_dir | 
 | 437 |                     break | 
 | 438 |             elif os.path.isfile(os.path.join(lic_dir, license_type)): | 
 | 439 |                 spdx_generic = license_type | 
 | 440 |                 license_source = lic_dir | 
 | 441 |                 break | 
 | 442 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 443 |         non_generic_lic = d.getVarFlag('NO_GENERIC_LICENSE', license_type, True) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 444 |         if spdx_generic and license_source: | 
 | 445 |             # we really should copy to generic_ + spdx_generic, however, that ends up messing the manifest | 
 | 446 |             # audit up. This should be fixed in emit_pkgdata (or, we actually got and fix all the recipes) | 
 | 447 |  | 
 | 448 |             lic_files_paths.append(("generic_" + license_type, os.path.join(license_source, spdx_generic))) | 
 | 449 |  | 
 | 450 |             # The user may attempt to use NO_GENERIC_LICENSE for a generic license which doesn't make sense | 
 | 451 |             # and should not be allowed, warn the user in this case. | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 452 |             if d.getVarFlag('NO_GENERIC_LICENSE', license_type, True): | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 453 |                 bb.warn("%s: %s is a generic license, please don't use NO_GENERIC_LICENSE for it." % (pn, license_type)) | 
 | 454 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 455 |         elif non_generic_lic and non_generic_lic in lic_chksums: | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 456 |             # if NO_GENERIC_LICENSE is set, we copy the license files from the fetched source | 
 | 457 |             # of the package rather than the license_source_dirs. | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 458 |             lic_files_paths.append(("generic_" + license_type, | 
 | 459 |                                     os.path.join(srcdir, non_generic_lic))) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 460 |         else: | 
 | 461 |             # Add explicity avoid of CLOSED license because this isn't generic | 
 | 462 |             if license_type != 'CLOSED': | 
 | 463 |                 # And here is where we warn people that their licenses are lousy | 
 | 464 |                 bb.warn("%s: No generic license file exists for: %s in any provider" % (pn, license_type)) | 
 | 465 |             pass | 
 | 466 |  | 
 | 467 |     if not generic_directory: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 468 |         bb.fatal("COMMON_LICENSE_DIR is unset. Please set this in your distro config") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 469 |  | 
 | 470 |     if not lic_files: | 
 | 471 |         # No recipe should have an invalid license file. This is checked else | 
 | 472 |         # where, but let's be pedantic | 
 | 473 |         bb.note(pn + ": Recipe file does not have license file information.") | 
 | 474 |         return lic_files_paths | 
 | 475 |  | 
 | 476 |     for url in lic_files.split(): | 
 | 477 |         try: | 
 | 478 |             (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url) | 
 | 479 |         except bb.fetch.MalformedUrl: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 480 |             bb.fatal("%s: LIC_FILES_CHKSUM contains an invalid URL:  %s" % (d.getVar('PF', True), url)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 481 |         # We want the license filename and path | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 482 |         chksum = parm['md5'] if 'md5' in parm else parm['sha256'] | 
 | 483 |         lic_chksums[path] = chksum | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 484 |  | 
 | 485 |     v = FindVisitor() | 
 | 486 |     try: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 487 |         v.visit_string(d.getVar('LICENSE', True)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 488 |     except oe.license.InvalidLicense as exc: | 
 | 489 |         bb.fatal('%s: %s' % (d.getVar('PF', True), exc)) | 
 | 490 |     except SyntaxError: | 
 | 491 |         bb.warn("%s: Failed to parse it's LICENSE field." % (d.getVar('PF', True))) | 
 | 492 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 493 |     # Add files from LIC_FILES_CHKSUM to list of license files | 
 | 494 |     lic_chksum_paths = defaultdict(OrderedDict) | 
 | 495 |     for path, chksum in lic_chksums.items(): | 
 | 496 |         lic_chksum_paths[os.path.basename(path)][chksum] = os.path.join(srcdir, path) | 
 | 497 |     for basename, files in lic_chksum_paths.items(): | 
 | 498 |         if len(files) == 1: | 
 | 499 |             lic_files_paths.append((basename, list(files.values())[0])) | 
 | 500 |         else: | 
 | 501 |             # If there are multiple different license files with identical | 
 | 502 |             # basenames we rename them to <file>.0, <file>.1, ... | 
 | 503 |             for i, path in enumerate(files.values()): | 
 | 504 |                 lic_files_paths.append(("%s.%d" % (basename, i), path)) | 
 | 505 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 506 |     return lic_files_paths | 
 | 507 |  | 
 | 508 | def return_spdx(d, license): | 
 | 509 |     """ | 
 | 510 |     This function returns the spdx mapping of a license if it exists. | 
 | 511 |      """ | 
 | 512 |     return d.getVarFlag('SPDXLICENSEMAP', license, True) | 
 | 513 |  | 
 | 514 | def canonical_license(d, license): | 
 | 515 |     """ | 
 | 516 |     Return the canonical (SPDX) form of the license if available (so GPLv3 | 
 | 517 |     becomes GPL-3.0), for the license named 'X+', return canonical form of | 
 | 518 |     'X' if availabel and the tailing '+' (so GPLv3+ becomes GPL-3.0+),  | 
 | 519 |     or the passed license if there is no canonical form. | 
 | 520 |     """ | 
 | 521 |     lic = d.getVarFlag('SPDXLICENSEMAP', license, True) or "" | 
 | 522 |     if not lic and license.endswith('+'): | 
 | 523 |         lic = d.getVarFlag('SPDXLICENSEMAP', license.rstrip('+'), True) | 
 | 524 |         if lic: | 
 | 525 |             lic += '+' | 
 | 526 |     return lic or license | 
 | 527 |  | 
 | 528 | def expand_wildcard_licenses(d, wildcard_licenses): | 
 | 529 |     """ | 
 | 530 |     Return actual spdx format license names if wildcard used. We expand | 
 | 531 |     wildcards from SPDXLICENSEMAP flags and SRC_DISTRIBUTE_LICENSES values. | 
 | 532 |     """ | 
 | 533 |     import fnmatch | 
 | 534 |     licenses = [] | 
 | 535 |     spdxmapkeys = d.getVarFlags('SPDXLICENSEMAP').keys() | 
 | 536 |     for wld_lic in wildcard_licenses: | 
 | 537 |         spdxflags = fnmatch.filter(spdxmapkeys, wld_lic) | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 538 |         licenses += [d.getVarFlag('SPDXLICENSEMAP', flag, True) for flag in spdxflags] | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 539 |  | 
 | 540 |     spdx_lics = (d.getVar('SRC_DISTRIBUTE_LICENSES', False) or '').split() | 
 | 541 |     for wld_lic in wildcard_licenses: | 
 | 542 |         licenses += fnmatch.filter(spdx_lics, wld_lic) | 
 | 543 |  | 
 | 544 |     licenses = list(set(licenses)) | 
 | 545 |     return licenses | 
 | 546 |  | 
 | 547 | def incompatible_license_contains(license, truevalue, falsevalue, d): | 
 | 548 |     license = canonical_license(d, license) | 
 | 549 |     bad_licenses = (d.getVar('INCOMPATIBLE_LICENSE', True) or "").split() | 
 | 550 |     bad_licenses = expand_wildcard_licenses(d, bad_licenses) | 
 | 551 |     return truevalue if license in bad_licenses else falsevalue | 
 | 552 |  | 
 | 553 | def incompatible_license(d, dont_want_licenses, package=None): | 
 | 554 |     """ | 
 | 555 |     This function checks if a recipe has only incompatible licenses. It also | 
 | 556 |     take into consideration 'or' operand.  dont_want_licenses should be passed | 
 | 557 |     as canonical (SPDX) names. | 
 | 558 |     """ | 
 | 559 |     import oe.license | 
 | 560 |     license = d.getVar("LICENSE_%s" % package, True) if package else None | 
 | 561 |     if not license: | 
 | 562 |         license = d.getVar('LICENSE', True) | 
 | 563 |  | 
 | 564 |     # Handles an "or" or two license sets provided by | 
 | 565 |     # flattened_licenses(), pick one that works if possible. | 
 | 566 |     def choose_lic_set(a, b): | 
 | 567 |         return a if all(oe.license.license_ok(canonical_license(d, lic),  | 
 | 568 |                             dont_want_licenses) for lic in a) else b | 
 | 569 |  | 
 | 570 |     try: | 
 | 571 |         licenses = oe.license.flattened_licenses(license, choose_lic_set) | 
 | 572 |     except oe.license.LicenseError as exc: | 
 | 573 |         bb.fatal('%s: %s' % (d.getVar('P', True), exc)) | 
 | 574 |     return any(not oe.license.license_ok(canonical_license(d, l), \ | 
 | 575 | 		dont_want_licenses) for l in licenses) | 
 | 576 |  | 
 | 577 | def check_license_flags(d): | 
 | 578 |     """ | 
 | 579 |     This function checks if a recipe has any LICENSE_FLAGS that | 
 | 580 |     aren't whitelisted. | 
 | 581 |  | 
 | 582 |     If it does, it returns the first LICENSE_FLAGS item missing from the | 
 | 583 |     whitelist, or all of the LICENSE_FLAGS if there is no whitelist. | 
 | 584 |  | 
 | 585 |     If everything is is properly whitelisted, it returns None. | 
 | 586 |     """ | 
 | 587 |  | 
 | 588 |     def license_flag_matches(flag, whitelist, pn): | 
 | 589 |         """ | 
 | 590 |         Return True if flag matches something in whitelist, None if not. | 
 | 591 |  | 
 | 592 |         Before we test a flag against the whitelist, we append _${PN} | 
 | 593 |         to it.  We then try to match that string against the | 
 | 594 |         whitelist.  This covers the normal case, where we expect | 
 | 595 |         LICENSE_FLAGS to be a simple string like 'commercial', which | 
 | 596 |         the user typically matches exactly in the whitelist by | 
 | 597 |         explicitly appending the package name e.g 'commercial_foo'. | 
 | 598 |         If we fail the match however, we then split the flag across | 
 | 599 |         '_' and append each fragment and test until we either match or | 
 | 600 |         run out of fragments. | 
 | 601 |         """ | 
 | 602 |         flag_pn = ("%s_%s" % (flag, pn)) | 
 | 603 |         for candidate in whitelist: | 
 | 604 |             if flag_pn == candidate: | 
 | 605 |                     return True | 
 | 606 |  | 
 | 607 |         flag_cur = "" | 
 | 608 |         flagments = flag_pn.split("_") | 
 | 609 |         flagments.pop() # we've already tested the full string | 
 | 610 |         for flagment in flagments: | 
 | 611 |             if flag_cur: | 
 | 612 |                 flag_cur += "_" | 
 | 613 |             flag_cur += flagment | 
 | 614 |             for candidate in whitelist: | 
 | 615 |                 if flag_cur == candidate: | 
 | 616 |                     return True | 
 | 617 |         return False | 
 | 618 |  | 
 | 619 |     def all_license_flags_match(license_flags, whitelist): | 
 | 620 |         """ Return first unmatched flag, None if all flags match """ | 
 | 621 |         pn = d.getVar('PN', True) | 
 | 622 |         split_whitelist = whitelist.split() | 
 | 623 |         for flag in license_flags.split(): | 
 | 624 |             if not license_flag_matches(flag, split_whitelist, pn): | 
 | 625 |                 return flag | 
 | 626 |         return None | 
 | 627 |  | 
 | 628 |     license_flags = d.getVar('LICENSE_FLAGS', True) | 
 | 629 |     if license_flags: | 
 | 630 |         whitelist = d.getVar('LICENSE_FLAGS_WHITELIST', True) | 
 | 631 |         if not whitelist: | 
 | 632 |             return license_flags | 
 | 633 |         unmatched_flag = all_license_flags_match(license_flags, whitelist) | 
 | 634 |         if unmatched_flag: | 
 | 635 |             return unmatched_flag | 
 | 636 |     return None | 
 | 637 |  | 
 | 638 | def check_license_format(d): | 
 | 639 |     """ | 
 | 640 |     This function checks if LICENSE is well defined, | 
 | 641 |         Validate operators in LICENSES. | 
 | 642 |         No spaces are allowed between LICENSES. | 
 | 643 |     """ | 
 | 644 |     pn = d.getVar('PN', True) | 
 | 645 |     licenses = d.getVar('LICENSE', True) | 
 | 646 |     from oe.license import license_operator, license_operator_chars, license_pattern | 
 | 647 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 648 |     elements = list(filter(lambda x: x.strip(), license_operator.split(licenses))) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 649 |     for pos, element in enumerate(elements): | 
 | 650 |         if license_pattern.match(element): | 
 | 651 |             if pos > 0 and license_pattern.match(elements[pos - 1]): | 
 | 652 |                 bb.warn('%s: LICENSE value "%s" has an invalid format - license names ' \ | 
 | 653 |                         'must be separated by the following characters to indicate ' \ | 
 | 654 |                         'the license selection: %s' % | 
 | 655 |                         (pn, licenses, license_operator_chars)) | 
 | 656 |         elif not license_operator.match(element): | 
 | 657 |             bb.warn('%s: LICENSE value "%s" has an invalid separator "%s" that is not ' \ | 
 | 658 |                     'in the valid list of separators (%s)' % | 
 | 659 |                     (pn, licenses, element, license_operator_chars)) | 
 | 660 |  | 
 | 661 | SSTATETASKS += "do_populate_lic" | 
 | 662 | do_populate_lic[sstate-inputdirs] = "${LICSSTATEDIR}" | 
 | 663 | do_populate_lic[sstate-outputdirs] = "${LICENSE_DIRECTORY}/" | 
 | 664 |  | 
 | 665 | ROOTFS_POSTPROCESS_COMMAND_prepend = "write_package_manifest; license_create_manifest; " | 
| Patrick Williams | f1e5d69 | 2016-03-30 15:21:19 -0500 | [diff] [blame] | 666 | do_rootfs[recrdeptask] += "do_populate_lic" | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 667 |  | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 668 | IMAGE_POSTPROCESS_COMMAND_prepend = "write_deploy_manifest; " | 
 | 669 | do_image[recrdeptask] += "do_populate_lic" | 
 | 670 |  | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 671 | python do_populate_lic_setscene () { | 
 | 672 |     sstate_setscene(d) | 
 | 673 | } | 
 | 674 | addtask do_populate_lic_setscene |