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.
This commit is contained in:
michael.hudson@canonical.com 2026-02-19 12:37:24 +13:00
parent 460037fb4d
commit ff3addb2f8
No known key found for this signature in database
GPG Key ID: 80E627A0AB757E23
7 changed files with 66 additions and 57 deletions

View File

@ -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"]
)

View File

@ -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)

View File

@ -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.

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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,