# Appends partition images generation to image build # # The format to specify it, in the machine, is: # # PARTITIONS_IMAGES ??= "partition_image_name_1 partition_image_name_2" # # The partition generation might be disabled by resetting ENABLE_PARTITIONS_IMAGE var # in an image recipe (for example) # ENABLE_PARTITIONS_IMAGE ??= "1" ENABLE_IMAGE_LICENSE_SUMMARY ??= "0" ENABLE_MULTIVOLUME_UBI ??= "0" PARTITIONS_IMAGES ??= "" python __anonymous () { # We check first if it is requested to generate any partition images if d.getVar('ENABLE_PARTITIONS_IMAGE') != "1": bb.note('ENABLE_PARTITIONS_IMAGE not enabled') return # ----------------------------------------------------------------------------- # Update the partition configuration set by user # ----------------------------------------------------------------------------- # Init partition list from PARTITIONS_IMAGES image_partitions = [] # Init image_summary_list image_summary_list = '' partitionsconfigflags = d.getVarFlags('PARTITIONS_IMAGES') # The "doc" varflag is special, we don't want to see it here partitionsconfigflags.pop('doc', None) partitionsconfig = (d.getVar('PARTITIONS_IMAGES') or "").split() if len(partitionsconfig) > 0: for config in partitionsconfig: for f, v in partitionsconfigflags.items(): if config == f: items = v.split(',') # Make sure about PARTITIONS_IMAGES contents if len(items) != 5: bb.fatal('[PARTITIONS_IMAGES] Only image,label,mountpoint,size,type can be specified!') if items[0] == '': bb.fatal('[PARTITIONS_IMAGES] Missing image setting') # Update IMAGE vars for each partition image if items[1] != '': bb.debug(1, "Set UBI_VOLNAME to %s for %s partition image." % (items[1], items[0])) if d.getVar('UBI_VOLNAME:pn-%s' % d.expand(items[0])): bb.debug(1,"UBI_VOLNAME is already configured to '%s' for %s partition image." % (d.getVar('UBI_VOLNAME:pn-%s' % d.expand(items[0])), items[0])) else: bb.debug(1, "Set UBI_VOLNAME to %s for %s partition image." % (items[1], items[0])) d.setVar('UBI_VOLNAME:pn-%s' % d.expand(items[0]), items[1]) if d.expand(items[1])[-2:] != 'fs': bb.debug(1, "Set IMAGE_NAME_SUFFIX to '.%sfs' for %s partition image." % (items[1], items[0])) d.setVar('IMAGE_NAME_SUFFIX:pn-%s' % d.expand(items[0]), '.' + items[1] + 'fs') else: bb.debug(1, "Set IMAGE_NAME_SUFFIX to '.%s' for %s partition image." % (items[1], items[0])) d.setVar('IMAGE_NAME_SUFFIX:pn-%s' % d.expand(items[0]), '.' + items[1]) else: bb.fatal('[PARTITIONS_IMAGES] Missing label setting for %s image' % items[0]) # Make sure that we're dealing with partition image and not rootfs image if items[2] != '': # Mount point is available, so we're dealing with partition image bb.debug(1, "Set IMAGE_PARTITION_MOUNTPOINT to %s for %s partition image." % (items[2], items[0])) d.setVar('IMAGE_PARTITION_MOUNTPOINT:pn-%s' % d.expand(items[0]), items[2]) # Append image to image_partitions list image_partitions.append(d.expand(items[0])) if items[3] != '': bb.debug(1, "Set IMAGE_ROOTFS_SIZE to %s for %s partition image." % (items[3], items[0])) d.setVar('IMAGE_ROOTFS_SIZE:pn-%s' % d.expand(items[0]), items[3]) else: bb.fatal('[PARTITIONS_IMAGES] Missing size setting for %s image' % items[0]) # Manage IMAGE_SUMMARY_LIST configuration according to PARTITIONS_IMAGE set if d.getVar('ENABLE_IMAGE_LICENSE_SUMMARY') == "1": if items[2] != '': image_summary_list += items[0] + ':' + items[2] + ';' else: # Set '/' as default mountpoint for rootfs in IMAGE_SUMMARY_LIST image_summary_list += items[0] + ':' + '/' + ';' # Manage multiubi volume list STM32MP_UBI_VOLUME if bb.utils.contains('IMAGE_FSTYPES', 'stmultiubi', True, False, d) and d.getVar('ENABLE_MULTIVOLUME_UBI') == "1": # Get the MULTIUBI_BUILD list without any duplicates ubiconfigs = list(dict.fromkeys((d.getVar('MULTIUBI_BUILD') or "").split())) if len(ubiconfigs) > 0: for ubi_config in ubiconfigs: bb.debug(1, "Appending '%s' image with %s size to STM32MP_UBI_VOLUME." % (items[0], items[3])) d.appendVar('STM32MP_UBI_VOLUME:%s' % ubi_config, ' ' + items[0] + ':' + items[3]) break # Reset IMAGE_LIST_SUMMARY with computed partition configuration if d.getVar('ENABLE_IMAGE_LICENSE_SUMMARY') == "1": bb.debug(1, "Set IMAGE_SUMMARY_LIST with configuration: %s." % image_summary_list) d.setVar('IMAGE_SUMMARY_LIST', image_summary_list) # ----------------------------------------------------------------------------- # Make sure to append the partition build to current image target # ----------------------------------------------------------------------------- if len(image_partitions) > 0: # Gather all current tasks tasks = filter(lambda k: d.getVarFlag(k, "task", True), d.keys()) for task in tasks: # Check that we are dealing with image recipe if task == 'do_image_complete': # Init current image name current_image_name = d.getVar('PN') or "" # Init RAMFS image if any initramfs = d.getVar('INITRAMFS_IMAGE') or "" # Init INITRD image if any initrd = d.getVar('INITRD_IMAGE_ALL') or d.getVar('INITRD_IMAGE') or "" # We need to append partition images generation only to image # that are not one of the defined partitions and not the InitRAMFS image. # Without this check we would create circular dependency if current_image_name not in image_partitions and current_image_name != initramfs and current_image_name not in initrd: for partition in image_partitions: bb.debug(1, "Appending %s image build to 'do_image' depends tasks." % partition) # We need to make sure the manifest file is deployed as we need it for 'image_rootfs_image_clean_task' d.appendVarFlag('do_image', 'depends', ' %s:do_populate_lic_deploy' % partition) bb.debug(1, "Appending 'image_rootfs_image_clean_task' to IMAGE_PREPROCESS_COMMAND.") d.appendVar('IMAGE_PREPROCESS_COMMAND', 'image_rootfs_image_clean_task;') bb.debug(1, "Set DEPLOY_BUILDINFO_FILE to '1' to allow to deploy build info file for rootfs build.") d.setVar('DEPLOY_BUILDINFO_FILE', '1') # Manage multiubi volume build enable for current image if bb.utils.contains('IMAGE_FSTYPES', 'stmultiubi', True, False, d) and d.getVar('ENABLE_MULTIVOLUME_UBI') == "1": bb.debug(1, "Appending 'st_multivolume_ubifs' to IMAGE_POSTPROCESS_COMMAND.") d.appendVar('IMAGE_POSTPROCESS_COMMAND', 'st_multivolume_ubifs;') } python image_rootfs_image_clean_task(){ import re; import subprocess import shutil deploy_image_dir = d.expand("${DEPLOY_DIR}") machine = d.expand("${MACHINE}") distro = d.expand("${DISTRO}") img_rootfs = d.getVar('IMAGE_ROOTFS') partitionsconfigflags = d.getVarFlags('PARTITIONS_IMAGES') partitionsconfig = (d.getVar('PARTITIONS_IMAGES') or "").split() if len(partitionsconfig) == 0: bb.note('No partition image: nothing more to do...') return for config in partitionsconfig: for f, v in partitionsconfigflags.items(): if config != f: continue items = v.split(',') _img_partition=d.expand(items[0]) _img_mountpoint=d.expand(items[2]) # Do not search for the rootfs if not items[2]: bb.note('Do not search for rootfs image') continue bb.note('Manage package check for %s mount point from %s partition image...' % (_img_partition, _img_mountpoint)) part_dir=os.path.join(img_rootfs, re.sub(r"^/", "", _img_mountpoint)) if not os.path.exists(part_dir): bb.note('The %s mountpoint is not populated on rootfs. Nothing to do.' % part_dir) continue # Discover all files in folder and sub-folder list_file = [] for root, subfolder, files in os.walk(part_dir): for f in files: list_file.append(re.sub(r"%s" % img_rootfs, "", os.path.join(root, f))) if not list_file: bb.note('No file found in current mount point %s: nothing to do' % part_dir) continue # Manifest file of the partition to check packages are in that partition manif_file = os.path.join(deploy_image_dir, "images", machine, _img_partition + "-" + distro + "-" + machine + ".manifest") try: manifest_content = open(manif_file, "r") contents = manifest_content.read().splitlines() manifest_content.close() if not contents: bb.fatal('Manifest associated to partition %s is empty.' \ ' No package verification can be on on that partition' % _img_partition) except Exception as e: bb.fatal("Unable to read %s file content: %s" % (manif_file, e)) except IOError: bb.fatal("File %s does not exist" % (manif_file)) # To speed up the process, save the list of processed files to avoid to check them again package_file_list = [] for f in list_file: if f in package_file_list: continue # Use oe-pkgdata-util to find the package providing a file cmd = ["oe-pkgdata-util", "-p", d.getVar('PKGDATA_DIR'), "find-path", f ] package = "" try: package = subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode("utf-8").rstrip('\n') package = re.sub(r":.*", "", package) except subprocess.CalledProcessError as e: bb.note("Cannot check package for file %s" % (os.path.join(root, f))) if package: # Use oe-pkgdata-util to list all files provided by a package cmd = ["oe-pkgdata-util", "-p", d.getVar('PKGDATA_DIR'), "list-pkg-files", package] try: package_filelist = subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode("utf-8") package_filelist = package_filelist.split() except subprocess.CalledProcessError as e: bb.fatal("Cannot read files inside package %s" % package) # Save processed files package_file_list = package_file_list + package_filelist # Check the package is in the manifest of the partition match = False for line in contents: if package == line.split()[0]: match = True break if not match: bb.note("Package %s should belong to %s partition image. Did you add it into the right image?" % (package, _img_partition)) else: bb.note("File %s is not in a package" % (os.path.join(root, f))) bb.note('Expecting to clean folder: %s' % part_dir) shutil.rmtree(part_dir) # directory is also removed. Re-create mount point os.mkdir(part_dir) bb.note('>>> Done') } # ----------------------------------------------------------------------------- # Manage to export to DEPLOYDIR the buildinfo file itself # ----------------------------------------------------------------------------- DEPLOY_BUILDINFO_FILE ??= "0" python extract_buildinfo() { if d.getVar('DEPLOY_BUILDINFO_FILE') == '1' and d.getVar('IMAGE_BUILDINFO_FILE'): # Export build information to deploy dir import shutil buildinfo_origin = d.getVar('IMAGE_BUILDINFO_FILE') rootfs_path = d.getVar('IMAGE_ROOTFS') buildinfo_srcfile = os.path.normpath(rootfs_path + '/' + buildinfo_origin) if os.path.isfile(buildinfo_srcfile): buildinfo_deploy = os.path.basename(d.getVar('IMAGE_BUILDINFO_FILE')) + '-' + d.getVar('IMAGE_LINK_NAME') buildinfo_dstfile = os.path.join(d.getVar('IMGDEPLOYDIR'), buildinfo_deploy) shutil.copy2(buildinfo_srcfile, buildinfo_dstfile) else: bb.warn('Not able to locate %s file in image rootfs %s' % (buildinfo_origin, rootfs_path)) } IMAGE_PREPROCESS_COMMAND += "extract_buildinfo;"