From 95fc6abc8d35c50fd163419e5d3789769f378b4c Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 13 Oct 2026 05:01:33 +0300 Subject: [PATCH] fix(image): select actual Gentoo distribution kernel image --- hydra/build.py | 2 +- hydra/image.py | 23 +++++++++++++++++++---- tests/test_image.py | 13 +++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/hydra/build.py b/hydra/build.py index 62af262..4440554 100644 --- a/hydra/build.py +++ b/hydra/build.py @@ -430,7 +430,7 @@ mkdir -p "$root" touch "$root/.hydra-export-owned" tar --extract --preserve-permissions --numeric-owner --file /hydra-output/artifacts/builder-rootfs.tar --directory "$root" /hydra-source/image/configure-rootfs.sh "$root" -cp "$root/boot/vmlinuz-$(python3 /hydra-source/hydra/image.py kernel "$root")" /hydra-output/artifacts/vmlinuz +cp "$(python3 /hydra-source/hydra/image.py kernel-image "$root")" /hydra-output/artifacts/vmlinuz cp "$root/boot/initramfs-live.img" /hydra-output/artifacts/initramfs-live.img cp "$root/usr/share/hydra/build-manifest.json" /hydra-output/artifacts/rootfs-manifest.json # Keep ownership for safe retries outside the shipped payload. diff --git a/hydra/image.py b/hydra/image.py index 1ca571c..9d7eebe 100644 --- a/hydra/image.py +++ b/hydra/image.py @@ -129,16 +129,29 @@ def copy_overlay(root, overlay): destination.chmod(source.stat().st_mode & 0o777) -def kernel_version(root): +def _kernel_version(root): modules = root_path(root, 'lib/modules') versions = sorted(path.name for path in modules.iterdir() if path.is_dir()) if modules.is_dir() else [] if len(versions) != 1 or not re.fullmatch(r'[A-Za-z0-9_.+-]+', versions[0]): raise ImageError('Exactly one installed payload kernel is required') - if not root_path(root, 'boot/vmlinuz-' + versions[0]).is_file(): - raise ImageError('Installed modules have no matching /boot/vmlinuz-VERSION') return versions[0] +def kernel_image(root): + version = _kernel_version(root) + candidates = [root_path(root, 'boot/' + prefix + version) + for prefix in ('kernel-', 'vmlinuz-')] + images = [path for path in candidates if path.is_file()] + if len(images) != 1: + raise ImageError('Installed modules require exactly one matching boot kernel image') + return images[0] + + +def kernel_version(root): + kernel_image(root) + return _kernel_version(root) + + def live_kernel_args(): return [f'root=live:CDLABEL={LABEL}', 'rd.live.image', 'rd.live.overlay.overlayfs=1', 'ro', 'console=tty0', 'console=ttyS0,115200n8'] @@ -356,7 +369,7 @@ def digest(path): def main(argv=None): parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('step', choices=('configure', 'kernel', 'network', 'audio')) + parser.add_argument('step', choices=('configure', 'kernel', 'kernel-image', 'network', 'audio')) parser.add_argument('root', nargs='?', type=Path) parser.add_argument('--source', type=Path) options = parser.parse_args(argv) @@ -367,6 +380,8 @@ def main(argv=None): raise ImageError('An isolated rootfs directory is required') if options.step == 'kernel': print(kernel_version(options.root)) + elif options.step == 'kernel-image': + print(kernel_image(options.root)) elif options.step == 'audio': enable_user_audio(options.root) else: diff --git a/tests/test_image.py b/tests/test_image.py index 55c0487..7aade23 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -39,6 +39,19 @@ class ImageTests(unittest.TestCase): self.kernel() self.assertEqual(image.kernel_version(self.root), '6.12.58-gentoo-dist') + def test_real_gentoo_kernel_bin_layout(self): + version = '6.18.54-gentoo-dist-bin' + (self.root / 'lib/modules' / version).mkdir(parents=True) + kernel = self.file('boot/kernel-' + version, 'real Gentoo kernel') + self.assertEqual(image.kernel_version(self.root), version) + self.assertEqual(image.kernel_image(self.root), kernel) + + def test_conflicting_kernel_images_refused(self): + version = self.kernel() + self.file('boot/kernel-' + version, 'different kernel') + with self.assertRaises(image.ImageError): + image.kernel_version(self.root) + def test_ambiguous_or_missing_kernel_refused(self): with self.assertRaises(image.ImageError): image.kernel_version(self.root)