diff options
| author | Pierre-Loup GOSSE <pierre-loup.gosse@smile.fr> | 2025-09-30 11:43:44 +0200 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-10-03 17:51:38 +0100 |
| commit | 7a3925c6e50d90b70e687c3c75ca3ab4c10cb245 (patch) | |
| tree | fa8ef8dfd8b722a02539eba6d56c655a6aab9ae8 | |
| parent | 3d87b9ca0d829c384680718970811aa31de3008c (diff) | |
| download | poky-7a3925c6e50d90b70e687c3c75ca3ab4c10cb245.tar.gz | |
wic: extra partition plugin
The extra_partition plugin allows populating an extra partition with
files listed in the new IMAGE_EXTRA_FILES variable. The implementation
is similar to the bootimg_partition plugin.
This plugin provides an easy way to install files that are not part of
the rootfs.
(From OE-Core rev: a6a3d9662947e7f6087a539efd8370b03ae64449)
Signed-off-by: Pierre-Loup GOSSE <pierre-loup.gosse@smile.fr>
Reviewed-by: Yoann CONGAL <yoann.congal@smile.fr>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
| -rw-r--r-- | meta/classes-recipe/image_types_wic.bbclass | 1 | ||||
| -rw-r--r-- | meta/lib/oeqa/selftest/cases/wic.py | 43 | ||||
| -rw-r--r-- | scripts/lib/wic/plugins/source/extra_partition.py | 134 |
3 files changed, 177 insertions, 1 deletions
diff --git a/meta/classes-recipe/image_types_wic.bbclass b/meta/classes-recipe/image_types_wic.bbclass index 6180874a4c..549a69db60 100644 --- a/meta/classes-recipe/image_types_wic.bbclass +++ b/meta/classes-recipe/image_types_wic.bbclass | |||
| @@ -17,6 +17,7 @@ WICVARS ?= "\ | |||
| 17 | IMAGE_BOOT_FILES \ | 17 | IMAGE_BOOT_FILES \ |
| 18 | IMAGE_CLASSES \ | 18 | IMAGE_CLASSES \ |
| 19 | IMAGE_EFI_BOOT_FILES \ | 19 | IMAGE_EFI_BOOT_FILES \ |
| 20 | IMAGE_EXTRA_FILES \ | ||
| 20 | IMAGE_LINK_NAME \ | 21 | IMAGE_LINK_NAME \ |
| 21 | IMAGE_ROOTFS \ | 22 | IMAGE_ROOTFS \ |
| 22 | IMGDEPLOYDIR \ | 23 | IMGDEPLOYDIR \ |
diff --git a/meta/lib/oeqa/selftest/cases/wic.py b/meta/lib/oeqa/selftest/cases/wic.py index b1c318bd4e..1b59980f1c 100644 --- a/meta/lib/oeqa/selftest/cases/wic.py +++ b/meta/lib/oeqa/selftest/cases/wic.py | |||
| @@ -18,6 +18,7 @@ from glob import glob | |||
| 18 | from shutil import rmtree, copy | 18 | from shutil import rmtree, copy |
| 19 | from tempfile import NamedTemporaryFile | 19 | from tempfile import NamedTemporaryFile |
| 20 | from tempfile import TemporaryDirectory | 20 | from tempfile import TemporaryDirectory |
| 21 | from textwrap import dedent | ||
| 21 | 22 | ||
| 22 | from oeqa.selftest.case import OESelftestTestCase | 23 | from oeqa.selftest.case import OESelftestTestCase |
| 23 | from oeqa.core.decorator import OETestTag | 24 | from oeqa.core.decorator import OETestTag |
| @@ -1021,7 +1022,7 @@ class Wic2(WicTestCase): | |||
| 1021 | wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES', | 1022 | wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES', |
| 1022 | 'INITRD', 'INITRD_LIVE', 'ISODIR','INITRAMFS_IMAGE', | 1023 | 'INITRD', 'INITRD_LIVE', 'ISODIR','INITRAMFS_IMAGE', |
| 1023 | 'INITRAMFS_IMAGE_BUNDLE', 'INITRAMFS_LINK_NAME', | 1024 | 'INITRAMFS_IMAGE_BUNDLE', 'INITRAMFS_LINK_NAME', |
| 1024 | 'APPEND', 'IMAGE_EFI_BOOT_FILES')) | 1025 | 'APPEND', 'IMAGE_EFI_BOOT_FILES', 'IMAGE_EXTRA_FILES')) |
| 1025 | with open(path) as envfile: | 1026 | with open(path) as envfile: |
| 1026 | content = dict(line.split("=", 1) for line in envfile) | 1027 | content = dict(line.split("=", 1) for line in envfile) |
| 1027 | # test if variables used by wic present in the .env file | 1028 | # test if variables used by wic present in the .env file |
| @@ -1647,6 +1648,46 @@ INITRAMFS_IMAGE = "core-image-initramfs-boot" | |||
| 1647 | status, output = qemu.run_serial(cmd) | 1648 | status, output = qemu.run_serial(cmd) |
| 1648 | self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) | 1649 | self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output)) |
| 1649 | 1650 | ||
| 1651 | def test_extra_partition_plugin(self): | ||
| 1652 | """Test extra partition plugin""" | ||
| 1653 | config = dedent("""\ | ||
| 1654 | IMAGE_EXTRA_FILES_label-foo = "bar.conf;foo.conf" | ||
| 1655 | IMAGE_EXTRA_FILES_uuid-e7d0824e-cda3-4bed-9f54-9ef5312d105d = "bar.conf;foobar.conf" | ||
| 1656 | IMAGE_EXTRA_FILES = "foo/*" | ||
| 1657 | WICVARS:append = "\ | ||
| 1658 | IMAGE_EXTRA_FILES_label-foo \ | ||
| 1659 | IMAGE_EXTRA_FILES_uuid-e7d0824e-cda3-4bed-9f54-9ef5312d105d \ | ||
| 1660 | " | ||
| 1661 | """) | ||
| 1662 | self.append_config(config) | ||
| 1663 | |||
| 1664 | deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE') | ||
| 1665 | |||
| 1666 | testfile = open(os.path.join(deploy_dir, "bar.conf"), "w") | ||
| 1667 | testfile.write("test") | ||
| 1668 | testfile.close() | ||
| 1669 | |||
| 1670 | os.mkdir(os.path.join(deploy_dir, "foo")) | ||
| 1671 | testfile = open(os.path.join(deploy_dir, "foo", "bar.conf"), "w") | ||
| 1672 | testfile.write("test") | ||
| 1673 | testfile.close() | ||
| 1674 | |||
| 1675 | with NamedTemporaryFile("w", suffix=".wks") as wks: | ||
| 1676 | wks.writelines(['part / --source extra_partition --ondisk sda --fstype=ext4 --label foo --align 4 --size 5M\n', | ||
| 1677 | 'part / --source extra_partition --ondisk sda --fstype=ext4 --uuid e7d0824e-cda3-4bed-9f54-9ef5312d105d --align 4 --size 5M\n', | ||
| 1678 | 'part / --source extra_partition --ondisk sda --fstype=ext4 --label bar --align 4 --size 5M\n']) | ||
| 1679 | wks.flush() | ||
| 1680 | _, wicimg = self._get_wic(wks.name) | ||
| 1681 | |||
| 1682 | result = runCmd("wic ls %s | wc -l" % wicimg) | ||
| 1683 | self.assertEqual('4', result.output, msg="Expect 3 partitions, not %s" % result.output) | ||
| 1684 | |||
| 1685 | for part, file in enumerate(["foo.conf", "foobar.conf", "bar.conf"]): | ||
| 1686 | result = runCmd("wic ls %s:%d | grep -q \"%s\"" % (wicimg, part + 1, file)) | ||
| 1687 | self.assertEqual(0, result.status, msg="File '%s' not found in the partition #%d" % (file, part)) | ||
| 1688 | |||
| 1689 | self.remove_config(config) | ||
| 1690 | |||
| 1650 | def test_fs_types(self): | 1691 | def test_fs_types(self): |
| 1651 | """Test filesystem types for empty and not empty partitions""" | 1692 | """Test filesystem types for empty and not empty partitions""" |
| 1652 | img = 'core-image-minimal' | 1693 | img = 'core-image-minimal' |
diff --git a/scripts/lib/wic/plugins/source/extra_partition.py b/scripts/lib/wic/plugins/source/extra_partition.py new file mode 100644 index 0000000000..499bede280 --- /dev/null +++ b/scripts/lib/wic/plugins/source/extra_partition.py | |||
| @@ -0,0 +1,134 @@ | |||
| 1 | import logging | ||
| 2 | import os | ||
| 3 | import re | ||
| 4 | |||
| 5 | from glob import glob | ||
| 6 | |||
| 7 | from wic import WicError | ||
| 8 | from wic.pluginbase import SourcePlugin | ||
| 9 | from wic.misc import exec_cmd, get_bitbake_var | ||
| 10 | |||
| 11 | logger = logging.getLogger('wic') | ||
| 12 | |||
| 13 | class ExtraPartitionPlugin(SourcePlugin): | ||
| 14 | """ | ||
| 15 | Populates an extra partition with files listed in the IMAGE_EXTRA_FILES | ||
| 16 | BitBake variable. Files should be deployed to the DEPLOY_DIR_IMAGE directory. | ||
| 17 | |||
| 18 | The plugin supports: | ||
| 19 | - Glob pattern matching for file selection. | ||
| 20 | - File renaming. | ||
| 21 | - Suffixes to specify the target partition (by label, UUID, or partname), | ||
| 22 | enabling multiple extra partitions to coexist. | ||
| 23 | |||
| 24 | For example: | ||
| 25 | |||
| 26 | IMAGE_EXTRA_FILES_label-foo = "bar.conf;foo.conf" | ||
| 27 | IMAGE_EXTRA_FILES_uuid-e7d0824e-cda3-4bed-9f54-9ef5312d105d = "bar.conf;foobar.conf" | ||
| 28 | IMAGE_EXTRA_FILES = "foo/*" | ||
| 29 | WICVARS:append = "\ | ||
| 30 | IMAGE_EXTRA_FILES_label-foo \ | ||
| 31 | IMAGE_EXTRA_FILES_uuid-e7d0824e-cda3-4bed-9f54-9ef5312d105d \ | ||
| 32 | " | ||
| 33 | |||
| 34 | """ | ||
| 35 | |||
| 36 | name = 'extra_partition' | ||
| 37 | image_extra_files_var_name = 'IMAGE_EXTRA_FILES' | ||
| 38 | |||
| 39 | @classmethod | ||
| 40 | def do_configure_partition(cls, part, source_params, cr, cr_workdir, | ||
| 41 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 42 | native_sysroot): | ||
| 43 | """ | ||
| 44 | Called before do_prepare_partition(), list the files to copy | ||
| 45 | """ | ||
| 46 | extradir = "%s/extra.%d" % (cr_workdir, part.lineno) | ||
| 47 | install_cmd = "install -d %s" % extradir | ||
| 48 | exec_cmd(install_cmd) | ||
| 49 | |||
| 50 | if not kernel_dir: | ||
| 51 | kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") | ||
| 52 | if not kernel_dir: | ||
| 53 | raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") | ||
| 54 | |||
| 55 | extra_files = None | ||
| 56 | for (fmt, id) in (("_uuid-%s", part.uuid), ("_label-%s", part.label), ("_part-name-%s", part.part_name), (None, None)): | ||
| 57 | if fmt: | ||
| 58 | var = fmt % id | ||
| 59 | else: | ||
| 60 | var = "" | ||
| 61 | extra_files = get_bitbake_var(cls.image_extra_files_var_name + var) | ||
| 62 | if extra_files is not None: | ||
| 63 | break | ||
| 64 | |||
| 65 | if extra_files is None: | ||
| 66 | raise WicError('No extra files defined, %s unset for entry #%d' % (cls.image_extra_files_var_name, part.lineno)) | ||
| 67 | |||
| 68 | logger.info('Extra files: %s', extra_files) | ||
| 69 | |||
| 70 | # list of tuples (src_name, dst_name) | ||
| 71 | deploy_files = [] | ||
| 72 | for src_entry in re.findall(r'[\w;\-\./\*]+', extra_files): | ||
| 73 | if ';' in src_entry: | ||
| 74 | dst_entry = tuple(src_entry.split(';')) | ||
| 75 | if not dst_entry[0] or not dst_entry[1]: | ||
| 76 | raise WicError('Malformed extra file entry: %s' % src_entry) | ||
| 77 | else: | ||
| 78 | dst_entry = (src_entry, src_entry) | ||
| 79 | |||
| 80 | logger.debug('Destination entry: %r', dst_entry) | ||
| 81 | deploy_files.append(dst_entry) | ||
| 82 | |||
| 83 | cls.install_task = []; | ||
| 84 | for deploy_entry in deploy_files: | ||
| 85 | src, dst = deploy_entry | ||
| 86 | if '*' in src: | ||
| 87 | # by default install files under their basename | ||
| 88 | entry_name_fn = os.path.basename | ||
| 89 | if dst != src: | ||
| 90 | # unless a target name was given, then treat name | ||
| 91 | # as a directory and append a basename | ||
| 92 | entry_name_fn = lambda name: \ | ||
| 93 | os.path.join(dst, | ||
| 94 | os.path.basename(name)) | ||
| 95 | |||
| 96 | srcs = glob(os.path.join(kernel_dir, src)) | ||
| 97 | |||
| 98 | logger.debug('Globbed sources: %s', ', '.join(srcs)) | ||
| 99 | for entry in srcs: | ||
| 100 | src = os.path.relpath(entry, kernel_dir) | ||
| 101 | entry_dst_name = entry_name_fn(entry) | ||
| 102 | cls.install_task.append((src, entry_dst_name)) | ||
| 103 | else: | ||
| 104 | cls.install_task.append((src, dst)) | ||
| 105 | |||
| 106 | |||
| 107 | @classmethod | ||
| 108 | def do_prepare_partition(cls, part, source_params, cr, cr_workdir, | ||
| 109 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 110 | rootfs_dir, native_sysroot): | ||
| 111 | """ | ||
| 112 | Called to do the actual content population for a partition i.e. it | ||
| 113 | 'prepares' the partition to be incorporated into the image. | ||
| 114 | In this case, we copies all files listed in IMAGE_EXTRA_FILES variable. | ||
| 115 | """ | ||
| 116 | extradir = "%s/extra.%d" % (cr_workdir, part.lineno) | ||
| 117 | |||
| 118 | if not kernel_dir: | ||
| 119 | kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") | ||
| 120 | if not kernel_dir: | ||
| 121 | raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting") | ||
| 122 | |||
| 123 | for task in cls.install_task: | ||
| 124 | src_path, dst_path = task | ||
| 125 | logger.debug('Install %s as %s', src_path, dst_path) | ||
| 126 | install_cmd = "install -m 0644 -D %s %s" \ | ||
| 127 | % (os.path.join(kernel_dir, src_path), | ||
| 128 | os.path.join(extradir, dst_path)) | ||
| 129 | exec_cmd(install_cmd) | ||
| 130 | |||
| 131 | logger.debug('Prepare extra partition using rootfs in %s', extradir) | ||
| 132 | part.prepare_rootfs(cr_workdir, oe_builddir, extradir, | ||
| 133 | native_sysroot, False) | ||
| 134 | |||
