From ff3addb2f8ac8645031a7950681942c045bd8281 Mon Sep 17 00:00:00 2001 From: "michael.hudson@canonical.com" Date: Thu, 19 Feb 2026 12:37:24 +1300 Subject: [PATCH] Extract packages to scratch dirs instead of boot tree subdirs Package contents were being extracted into subdirectories of the boot tree (grub_dir, shim_dir), which meant the boot tree contained both the final boot files and the raw package extractions. Extract packages into scratch directories instead, copying only the needed files into the boot tree. This also removes the grub_dir/shim_dir instance variables and the create_dirs overrides, and moves copy_grub_modules to a standalone function in grub.py. --- live-build/isobuilder/boot/amd64.py | 13 ++++++---- live-build/isobuilder/boot/arm64.py | 2 +- live-build/isobuilder/boot/base.py | 9 ------- live-build/isobuilder/boot/grub.py | 21 +++++++++-------- live-build/isobuilder/boot/ppc64el.py | 20 ++++++++++------ live-build/isobuilder/boot/riscv64.py | 24 ++++++++++++------- live-build/isobuilder/boot/uefi.py | 34 ++++++++++++++------------- 7 files changed, 66 insertions(+), 57 deletions(-) diff --git a/live-build/isobuilder/boot/amd64.py b/live-build/isobuilder/boot/amd64.py index 31260662..d17eb196 100644 --- a/live-build/isobuilder/boot/amd64.py +++ b/live-build/isobuilder/boot/amd64.py @@ -3,8 +3,9 @@ import pathlib import shutil -from .uefi import UEFIBootConfigurator from .base import default_kernel_params +from .grub import copy_grub_modules +from .uefi import UEFIBootConfigurator CALAMARES_PROJECTS = ["kubuntu", "lubuntu"] @@ -51,7 +52,7 @@ class AMD64BootConfigurator(UEFIBootConfigurator): opts.extend( [ "--grub2-mbr", - self.grub_dir.joinpath("usr/lib/grub/i386-pc/boot_hybrid.img"), + self.scratch.joinpath("boot_hybrid.img"), ] ) @@ -71,16 +72,18 @@ class AMD64BootConfigurator(UEFIBootConfigurator): # AMD64-specific: Add BIOS/legacy boot files with self.logger.logged("adding BIOS/legacy boot files"): - self.download_and_extract_package("grub-pc-bin", self.grub_dir) + grub_pc_pkg_dir = self.scratch.joinpath("grub-pc-pkg") + self.download_and_extract_package("grub-pc-bin", grub_pc_pkg_dir) grub_boot_dir = self.boot_tree.joinpath("boot", "grub", "i386-pc") grub_boot_dir.mkdir(parents=True, exist_ok=True) - src_grub_dir = self.grub_dir.joinpath("usr", "lib", "grub", "i386-pc") + src_grub_dir = grub_pc_pkg_dir.joinpath("usr", "lib", "grub", "i386-pc") shutil.copy(src_grub_dir.joinpath("eltorito.img"), grub_boot_dir) + shutil.copy(src_grub_dir.joinpath("boot_hybrid.img"), self.scratch) - self.copy_grub_modules( + copy_grub_modules( src_grub_dir, grub_boot_dir, ["*.mod", "*.lst", "*.o"] ) diff --git a/live-build/isobuilder/boot/arm64.py b/live-build/isobuilder/boot/arm64.py index b1623e4d..aa7e168b 100644 --- a/live-build/isobuilder/boot/arm64.py +++ b/live-build/isobuilder/boot/arm64.py @@ -38,7 +38,7 @@ class ARM64BootConfigurator(UEFIBootConfigurator): """Generate grub.cfg for ARM64.""" kernel_params = default_kernel_params(self.project) - grub_cfg = self.grub_dir.joinpath("grub.cfg") + grub_cfg = self.boot_tree.joinpath("boot", "grub", "grub.cfg") # Write common GRUB header self.write_grub_header(grub_cfg) diff --git a/live-build/isobuilder/boot/base.py b/live-build/isobuilder/boot/base.py index 8ca8b8f9..6e961900 100644 --- a/live-build/isobuilder/boot/base.py +++ b/live-build/isobuilder/boot/base.py @@ -1,7 +1,6 @@ """Base classes and helper functions for boot configuration.""" import pathlib -import shutil import subprocess import tempfile from abc import ABC, abstractmethod @@ -65,14 +64,6 @@ class BaseBootConfigurator(ABC): dpkg_proc.stdout.close() tar_proc.communicate() - def copy_grub_modules( - self, src_dir: pathlib.Path, dest_dir: pathlib.Path, extensions: list[str] - ) -> None: - """Copy GRUB module files matching given extensions from src to dest.""" - for ext in extensions: - for file in src_dir.glob(ext): - shutil.copy(file, dest_dir) - @abstractmethod def extract_files(self) -> None: """Download and extract bootloader packages to the boot tree. diff --git a/live-build/isobuilder/boot/grub.py b/live-build/isobuilder/boot/grub.py index 528135e4..cb9efaed 100644 --- a/live-build/isobuilder/boot/grub.py +++ b/live-build/isobuilder/boot/grub.py @@ -8,16 +8,25 @@ from .base import BaseBootConfigurator def copy_grub_common_files_to_boot_tree( - grub_dir: pathlib.Path, boot_tree: pathlib.Path + grub_pkg_dir: pathlib.Path, boot_tree: pathlib.Path ) -> None: fonts_dir = boot_tree.joinpath("boot", "grub", "fonts") fonts_dir.mkdir(parents=True, exist_ok=True) - src = grub_dir.joinpath("usr", "share", "grub", "unicode.pf2") + src = grub_pkg_dir.joinpath("usr", "share", "grub", "unicode.pf2") dst = fonts_dir.joinpath("unicode.pf2") shutil.copy(src, dst) +def copy_grub_modules( + src_dir: pathlib.Path, dest_dir: pathlib.Path, patterns: list[str] +) -> None: + """Copy GRUB module files matching given patterns from src to dest.""" + for pat in patterns: + for file in src_dir.glob(pat): + shutil.copy(file, dest_dir) + + class GrubBootConfigurator(BaseBootConfigurator): """Base class for architectures that use GRUB (all except S390X). @@ -25,14 +34,6 @@ class GrubBootConfigurator(BaseBootConfigurator): Subclasses must implement generate_grub_config(). """ - def create_dirs(self, workdir): - super().create_dirs(workdir) - self.grub_dir = self.boot_tree.joinpath("grub") - - def setup_grub_common_files(self) -> None: - """Copy common GRUB files (fonts, etc.) to boot tree.""" - copy_grub_common_files_to_boot_tree(self.grub_dir, self.boot_tree) - def write_grub_header( self, grub_cfg: pathlib.Path, include_loadfont: bool = True ) -> None: diff --git a/live-build/isobuilder/boot/ppc64el.py b/live-build/isobuilder/boot/ppc64el.py index db731591..3ccd98e5 100644 --- a/live-build/isobuilder/boot/ppc64el.py +++ b/live-build/isobuilder/boot/ppc64el.py @@ -3,7 +3,11 @@ import pathlib import shutil -from .grub import GrubBootConfigurator +from .grub import ( + copy_grub_common_files_to_boot_tree, + copy_grub_modules, + GrubBootConfigurator, +) from .base import default_kernel_params @@ -19,12 +23,14 @@ class PPC64ELBootConfigurator(GrubBootConfigurator): """Download and extract bootloader packages for PPC64EL.""" self.logger.log("extracting PPC64EL boot files") + grub_pkg_dir = self.scratch.joinpath("grub-pkg") + # Download and extract bootloader packages - self.download_and_extract_package("grub2-common", self.grub_dir) - self.download_and_extract_package("grub-ieee1275-bin", self.grub_dir) + self.download_and_extract_package("grub2-common", grub_pkg_dir) + self.download_and_extract_package("grub-ieee1275-bin", grub_pkg_dir) # Add common files for GRUB to tree - self.setup_grub_common_files() + copy_grub_common_files_to_boot_tree(grub_pkg_dir, self.boot_tree) # Add IEEE1275 ppc boot files ppc_dir = self.boot_tree.joinpath("ppc") @@ -33,7 +39,7 @@ class PPC64ELBootConfigurator(GrubBootConfigurator): grub_boot_dir = self.boot_tree.joinpath("boot", "grub", "powerpc-ieee1275") grub_boot_dir.mkdir(parents=True, exist_ok=True) - src_grub_dir = self.grub_dir.joinpath("usr", "lib", "grub", "powerpc-ieee1275") + src_grub_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", "powerpc-ieee1275") # Copy bootinfo.txt to ppc directory shutil.copy( @@ -47,13 +53,13 @@ class PPC64ELBootConfigurator(GrubBootConfigurator): ) # Copy GRUB modules - self.copy_grub_modules(src_grub_dir, grub_boot_dir, ["*.mod", "*.lst"]) + copy_grub_modules(src_grub_dir, grub_boot_dir, ["*.mod", "*.lst"]) def generate_grub_config(self) -> None: """Generate grub.cfg for PPC64EL.""" kernel_params = default_kernel_params(self.project) - grub_cfg = self.grub_dir.joinpath("grub.cfg") + grub_cfg = self.boot_tree.joinpath("boot", "grub", "grub.cfg") # Write common GRUB header self.write_grub_header(grub_cfg) diff --git a/live-build/isobuilder/boot/riscv64.py b/live-build/isobuilder/boot/riscv64.py index 6b52f1ec..a57fe590 100644 --- a/live-build/isobuilder/boot/riscv64.py +++ b/live-build/isobuilder/boot/riscv64.py @@ -3,17 +3,20 @@ import pathlib import shutil -from .grub import GrubBootConfigurator +from .grub import GrubBootConfigurator, copy_grub_common_files_to_boot_tree def copy_unsigned_monolithic_grub_to_boot_tree( - grub_dir: pathlib.Path, efi_suffix: str, grub_target: str, boot_tree: pathlib.Path + grub_pkg_dir: pathlib.Path, + efi_suffix: str, + grub_target: str, + boot_tree: pathlib.Path, ) -> None: efi_boot_dir = boot_tree.joinpath("EFI", "boot") efi_boot_dir.mkdir(parents=True, exist_ok=True) shutil.copy( - grub_dir.joinpath( + grub_pkg_dir.joinpath( "usr", "lib", "grub", @@ -27,7 +30,7 @@ def copy_unsigned_monolithic_grub_to_boot_tree( grub_boot_dir = boot_tree.joinpath("boot", "grub", f"{grub_target}-efi") grub_boot_dir.mkdir(parents=True, exist_ok=True) - src_grub_dir = grub_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi") + src_grub_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi") for mod_file in src_grub_dir.glob("*.mod"): shutil.copy(mod_file, grub_boot_dir) for lst_file in src_grub_dir.glob("*.lst"): @@ -74,16 +77,19 @@ class RISCV64BootConfigurator(GrubBootConfigurator): self.logger.log("extracting RISC-V64 boot files") u_boot_dir = self.scratch.joinpath("u-boot-sifive") + grub_pkg_dir = self.scratch.joinpath("grub-pkg") + # Download and extract bootloader packages - self.download_and_extract_package("grub2-common", self.grub_dir) - self.download_and_extract_package("grub-efi-riscv64-bin", self.grub_dir) - self.download_and_extract_package("grub-efi-riscv64-unsigned", self.grub_dir) + self.download_and_extract_package("grub2-common", grub_pkg_dir) + self.download_and_extract_package("grub-efi-riscv64-bin", grub_pkg_dir) + self.download_and_extract_package("grub-efi-riscv64-unsigned", grub_pkg_dir) self.download_and_extract_package("u-boot-sifive", u_boot_dir) # Add GRUB to tree - self.setup_grub_common_files() + copy_grub_common_files_to_boot_tree(grub_pkg_dir, self.boot_tree) + copy_unsigned_monolithic_grub_to_boot_tree( - self.grub_dir, "riscv64", "riscv64", self.boot_tree + grub_pkg_dir, "riscv64", "riscv64", self.boot_tree ) # Extract DTBs to tree diff --git a/live-build/isobuilder/boot/uefi.py b/live-build/isobuilder/boot/uefi.py index ca991c1c..95f381e0 100644 --- a/live-build/isobuilder/boot/uefi.py +++ b/live-build/isobuilder/boot/uefi.py @@ -4,12 +4,12 @@ import pathlib import shutil from ..builder import Logger -from .grub import GrubBootConfigurator +from .grub import copy_grub_common_files_to_boot_tree, GrubBootConfigurator def copy_signed_shim_grub_to_boot_tree( - shim_dir: pathlib.Path, - grub_dir: pathlib.Path, + shim_pkg_dir: pathlib.Path, + grub_pkg_dir: pathlib.Path, efi_suffix: str, grub_target: str, boot_tree: pathlib.Path, @@ -18,15 +18,17 @@ def copy_signed_shim_grub_to_boot_tree( efi_boot_dir.mkdir(parents=True, exist_ok=True) shutil.copy( - shim_dir.joinpath("usr", "lib", "shim", f"shim{efi_suffix}.efi.signed.latest"), + shim_pkg_dir.joinpath( + "usr", "lib", "shim", f"shim{efi_suffix}.efi.signed.latest" + ), efi_boot_dir.joinpath(f"boot{efi_suffix}.efi"), ) shutil.copy( - shim_dir.joinpath("usr", "lib", "shim", f"mm{efi_suffix}.efi"), + shim_pkg_dir.joinpath("usr", "lib", "shim", f"mm{efi_suffix}.efi"), efi_boot_dir.joinpath(f"mm{efi_suffix}.efi"), ) shutil.copy( - grub_dir.joinpath( + grub_pkg_dir.joinpath( "usr", "lib", "grub", @@ -39,7 +41,7 @@ def copy_signed_shim_grub_to_boot_tree( grub_boot_dir = boot_tree.joinpath("boot", "grub", f"{grub_target}-efi") grub_boot_dir.mkdir(parents=True, exist_ok=True) - src_grub_dir = grub_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi") + src_grub_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi") for mod_file in src_grub_dir.glob("*.mod"): shutil.copy(mod_file, grub_boot_dir) for lst_file in src_grub_dir.glob("*.lst"): @@ -84,10 +86,6 @@ class UEFIBootConfigurator(GrubBootConfigurator): grub_target: str = "" arch: str = "" - def create_dirs(self, workdir): - super().create_dirs(workdir) - self.shim_dir = self.boot_tree.joinpath("shim") - def get_uefi_grub_packages(self) -> list[str]: """Return list of UEFI GRUB packages to download.""" return [ @@ -98,18 +96,22 @@ class UEFIBootConfigurator(GrubBootConfigurator): def extract_uefi_files(self) -> None: """Extract common UEFI files to boot tree.""" + + shim_pkg_dir = self.scratch.joinpath("shim-pkg") + grub_pkg_dir = self.scratch.joinpath("grub-pkg") + # Download UEFI packages - self.download_and_extract_package("shim-signed", self.shim_dir) + self.download_and_extract_package("shim-signed", shim_pkg_dir) for pkg in self.get_uefi_grub_packages(): - self.download_and_extract_package(pkg, self.grub_dir) + self.download_and_extract_package(pkg, grub_pkg_dir) # Add common files for GRUB to tree - self.setup_grub_common_files() + copy_grub_common_files_to_boot_tree(grub_pkg_dir, self.boot_tree) # Add EFI GRUB to tree copy_signed_shim_grub_to_boot_tree( - self.shim_dir, - self.grub_dir, + shim_pkg_dir, + grub_pkg_dir, self.efi_suffix, self.grub_target, self.boot_tree,