michael.hudson@canonical.com ff3addb2f8
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.
2026-02-19 13:17:35 +13:00

105 lines
3.1 KiB
Python

"""GRUB boot configuration for multiple architectures."""
import pathlib
import shutil
from abc import abstractmethod
from .base import BaseBootConfigurator
def copy_grub_common_files_to_boot_tree(
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_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).
Common GRUB functionality shared across AMD64, ARM64, PPC64EL, and RISC-V64.
Subclasses must implement generate_grub_config().
"""
def write_grub_header(
self, grub_cfg: pathlib.Path, include_loadfont: bool = True
) -> None:
"""Write common GRUB config header (timeout, colors).
Args:
grub_cfg: Path to grub.cfg file
include_loadfont: Whether to include 'loadfont unicode'
(not needed for RISC-V)
"""
with grub_cfg.open("a") as f:
f.write("set timeout=30\n\n")
if include_loadfont:
f.write("loadfont unicode\n\n")
f.write(
"""set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
"""
)
def write_hwe_menu_entry(
self,
grub_cfg: pathlib.Path,
kernel_name: str,
kernel_params: str,
extra_params: str = "",
) -> None:
"""Write HWE kernel menu entry if HWE is enabled.
Args:
grub_cfg: Path to grub.cfg file
kernel_name: Kernel binary name (vmlinuz or vmlinux)
kernel_params: Kernel parameters to append
extra_params: Additional parameters (e.g., console=tty0, $cmdline)
"""
if self.hwe:
with grub_cfg.open("a") as f:
f.write(
f"""menuentry "{self.humanproject} with the HWE kernel" {{
\tset gfxpayload=keep
\tlinux\t/casper/hwe-{kernel_name} {extra_params}{kernel_params}
\tinitrd\t/casper/hwe-initrd
}}
"""
)
@abstractmethod
def generate_grub_config(self) -> None:
"""Generate grub.cfg configuration file.
Each GRUB-based architecture must implement this to create its
specific GRUB configuration.
"""
...
def make_bootable(
self,
workdir: pathlib.Path,
project: str,
capproject: str,
subarch: str,
hwe: bool,
) -> None:
"""Make the ISO bootable by extracting files and generating GRUB config."""
super().make_bootable(workdir, project, capproject, subarch, hwe)
with self.logger.logged("generating grub config"):
self.generate_grub_config()