[OE-core][PATCH v2 1/7] classes-recipe/image: Add image file manifest

Joshua Watt
2024-06-19T22:18:16Z

Downstream tasks may want to know what image files were written by the
do_image family of tasks (e.g. SPDX) so have each task write out a
manifest file that describes the files it produced, then aggregate them
in do_image_complete

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
---
meta/classes-recipe/image.bbclass | 58 +++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)

diff --git a/meta/classes-recipe/image.bbclass b/meta/classes-recipe/image.bbclass
index 28be6c63623..a9347adb832 100644
--- a/meta/classes-recipe/image.bbclass
+++ b/meta/classes-recipe/image.bbclass
@@ -88,6 +88,11 @@ PACKAGE_INSTALL_ATTEMPTONLY ?= "${FEATURE_INSTALL_OPTIONAL}"

IMGDEPLOYDIR = "${WORKDIR}/deploy-${PN}-image-complete"

+IMGMANIFESTDIR = "${WORKDIR}/image-task-manifest"
+
+IMAGE_FILE_MANIFEST_DIR = "${WORKDIR}/deploy-image-file-manifest"
+IMAGE_FILE_MANIFEST = "${IMAGE_FILE_MANIFEST_DIR}/manifest.json"
+
# Images are generally built explicitly, do not need to be part of world.
EXCLUDE_FROM_WORLD = "1"

@@ -277,14 +282,28 @@ fakeroot python do_image () {
execute_pre_post_process(d, pre_process_cmds)
}
do_image[dirs] = "${TOPDIR}"
+do_image[cleandirs] += "${IMGMANIFESTDIR}"
addtask do_image after do_rootfs

fakeroot python do_image_complete () {
from oe.utils import execute_pre_post_process
+ from pathlib import Path
+ import json

post_process_cmds = d.getVar("IMAGE_POSTPROCESS_COMMAND")

execute_pre_post_process(d, post_process_cmds)
+
+ image_manifest_dir = Path(d.getVar('IMGMANIFESTDIR'))
+
+ data = []
+
+ for manifest_path in image_manifest_dir.glob("*.json"):
+ with manifest_path.open("r") as f:
+ data.extend(json.load(f))
+
+ with open(d.getVar("IMAGE_FILE_MANIFEST"), "w") as f:
+ json.dump(data, f)
}
do_image_complete[dirs] = "${TOPDIR}"
SSTATETASKS += "do_image_complete"
@@ -292,6 +311,8 @@ SSTATE_SKIP_CREATION:task-image-complete = '1'
do_image_complete[sstate-inputdirs] = "${IMGDEPLOYDIR}"
do_image_complete[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}"
do_image_complete[stamp-extra-info] = "${MACHINE_ARCH}"
+do_image_complete[sstate-plaindirs] = "${IMAGE_FILE_MANIFEST_DIR}"
+do_image_complete[dirs] += "${IMAGE_FILE_MANIFEST_DIR}"
addtask do_image_complete after do_image before do_build
python do_image_complete_setscene () {
sstate_setscene(d)
@@ -507,12 +528,14 @@ python () {
d.setVar(task, '\n'.join(cmds))
d.setVarFlag(task, 'func', '1')
d.setVarFlag(task, 'fakeroot', '1')
+ d.setVarFlag(task, 'imagetype', t)

d.appendVarFlag(task, 'prefuncs', ' ' + debug + ' set_image_size')
d.prependVarFlag(task, 'postfuncs', 'create_symlinks ')
d.appendVarFlag(task, 'subimages', ' ' + ' '.join(subimages))
d.appendVarFlag(task, 'vardeps', ' ' + ' '.join(vardeps))
d.appendVarFlag(task, 'vardepsexclude', ' DATETIME DATE ' + ' '.join(vardepsexclude))
+ d.appendVarFlag(task, 'postfuncs', ' write_image_file_manifest')

bb.debug(2, "Adding task %s before %s, after %s" % (task, 'do_image_complete', after))
bb.build.addtask(task, 'do_image_complete', after, d)
@@ -610,6 +633,41 @@ python create_symlinks() {
bb.note("Skipping symlink, source does not exist: %s -> %s" % (dst, src))
}

+python write_image_file_manifest() {
+ import json
+ from pathlib import Path
+
+ taskname = d.getVar("BB_CURRENTTASK")
+ image_deploy_dir = Path(d.getVar('IMGDEPLOYDIR'))
+ image_manifest_dir = Path(d.getVar('IMGMANIFESTDIR'))
+ manifest_path = image_manifest_dir / ("do_" + d.getVar("BB_CURRENTTASK") + ".json")
+
+ image_name = d.getVar("IMAGE_NAME")
+ image_basename = d.getVar("IMAGE_BASENAME")
+ machine = d.getVar("MACHINE")
+
+ subimages = (d.getVarFlag("do_" + taskname, 'subimages', False) or "").split()
+ imagetype = d.getVarFlag("do_" + taskname, 'imagetype', False)
+
+ data = {
+ "taskname": taskname,
+ "imagetype": imagetype,
+ "images": []
+ }
+
+ for type in subimages:
+ image_filename = image_name + "." + type
+ image_path = image_deploy_dir / image_filename
+ if not image_path.exists():
+ continue
+ data["images"].append({
+ "filename": image_filename,
+ })
+
+ with manifest_path.open("w") as f:
+ json.dump([data], f)
+}
+
MULTILIBRE_ALLOW_REP += "${base_bindir} ${base_sbindir} ${bindir} ${sbindir} ${libexecdir} ${sysconfdir} ${nonarch_base_libdir}/udev /lib/modules/[^/]*/modules.*"
MULTILIB_CHECK_FILE = "${WORKDIR}/multilib_check.py"
MULTILIB_TEMP_ROOTFS = "${WORKDIR}/multilib"
--
2.43.2