summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLamine REHAHLIA <lamine.rehahlia@smile.fr>2025-07-31 17:33:10 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-08-06 22:32:41 +0100
commit820a6edcec880ff02deb3fdb0a60832e57726bcd (patch)
tree036bbd362146316072d9e52de545642754e0b007
parentd4b949b1782fb888e2a11000c90941900cdc2155 (diff)
downloadpoky-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>
-rwxr-xr-xscripts/runqemu45
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()