diff options
author | Lamine REHAHLIA <lamine.rehahlia@smile.fr> | 2025-07-31 17:33:10 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-08-06 22:32:41 +0100 |
commit | 820a6edcec880ff02deb3fdb0a60832e57726bcd (patch) | |
tree | 036bbd362146316072d9e52de545642754e0b007 /scripts/runqemu | |
parent | d4b949b1782fb888e2a11000c90941900cdc2155 (diff) | |
download | poky-820a6edcec880ff02deb3fdb0a60832e57726bcd.tar.gz |
runqemu: Add support for running compressed .zst rootfs images
Enhance runqemu to detect and decompress .zst-compressed rootfs images
(e.g. ext4.zst, wic.zst) automatically. If a decompressed image already
exists in the original directory, it will be reused to avoid overwriting
build artifacts. Otherwise, the image is decompressed and removed after
the QEMU session ends.
This allows runqemu to be used seamlessly with compressed image formats
generated by the build system or during releases.
Note: support for .zst images is only available when snapshot mode is
enabled
IMPORTANT:
This patch assumes that the original directory of the .zst-compressed
image is writable. If, for some reason, the path passed from CI or
another system to the script is read-only, the decompression step will
fail when trying to write the uncompressed image to the same directory.
(From OE-Core rev: e069fe2480c871c649b83f6278564a553cc3dd58)
Signed-off-by: Lamine REHAHLIA <lamine.rehahlia@smile.fr>
Signed-off-by: Yoann Congal <yoann.congal@smile.fr>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/runqemu')
-rwxr-xr-x | scripts/runqemu | 45 |
1 files changed, 44 insertions, 1 deletions
diff --git a/scripts/runqemu b/scripts/runqemu index 3d77046972..c668906bdd 100755 --- a/scripts/runqemu +++ b/scripts/runqemu | |||
@@ -197,7 +197,7 @@ class BaseConfig(object): | |||
197 | self.portlocks = {} | 197 | self.portlocks = {} |
198 | self.bitbake_e = '' | 198 | self.bitbake_e = '' |
199 | self.snapshot = False | 199 | self.snapshot = False |
200 | self.wictypes = ('wic', 'wic.vmdk', 'wic.qcow2', 'wic.vdi', "wic.vhd", "wic.vhdx") | 200 | self.wictypes = ('wic.zst', 'wic', 'wic.vmdk', 'wic.qcow2', 'wic.vdi', "wic.vhd", "wic.vhdx") |
201 | self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs', | 201 | self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs', |
202 | 'cpio.gz', 'cpio', 'ramfs', 'tar.bz2', 'tar.gz', | 202 | 'cpio.gz', 'cpio', 'ramfs', 'tar.bz2', 'tar.gz', |
203 | 'squashfs', 'squashfs-xz', 'squashfs-lzo', | 203 | 'squashfs', 'squashfs-xz', 'squashfs-lzo', |
@@ -418,6 +418,48 @@ class BaseConfig(object): | |||
418 | else: | 418 | else: |
419 | raise RunQemuError("Unknown path arg %s" % p) | 419 | raise RunQemuError("Unknown path arg %s" % p) |
420 | 420 | ||
421 | def uncompress_rootfs(self): | ||
422 | """Decompress ZST rootfs image if needed""" | ||
423 | if not self.rootfs or not self.fstype.endswith('.zst'): | ||
424 | return | ||
425 | |||
426 | # Ensure snapshot mode is active before allowing decompression. | ||
427 | if not self.snapshot: | ||
428 | raise RunQemuError(".zst images are only supported with snapshot mode. " \ | ||
429 | "You can either use the \"snapshot\" option or use an uncompressed image.") | ||
430 | |||
431 | # Get the real path to the image to avoid issues when a symbolic link is passed. | ||
432 | # This ensures we always operate on the actual file. | ||
433 | image_path = os.path.realpath(self.rootfs) | ||
434 | # Extract target filename by removing .zst | ||
435 | image_dir = os.path.dirname(image_path) | ||
436 | uncompressed_name = os.path.basename(image_path).replace(".zst", "") | ||
437 | uncompressed_path = os.path.join(image_dir, uncompressed_name) | ||
438 | |||
439 | # If the decompressed image already exists (e.g., in the deploy directory), | ||
440 | # we use it directly to avoid overwriting artifacts generated by the build system. | ||
441 | # This prevents redundant decompression and preserves build outputs. | ||
442 | if os.path.exists(uncompressed_path): | ||
443 | logger.warning(f"Found existing decompressed image: {uncompressed_path}, Using it directly.") | ||
444 | else: | ||
445 | logger.info(f"Decompressing {self.rootfs} to {uncompressed_path}") | ||
446 | # Ensure the 'zstd' tool is installed before attempting to decompress. | ||
447 | if not shutil.which('zstd'): | ||
448 | raise RunQemuError(f"'zstd' is required to decompress {self.rootfs} but was not found in PATH") | ||
449 | try: | ||
450 | with open(uncompressed_path, 'wb') as out_file: | ||
451 | subprocess.check_call(['zstd', '-d', '-c', image_path], stdout=out_file) | ||
452 | except subprocess.CalledProcessError as e: | ||
453 | self.cleanup_files.append(uncompressed_path) | ||
454 | raise RunQemuError(f"Failed to decompress {self.rootfs}: {e}") | ||
455 | |||
456 | # Mark for deletion at the end | ||
457 | self.cleanup_files.append(uncompressed_path) | ||
458 | |||
459 | # Use the decompressed image as the rootfs | ||
460 | self.rootfs = uncompressed_path | ||
461 | self.fstype = self.fstype.removesuffix(".zst") | ||
462 | |||
421 | def check_arg_machine(self, arg): | 463 | def check_arg_machine(self, arg): |
422 | """Check whether it is a machine""" | 464 | """Check whether it is a machine""" |
423 | if self.get('MACHINE') == arg: | 465 | if self.get('MACHINE') == arg: |
@@ -1762,6 +1804,7 @@ def main(): | |||
1762 | config.check_args() | 1804 | config.check_args() |
1763 | config.read_qemuboot() | 1805 | config.read_qemuboot() |
1764 | config.check_and_set() | 1806 | config.check_and_set() |
1807 | config.uncompress_rootfs() | ||
1765 | # Check whether the combos is valid or not | 1808 | # Check whether the combos is valid or not |
1766 | config.validate_combos() | 1809 | config.validate_combos() |
1767 | config.print_config() | 1810 | config.print_config() |