From 3d6dd598424cc5675330f7ca9fdb20807de8d2d9 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 12 Dec 2023 12:26:45 +0100 Subject: [PATCH] mkosi-initrd: Rewrite kernel-install plugin in python and support UKIs There's really no point for the kernel-install plugin to be in bash, so let's rewrite it in python. While we're at it, let's also support running as a UKI generator. --- .github/workflows/ci.yml | 6 +- kernel-install/50-mkosi-initrd.install | 47 ------ kernel-install/50-mkosi.install | 134 ++++++++++++++++++ .../mkosi-initrd/mkosi.conf.d/20-stub.conf | 8 ++ 4 files changed, 145 insertions(+), 50 deletions(-) delete mode 100644 kernel-install/50-mkosi-initrd.install create mode 100644 kernel-install/50-mkosi.install create mode 100644 mkosi/resources/mkosi-initrd/mkosi.conf.d/20-stub.conf diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02ec88ed3..9c5f8fb5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: - name: Run ruff run: | ruff --version - ruff mkosi/ tests/ + ruff mkosi/ tests/ kernel-install/50-mkosi.install - name: Check that tabs are not used in code run: sh -c '! git grep -P "\\t" "*.py"' @@ -36,12 +36,12 @@ jobs: - name: Type Checking (mypy) run: | python3 -m mypy --version - python3 -m mypy mkosi/ tests/ + python3 -m mypy mkosi/ tests/ kernel-install/50-mkosi.install - name: Type Checking (pyright) run: | pyright --version - pyright mkosi/ tests/ + pyright mkosi/ tests/ kernel-install/50-mkosi.install - name: Unit Tests run: | diff --git a/kernel-install/50-mkosi-initrd.install b/kernel-install/50-mkosi-initrd.install deleted file mode 100644 index 1b3e6c059..000000000 --- a/kernel-install/50-mkosi-initrd.install +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/bash -# SPDX-License-Identifier: LGPL-2.1-or-later -set -e -export LANG=C.UTF-8 - -COMMAND="$1" -KERNEL_VERSION="$2" -BOOT_DIR_ABS="$3" -KERNEL_IMAGE="$4" -INITRD_OPTIONS_SHIFT=4 - -# Skip this plugin if we're using a different generator. -[ "${KERNEL_INSTALL_INITRD_GENERATOR}" != "mkosi-initrd" ] && exit 0 - -: "${KERNEL_INSTALL_STAGING_AREA:?}" - -case "$COMMAND" in - add) - # If the initrd was provided on the kernel command line, we shouldn't generate our own. - [ "$#" -gt "$INITRD_OPTIONS_SHIFT" ] && exit 0 - - ( - [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && set -x - - mkosi --directory "" \ - $([ -e /usr/lib/mkosi-initrd ] && echo --include=/usr/lib/mkosi-initrd) \ - $([ -e /etc/mkosi-initrd ] && echo --include=/etc/mkosi-initrd) \ - --image-version="$KERNEL_VERSION" \ - --environment="KERNEL_VERSION=$KERNEL_VERSION" \ - --workspace-dir=/var/tmp \ - --cache-dir=/var/cache \ - --output-dir="$KERNEL_INSTALL_STAGING_AREA" \ - --extra-tree="/usr/lib/modules/${KERNEL_VERSION}:/usr/lib/modules/${KERNEL_VERSION}" \ - --extra-tree="/usr/lib/firmware:/usr/lib/firmware" \ - --kernel-modules-exclude=".*" \ - --kernel-modules-include-host=yes - - rm "${KERNEL_INSTALL_STAGING_AREA}/initrd" - mv -v "${KERNEL_INSTALL_STAGING_AREA}"/initrd_*.cpio.zst "${KERNEL_INSTALL_STAGING_AREA}/initrd" - ) - ;; - - remove) - ;; -esac - -exit 0 diff --git a/kernel-install/50-mkosi.install b/kernel-install/50-mkosi.install new file mode 100644 index 000000000..c8f1e9177 --- /dev/null +++ b/kernel-install/50-mkosi.install @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1+ + +import argparse +import logging +import os +import shutil +from pathlib import Path +from typing import NamedTuple, Optional + +from mkosi.config import OutputFormat, __version__ +from mkosi.log import die, log_setup +from mkosi.run import run, uncaught_exception_handler +from mkosi.types import PathString + + +class Context(NamedTuple): + command: str + kernel_version: str + entry_dir: Path + kernel_image: Path + initrds: list[Path] + staging_area: Path + layout: str + image_type: str + initrd_generator: Optional[str] + uki_generator: Optional[str] + verbose: bool + + +def we_are_wanted(context: Context) -> bool: + return context.uki_generator == "mkosi" or context.initrd_generator in ("mkosi", "mkosi-initrd") + + +def mandatory_variable(name: str) -> str: + try: + return os.environ[name] + except KeyError: + die(f"${name} must be set in the environment") + + +@uncaught_exception_handler() +def main() -> None: + log_setup() + + p = argparse.ArgumentParser( + description='kernel-install plugin to build initrds or Unified Kernel Images using mkosi', + allow_abbrev=False, + usage='50-mkosi.install COMMAND KERNEL_VERSION ENTRY_DIR KERNEL_IMAGE INITRD…', + ) + + p.add_argument("command", + metavar="COMMAND", + help="The action to perform. Only 'add' is supported.") + p.add_argument("kernel_version", + metavar="KERNEL_VERSION", + help="Kernel version string") + p.add_argument("entry_dir", + metavar="ENTRY_DIR", + type=Path, + help="Type#1 entry directory (ignored)") + p.add_argument("kernel_image", + metavar="KERNEL_IMAGE", + type=Path, + help="Kernel image") + p.add_argument("initrds", + metavar="INITRD…", + type=Path, + nargs="*", + help="Initrd files") + p.add_argument("--version", + action="version", + version=f"mkosi {__version__}") + + context = Context( + **vars(p.parse_args()), + staging_area=Path(mandatory_variable("KERNEL_INSTALL_STAGING_AREA")), + layout=mandatory_variable("KERNEL_INSTALL_LAYOUT"), + image_type=mandatory_variable("KERNEL_INSTALL_IMAGE_TYPE"), + initrd_generator=os.getenv("KERNEL_INSTALL_INITRD_GENERATOR"), + uki_generator=os.getenv("KERNEL_INSTALL_UKI_GENERATOR"), + verbose=int(os.getenv("KERNEL_INSTALL_VERBOSE", 0)) > 0, + ) + + if context.command != "add" or not we_are_wanted(context): + return + + # If kernel-install was passed a UKI, there's no need to build anything ourselves. + if context.image_type == "uki": + return + + # If the initrd was provided on the kernel command line, we shouldn't generate our own. + if context.layout != "uki" and context.initrds: + return + + format = OutputFormat.uki if context.layout == "uki" else OutputFormat.cpio + output = "initrd" if format == OutputFormat.cpio else "uki" + + cmdline: list[PathString] = [ + "mkosi", + "--directory", "", + "--format", str(format), + "--output", output, + "--workspace-dir=/var/tmp", + "--cache-dir=/var/cache", + "--output-dir", context.staging_area, + "--extra-tree", f"/usr/lib/modules/{context.kernel_version}:/usr/lib/modules/{context.kernel_version}", + "--extra-tree=/usr/lib/firmware:/usr/lib/firmware", + "--kernel-modules-exclude=.*", + "--kernel-modules-include-host=yes", + ] + + if context.verbose: + cmdline += ["--debug"] + + for d in ("/usr/lib/mkosi-initrd", "/etc/mkosi-initrd"): + if Path(d).exists(): + cmdline += ["--include", d] + + logging.info(f"Building {output}") + + run(cmdline) + + (context.staging_area / output).unlink() + + if format == OutputFormat.cpio: + shutil.move(next(context.staging_area.glob("initrd*.cpio*")), context.staging_area / "initrd") + else: + (context.staging_area / f"{output}.vmlinuz").unlink() + (context.staging_area / f"{output}.initrd").unlink() + + +if __name__ == '__main__': + main() diff --git a/mkosi/resources/mkosi-initrd/mkosi.conf.d/20-stub.conf b/mkosi/resources/mkosi-initrd/mkosi.conf.d/20-stub.conf new file mode 100644 index 000000000..42b6b0478 --- /dev/null +++ b/mkosi/resources/mkosi-initrd/mkosi.conf.d/20-stub.conf @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +[Match] +Format=uki +Distribution=!arch + +[Content] +Packages=systemd-boot -- 2.47.2