From: Daan De Meyer Date: Mon, 29 May 2023 20:41:31 +0000 (+0200) Subject: Rework architecture handling X-Git-Tag: v15~140^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c413ca859420c4ee3a40b8fbdab91bd7da3bbc87;p=thirdparty%2Fmkosi.git Rework architecture handling Let's lock architectures down by making it an enum instead of a free form string. We also introduce a bunch of mapping functions to map the Architecture enum to qemu, distribution arches, efi arches. We only support the architectures defined in the discoverable partitions spec and use those architectures as the default representation. --- diff --git a/mkosi.md b/mkosi.md index 3aa70c2a5..de4048dbb 100644 --- a/mkosi.md +++ b/mkosi.md @@ -402,10 +402,33 @@ a boolean argument: either "1", "yes", or "true" to enable, or "0", `Architecture=`, `--architecture=` -: The architecture to build the image for. Note that this currently - only works for architectures compatible with the host's +: The architecture to build the image for. A number of architectures can be specified, but which ones are + actually supported depends on the distribution used and whether a bootable image is requested or not. When + building for a foreign architecture, you'll also need to install and register a user mode emulator for that architecture. + The following architectures can be specified: + + - alpha + - arc + - arm + - arm64 + - ia64 + - loongarch64 + - mips64-le + - mips-le + - parisc + - ppc + - ppc64 + - ppc64-le + - riscv32 + - riscv64 + - s390 + - s390x + - tilegx + - x86 + - x86-64 + ### [Output] Section `Format=`, `--format=`, `-t` diff --git a/mkosi/__init__.py b/mkosi/__init__.py index e3a7a6e19..17b3f38e2 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -59,16 +59,6 @@ MKOSI_COMMANDS_SUDO = (Verb.shell, Verb.boot) T = TypeVar("T") -# EFI has its own conventions too -EFI_ARCHITECTURES = { - "x86_64": "x64", - "x86": "ia32", - "aarch64": "aa64", - "armhfp": "arm", - "riscv64:": "riscv64", -} - - def format_bytes(num_bytes: int) -> str: if num_bytes >= 1024 * 1024 * 1024: return f"{num_bytes/1024**3 :0.1f}G" @@ -833,7 +823,7 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None: "--directory", "", "--distribution", str(state.config.distribution), "--release", state.config.release, - "--architecture", state.config.architecture, + "--architecture", str(state.config.architecture), *(["--mirror", state.config.mirror] if state.config.mirror else []), "--repository-key-check", yes_no(state.config.repository_key_check), "--repositories", ",".join(state.config.repositories), @@ -906,7 +896,7 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None: # nul terminators in argv so let's communicate the cmdline via a file instead. state.workspace.joinpath("cmdline").write_text(f"{' '.join(cmdline).strip()}\x00") - stub = state.root / f"usr/lib/systemd/boot/efi/linux{EFI_ARCHITECTURES[state.config.architecture]}.efi.stub" + stub = state.root / f"usr/lib/systemd/boot/efi/linux{state.config.architecture.to_efi()}.efi.stub" if not stub.exists(): die(f"sd-stub not found at /{stub.relative_to(state.root)} in the image") @@ -916,7 +906,7 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None: "--os-release", f"@{state.root / 'usr/lib/os-release'}", "--stub", stub, "--output", boot_binary, - "--efi-arch", EFI_ARCHITECTURES[state.config.architecture], + "--efi-arch", state.config.architecture.to_efi(), ] for p in state.config.extra_search_paths: @@ -1652,7 +1642,7 @@ def invoke_repart(state: MkosiState, skip: Sequence[str] = [], split: bool = Fal dedent( f"""\ [Partition] - Type=root + Type=root-{state.config.architecture} Format={state.installer.filesystem()} CopyFiles=/ Minimize=guess diff --git a/mkosi/architecture.py b/mkosi/architecture.py new file mode 100644 index 000000000..00a577f9b --- /dev/null +++ b/mkosi/architecture.py @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: LGPL-2.1+ + +import enum +import platform + +from mkosi.log import die + + +class Architecture(enum.Enum): + alpha = "alpha" + arc = "arc" + arm = "arm" + arm64 = "arm64" + ia64 = "ia64" + loongarch64 = "loongarch64" + mips_le = "mips-le" + mips64_le = "mips64-le" + parisc = "parisc" + ppc = "ppc" + ppc64 = "ppc64" + ppc64_le = "ppc64-le" + riscv32 = "riscv32" + riscv64 = "riscv64" + s390 = "s390" + s390x = "s390x" + tilegx = "tilegx" + x86 = "x86" + x86_64 = "x86-64" + + def __str__(self) -> str: + return self.value + + @staticmethod + def from_uname(s: str) -> "Architecture": + a = { + "aarch64" : Architecture.arm64, + "aarch64_be" : Architecture.arm64, + "armv8l" : Architecture.arm, + "armv8b" : Architecture.arm, + "armv7ml" : Architecture.arm, + "armv7mb" : Architecture.arm, + "armv7l" : Architecture.arm, + "armv7b" : Architecture.arm, + "armv6l" : Architecture.arm, + "armv6b" : Architecture.arm, + "armv5tl" : Architecture.arm, + "armv5tel" : Architecture.arm, + "armv5tejl" : Architecture.arm, + "armv5tejb" : Architecture.arm, + "armv5teb" : Architecture.arm, + "armv5tb" : Architecture.arm, + "armv4tl" : Architecture.arm, + "armv4tb" : Architecture.arm, + "armv4l" : Architecture.arm, + "armv4b" : Architecture.arm, + "alpha" : Architecture.alpha, + "arc" : Architecture.arc, + "arceb" : Architecture.arc, + "x86_64" : Architecture.x86_64, + "i686" : Architecture.x86, + "i586" : Architecture.x86, + "i486" : Architecture.x86, + "i386" : Architecture.x86, + "ia64" : Architecture.ia64, + "parisc64" : Architecture.parisc, + "parisc" : Architecture.parisc, + "loongarch64" : Architecture.loongarch64, + "mips64" : Architecture.mips64_le, + "mips" : Architecture.mips_le, + "ppc64le" : Architecture.ppc64_le, + "ppc64" : Architecture.ppc64, + "ppc" : Architecture.ppc, + "riscv64" : Architecture.riscv64, + "riscv32" : Architecture.riscv32, + "riscv" : Architecture.riscv64, + "s390x" : Architecture.s390x, + "s390" : Architecture.s390, + "tilegx" : Architecture.tilegx, + }.get(s) + + if not a: + die(f"Architecture {a} is not supported") + + return a + + def to_efi(self) -> str: + a = { + Architecture.x86_64 : "x64", + Architecture.x86 : "ia32", + Architecture.arm64 : "aa64", + Architecture.arm : "arm", + Architecture.riscv64 : "riscv64", + Architecture.loongarch64 : "loongarch64", + }.get(self) + + if not a: + die(f"Architecture {self} does not support UEFI") + + return a + + def to_qemu(self) -> str: + a = { + Architecture.alpha: "alpha", + Architecture.arm: "arm", + Architecture.arm64: "aarch64", + Architecture.loongarch64: "loongarch64", + Architecture.mips64_le: "mips", + Architecture.mips_le: "mips", + Architecture.parisc: "hppa", + Architecture.ppc: "ppc", + Architecture.ppc64: "ppc", + Architecture.ppc64_le: "ppc", + Architecture.riscv32: "riscv32", + Architecture.riscv64: "riscv64", + Architecture.s390x: "s390x", + Architecture.x86: "i386", + Architecture.x86_64: "x86_64", + }.get(self) + + if not a: + die(f"Architecture {self} not supported by QEMU") + + return a + + def is_native(self) -> bool: + return self == self.native() + + @classmethod + def native(cls) -> "Architecture": + return cls.from_uname(platform.machine()) + diff --git a/mkosi/config.py b/mkosi/config.py index 16f6914a7..75cd4e3a0 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -20,6 +20,7 @@ from collections.abc import Sequence from pathlib import Path from typing import Any, Callable, Optional, Type, Union, cast +from mkosi.architecture import Architecture from mkosi.log import ARG_DEBUG, ARG_DEBUG_SHELL, Style, die from mkosi.pager import page from mkosi.run import run @@ -218,7 +219,7 @@ def config_default_mirror(namespace: argparse.Namespace) -> Optional[str]: if "distribution" not in namespace: setattr(namespace, "distribution", detect_distribution()[0]) if "architecture" not in namespace: - setattr(namespace, "architecture", platform.machine()) + setattr(namespace, "architecture", Architecture.native()) d = getattr(namespace, "distribution") a = getattr(namespace, "architecture") @@ -226,12 +227,12 @@ def config_default_mirror(namespace: argparse.Namespace) -> Optional[str]: if d == Distribution.debian: return "http://deb.debian.org/debian" elif d == Distribution.ubuntu: - if a == "x86" or a == "x86_64": + if a == Architecture.x86 or a == Architecture.x86_64: return "http://archive.ubuntu.com/ubuntu" else: return "http://ports.ubuntu.com" elif d == Distribution.arch: - if a == "aarch64": + if a == Architecture.arm64: return "http://mirror.archlinuxarm.org" else: return "https://geo.mirror.pkgbuild.com" @@ -244,9 +245,9 @@ def config_default_mirror(namespace: argparse.Namespace) -> Optional[str]: def make_enum_parser(type: Type[enum.Enum]) -> Callable[[str], enum.Enum]: def parse_enum(value: str) -> enum.Enum: try: - return type[value] - except KeyError: - die(f"Invalid {type.__name__} value \"{value}\"") + return type(value) + except ValueError: + die(f"'{value}' is not a valid {type.__name__}") return parse_enum @@ -594,7 +595,7 @@ class MkosiConfig: repo_dirs: list[Path] repart_dirs: list[Path] overlay: bool - architecture: str + architecture: Architecture output_format: OutputFormat manifest_format: list[ManifestFormat] output: str @@ -682,9 +683,6 @@ class MkosiConfig: if k in inspect.signature(cls).parameters }) - def architecture_is_native(self) -> bool: - return self.architecture == platform.machine() - @property def output_with_version(self) -> str: output = self.output @@ -775,7 +773,8 @@ class MkosiConfigParser: MkosiConfigSetting( dest="architecture", section="Distribution", - default=platform.machine(), + parse=config_make_enum_parser(Architecture), + default=Architecture.native(), ), MkosiConfigSetting( dest="mirror", diff --git a/mkosi/distributions/__init__.py b/mkosi/distributions/__init__.py index bdc1b6568..51f51b356 100644 --- a/mkosi/distributions/__init__.py +++ b/mkosi/distributions/__init__.py @@ -4,6 +4,8 @@ from collections.abc import Sequence from pathlib import Path from typing import TYPE_CHECKING +from mkosi.architecture import Architecture + if TYPE_CHECKING: from mkosi.state import MkosiState @@ -11,23 +13,23 @@ if TYPE_CHECKING: class DistributionInstaller: @classmethod def install(cls, state: "MkosiState") -> None: - raise NotImplementedError + raise NotImplementedError() @staticmethod - def kernel_image(kver: str, architecture: str) -> Path: + def kernel_image(kver: str, architecture: Architecture) -> Path: return Path("usr/lib/modules") / kver / "vmlinuz" @classmethod def install_packages(cls, state: "MkosiState", packages: Sequence[str]) -> None: - raise NotImplementedError + raise NotImplementedError() @classmethod def remove_packages(cls, state: "MkosiState", packages: Sequence[str]) -> None: - raise NotImplementedError + raise NotImplementedError() @classmethod def filesystem(cls) -> str: - raise NotImplementedError + raise NotImplementedError() @classmethod def filesystem_options(cls, state: "MkosiState") -> dict[str, list[str]]: @@ -36,3 +38,7 @@ class DistributionInstaller: @staticmethod def kernel_command_line(state: "MkosiState") -> list[str]: return [] + + @staticmethod + def architecture(arch: Architecture) -> str: + raise NotImplementedError() diff --git a/mkosi/distributions/arch.py b/mkosi/distributions/arch.py index 1dbd6772c..b22fd04a7 100644 --- a/mkosi/distributions/arch.py +++ b/mkosi/distributions/arch.py @@ -3,8 +3,10 @@ from collections.abc import Sequence from textwrap import dedent +from mkosi.architecture import Architecture from mkosi.config import ConfigFeature from mkosi.distributions import DistributionInstaller +from mkosi.log import die from mkosi.run import bwrap from mkosi.state import MkosiState from mkosi.types import PathString @@ -27,7 +29,7 @@ class ArchInstaller(DistributionInstaller): if state.config.local_mirror: server = f"Server = {state.config.local_mirror}" else: - if state.config.architecture == "aarch64": + if state.config.architecture == Architecture.arm64: server = f"Server = {state.config.mirror}/$arch/$repo" else: server = f"Server = {state.config.mirror}/$repo/os/$arch" @@ -54,7 +56,7 @@ class ArchInstaller(DistributionInstaller): GPGDir = /etc/pacman.d/gnupg/ HookDir = {state.root}/etc/pacman.d/hooks/ HoldPkg = pacman glibc - Architecture = {state.config.architecture} + Architecture = {state.installer.architecture(state.config.architecture)} Color CheckSpace SigLevel = {sig_level} @@ -85,6 +87,18 @@ class ArchInstaller(DistributionInstaller): return invoke_pacman(state, packages, apivfs=apivfs) + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.x86_64 : "x86_64", + Architecture.arm64 : "aarch64", + }.get(arch) + + if not a: + die(f"Architecture {a} is not supported by Arch Linux") + + return a + def invoke_pacman(state: MkosiState, packages: Sequence[str], apivfs: bool = True) -> None: cmdline: list[PathString] = [ diff --git a/mkosi/distributions/centos.py b/mkosi/distributions/centos.py index c9b3e6a3e..b2046a4fb 100644 --- a/mkosi/distributions/centos.py +++ b/mkosi/distributions/centos.py @@ -5,6 +5,7 @@ import shutil from collections.abc import Sequence from pathlib import Path +from mkosi.architecture import Architecture from mkosi.config import MkosiConfig from mkosi.distributions import DistributionInstaller from mkosi.distributions.fedora import Repo, invoke_dnf, setup_dnf @@ -109,6 +110,20 @@ class CentosInstaller(DistributionInstaller): def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: invoke_dnf(state, "remove", packages) + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.x86_64 : "x86_64", + Architecture.ppc64_le : "ppc64le", + Architecture.s390x : "s390x", + Architecture.arm64 : "aarch64", + }.get(arch) + + if not a: + die(f"Architecture {a} is not supported by CentOS") + + return a + @staticmethod def _gpgurl(release: int) -> str: return "https://www.centos.org/keys/RPM-GPG-KEY-CentOS-Official" diff --git a/mkosi/distributions/debian.py b/mkosi/distributions/debian.py index db2262016..5ee962a26 100644 --- a/mkosi/distributions/debian.py +++ b/mkosi/distributions/debian.py @@ -6,7 +6,9 @@ from collections.abc import Sequence from pathlib import Path from textwrap import dedent +from mkosi.architecture import Architecture from mkosi.distributions import DistributionInstaller +from mkosi.log import die from mkosi.run import bwrap, run from mkosi.state import MkosiState from mkosi.types import CompletedProcess, PathString @@ -18,7 +20,7 @@ class DebianInstaller(DistributionInstaller): return "ext4" @staticmethod - def kernel_image(name: str, architecture: str) -> Path: + def kernel_image(name: str, architecture: Architecture) -> Path: return Path(f"boot/vmlinuz-{name}") @staticmethod @@ -68,7 +70,7 @@ class DebianInstaller(DistributionInstaller): "sparc" : ["lib64"], "sparc64" : ["lib32", "lib64"], "x32" : ["lib32", "lib64", "libx32"], - }.get(DEBIAN_ARCHITECTURES[state.config.architecture], []) + }.get(state.installer.architecture(state.config.architecture), []) state.root.joinpath("usr").mkdir(mode=0o755, exist_ok=True) for d in subdirs: @@ -130,24 +132,30 @@ class DebianInstaller(DistributionInstaller): def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: invoke_apt(state, "purge", packages) - -# Debian calls their architectures differently, so when calling apt we will have to map to their names. -# uname -m -> dpkg --print-architecture -DEBIAN_ARCHITECTURES = { - "aarch64": "arm64", - "armhfp": "armhf", - "armv7l": "armhf", - "ia64": "ia64", - "mips64": "mipsel", - "m68k": "m68k", - "parisc64": "hppa", - "ppc64": "ppc64", - "ppc64le": "ppc64el", - "riscv64:": "riscv64", - "s390x": "s390x", - "x86": "i386", - "x86_64": "amd64", -} + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.arm64 : "arm64", + Architecture.arm : "armhf", + Architecture.alpha : "alpha", + Architecture.x86_64 : "amd64", + Architecture.x86 : "i386", + Architecture.ia64 : "ia64", + Architecture.loongarch64 : "loongarch64", + Architecture.mips64_le : "mips64el", + Architecture.mips_le : "mipsel", + Architecture.parisc : "hppa", + Architecture.ppc64_le : "ppc64el", + Architecture.ppc64 : "ppc64", + Architecture.riscv64 : "riscv64", + Architecture.s390x : "s390x", + Architecture.s390 : "s390", + }.get(arch) + + if not a: + die(f"Architecture {arch} is not supported by Debian") + + return a def setup_apt(state: MkosiState, repos: Sequence[str]) -> None: @@ -164,7 +172,7 @@ def setup_apt(state: MkosiState, repos: Sequence[str]) -> None: state.root.joinpath("var/lib/dpkg/status").touch() config = state.workspace / "apt/apt.conf" - debarch = DEBIAN_ARCHITECTURES[state.config.architecture] + debarch = state.installer.architecture(state.config.architecture) config.write_text( dedent( diff --git a/mkosi/distributions/fedora.py b/mkosi/distributions/fedora.py index 821b460f4..db42e647f 100644 --- a/mkosi/distributions/fedora.py +++ b/mkosi/distributions/fedora.py @@ -10,7 +10,9 @@ from pathlib import Path from textwrap import dedent from typing import Any, NamedTuple +from mkosi.architecture import Architecture from mkosi.distributions import DistributionInstaller +from mkosi.log import die from mkosi.remove import unlink_try_hard from mkosi.run import bwrap from mkosi.state import MkosiState @@ -35,7 +37,7 @@ class FedoraInstaller(DistributionInstaller): updates_url = None elif state.config.mirror: baseurl = urllib.parse.urljoin(state.config.mirror, f"releases/{release}/Everything/$basearch/os/") - media = urllib.parse.urljoin(baseurl.replace("$basearch", state.config.architecture), "media.repo") + media = urllib.parse.urljoin(baseurl.replace("$basearch", state.installer.architecture(state.config.architecture)), "media.repo") if not url_exists(media): baseurl = urllib.parse.urljoin(state.config.mirror, f"development/{release}/Everything/$basearch/os/") @@ -66,6 +68,25 @@ class FedoraInstaller(DistributionInstaller): def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: invoke_dnf(state, "remove", packages) + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.arm64 : "aarch64", + Architecture.ia64 : "ia64", + Architecture.mips64_le : "mips64el", + Architecture.mips_le : "mipsel", + Architecture.parisc : "parisc64", + Architecture.ppc64_le : "ppc64le", + Architecture.riscv64 : "riscv64", + Architecture.s390x : "s390x", + Architecture.x86_64 : "x86_64", + }.get(arch) + + if not a: + die(f"Architecture {a} is not supported by Fedora") + + return a + def parse_fedora_release(release: str) -> str: # The release can be specified as 'rawhide-'. We don't make use @@ -178,8 +199,8 @@ def invoke_dnf( if state.config.cache_only and not state.config.local_mirror: cmdline += ["-C"] - if not state.config.architecture_is_native(): - cmdline += [f"--forcearch={state.config.architecture}"] + if not state.config.architecture.is_native(): + cmdline += [f"--forcearch={state.installer.architecture(state.config.architecture)}"] if not state.config.with_docs: cmdline += ["--no-docs" if dnf.endswith("dnf5") else "--nodocs"] diff --git a/mkosi/distributions/gentoo.py b/mkosi/distributions/gentoo.py index 7756a6a89..b455119ce 100644 --- a/mkosi/distributions/gentoo.py +++ b/mkosi/distributions/gentoo.py @@ -9,6 +9,7 @@ from collections.abc import Sequence from pathlib import Path from textwrap import dedent +from mkosi.architecture import Architecture from mkosi.distributions import DistributionInstaller from mkosi.install import copy_path, flock from mkosi.log import ARG_DEBUG, complete_step, die, log_step @@ -16,14 +17,6 @@ from mkosi.remove import unlink_try_hard from mkosi.run import run, run_workspace_command from mkosi.state import MkosiState -ARCHITECTURES = { - "x86_64": ("amd64", "arch/x86/boot/bzImage"), - # TODO: - "aarch64": ("arm64", "arch/arm64/boot/Image.gz"), - # TODO: - "armv7l": ("arm", "arch/arm/boot/zImage"), -} - def invoke_emerge( state: MkosiState, @@ -172,7 +165,7 @@ class Gentoo: self.portage_cfg_dir.mkdir(parents=True, exist_ok=True) - self.arch, _ = ARCHITECTURES[state.config.architecture or "x86_64"] + self.arch, _ = state.installer.architecture(state.config.architecture) self.arch_profile = Path(f"default/linux/{self.arch}/{state.config.release}/no-multilib/systemd/merged-usr") self.pkgs['sys'] = ["@world"] @@ -321,8 +314,13 @@ class GentooInstaller(DistributionInstaller): return "ext4" @staticmethod - def kernel_image(name: str, architecture: str) -> Path: - _, kimg_path = ARCHITECTURES[architecture] + def kernel_image(name: str, architecture: Architecture) -> Path: + kimg_path = { + Architecture.x86_64: "arch/x86/boot/bzImage", + Architecture.arm64: "arch/arm64/boot/Image.gz", + Architecture.arm: "arch/arm/boot/zImage", + }[architecture] + return Path(f"usr/src/linux-{name}") / kimg_path @classmethod @@ -332,3 +330,16 @@ class GentooInstaller(DistributionInstaller): @classmethod def install_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: invoke_emerge(state, packages) + + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.x86_64 : "amd64", + Architecture.arm64 : "arm64", + Architecture.arm : "arm", + }.get(arch) + + if not a: + die(f"Architecture {a} is not supported by Gentoo") + + return a diff --git a/mkosi/distributions/mageia.py b/mkosi/distributions/mageia.py index 73432bdb9..54ca55d8c 100644 --- a/mkosi/distributions/mageia.py +++ b/mkosi/distributions/mageia.py @@ -2,8 +2,10 @@ from collections.abc import Sequence +from mkosi.architecture import Architecture from mkosi.distributions import DistributionInstaller from mkosi.distributions.fedora import Repo, invoke_dnf, setup_dnf +from mkosi.log import die from mkosi.state import MkosiState @@ -19,26 +21,27 @@ class MageiaInstaller(DistributionInstaller): @classmethod def install_packages(cls, state: MkosiState, packages: Sequence[str], apivfs: bool = True) -> None: release = state.config.release.strip("'") + arch = state.installer.architecture(state.config.architecture) if state.config.local_mirror: release_url = f"baseurl={state.config.local_mirror}" updates_url = None elif state.config.mirror: - baseurl = f"{state.config.mirror}/distrib/{release}/{state.config.architecture}/media/core/" + baseurl = f"{state.config.mirror}/distrib/{release}/{arch}/media/core/" release_url = f"baseurl={baseurl}/release/" if release == "cauldron": updates_url = None else: updates_url = f"baseurl={baseurl}/updates/" else: - baseurl = f"https://www.mageia.org/mirrorlist/?release={release}&arch={state.config.architecture}§ion=core" + baseurl = f"https://www.mageia.org/mirrorlist/?release={release}&arch={arch}§ion=core" release_url = f"mirrorlist={baseurl}&repo=release" if release == "cauldron": updates_url = None else: updates_url = f"mirrorlist={baseurl}&repo=updates" - gpgurl = f"https://mirrors.kernel.org/mageia/distrib/{release}/{state.config.architecture}/media/core/release/media_info/pubkey" + gpgurl = f"https://mirrors.kernel.org/mageia/distrib/{release}/{arch}/media/core/release/media_info/pubkey" repos = [Repo(f"mageia-{release}", release_url, [gpgurl])] if updates_url is not None: @@ -50,3 +53,14 @@ class MageiaInstaller(DistributionInstaller): @classmethod def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: invoke_dnf(state, "remove", packages) + + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.x86_64 : "x86_64", + }.get(arch) + + if not a: + die(f"Architecture {a} is not supported by Mageia") + + return a diff --git a/mkosi/distributions/openmandriva.py b/mkosi/distributions/openmandriva.py index dd7f9f42c..a0bfbe02d 100644 --- a/mkosi/distributions/openmandriva.py +++ b/mkosi/distributions/openmandriva.py @@ -2,8 +2,10 @@ from collections.abc import Sequence +from mkosi.architecture import Architecture from mkosi.distributions import DistributionInstaller from mkosi.distributions.fedora import Repo, invoke_dnf, setup_dnf +from mkosi.log import die from mkosi.state import MkosiState @@ -19,6 +21,7 @@ class OpenmandrivaInstaller(DistributionInstaller): @classmethod def install_packages(cls, state: MkosiState, packages: Sequence[str], apivfs: bool = True) -> None: release = state.config.release.strip("'") + arch = state.installer.architecture(state.config.architecture) if release[0].isdigit(): release_model = "rock" @@ -31,11 +34,11 @@ class OpenmandrivaInstaller(DistributionInstaller): release_url = f"baseurl={state.config.local_mirror}" updates_url = None elif state.config.mirror: - baseurl = f"{state.config.mirror}/{release_model}/repository/{state.config.architecture}/main" + baseurl = f"{state.config.mirror}/{release_model}/repository/{arch}/main" release_url = f"baseurl={baseurl}/release/" updates_url = f"baseurl={baseurl}/updates/" else: - baseurl = f"http://mirrors.openmandriva.org/mirrors.php?platform={release_model}&arch={state.config.architecture}&repo=main" + baseurl = f"http://mirrors.openmandriva.org/mirrors.php?platform={release_model}&arch={arch}&repo=main" release_url = f"mirrorlist={baseurl}&release=release" updates_url = f"mirrorlist={baseurl}&release=updates" @@ -51,3 +54,14 @@ class OpenmandrivaInstaller(DistributionInstaller): @classmethod def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: invoke_dnf(state, "remove", packages) + + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.x86_64 : "x86_64", + }.get(arch) + + if not a: + die(f"Architecture {a} is not supported by OpenMandriva") + + return a diff --git a/mkosi/distributions/opensuse.py b/mkosi/distributions/opensuse.py index 700280a2f..d28ed0ed2 100644 --- a/mkosi/distributions/opensuse.py +++ b/mkosi/distributions/opensuse.py @@ -4,6 +4,7 @@ import urllib.request import xml.etree.ElementTree as ElementTree from collections.abc import Sequence +from mkosi.architecture import Architecture from mkosi.distributions import DistributionInstaller from mkosi.distributions.fedora import Repo, invoke_dnf, setup_dnf from mkosi.log import die @@ -51,6 +52,17 @@ class OpensuseInstaller(DistributionInstaller): def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: invoke_dnf(state, "remove", packages) + @staticmethod + def architecture(arch: Architecture) -> str: + a = { + Architecture.x86_64 : "x86_64", + }.get(arch) + + if not a: + die(f"Architecture {a} is not supported by OpenSUSE") + + return a + def fetch_gpgurls(repourl: str) -> list[str]: gpgurls = [f"{repourl}/repodata/repomd.xml.key"] diff --git a/mkosi/distributions/ubuntu.py b/mkosi/distributions/ubuntu.py index 39504aacd..72ec1daf2 100644 --- a/mkosi/distributions/ubuntu.py +++ b/mkosi/distributions/ubuntu.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1+ +from mkosi.architecture import Architecture from mkosi.distributions.debian import DebianInstaller from mkosi.state import MkosiState @@ -16,7 +17,7 @@ class UbuntuInstaller(DebianInstaller): updates = f"deb {state.config.mirror} {state.config.release}-updates {repos}" # Security updates repos are never mirrored. But !x86 are on the ports server. - if state.config.architecture in ["x86", "x86_64"]: + if state.config.architecture in [Architecture.x86, Architecture.x86_64]: security = f"deb http://security.ubuntu.com/ubuntu/ {state.config.release}-security {repos}" else: security = f"deb http://ports.ubuntu.com/ {state.config.release}-security {repos}" diff --git a/mkosi/manifest.py b/mkosi/manifest.py index 899170492..4e95bbec4 100644 --- a/mkosi/manifest.py +++ b/mkosi/manifest.py @@ -255,8 +255,8 @@ class Manifest: def as_dict(self) -> dict[str, Any]: config = { "name": self.config.image_id or "image", - "distribution": self.config.distribution.name, - "architecture": self.config.architecture, + "distribution": str(self.config.distribution), + "architecture": str(self.config.architecture), } if self.config.image_version is not None: config["version"] = self.config.image_version diff --git a/mkosi/qemu.py b/mkosi/qemu.py index 175bea43a..2541348cd 100644 --- a/mkosi/qemu.py +++ b/mkosi/qemu.py @@ -14,6 +14,7 @@ import tempfile from pathlib import Path from typing import Iterator, Optional +from mkosi.architecture import Architecture from mkosi.config import ConfigFeature, MkosiArgs, MkosiConfig from mkosi.install import copy_path from mkosi.log import die @@ -35,7 +36,7 @@ def machine_cid(config: MkosiConfig) -> int: def find_qemu_binary(config: MkosiConfig) -> str: - binaries = ["qemu", "qemu-kvm", f"qemu-system-{config.architecture}"] + binaries = ["qemu", "qemu-kvm", f"qemu-system-{config.architecture.to_qemu()}"] for binary in binaries: if shutil.which(binary) is not None: return binary @@ -45,8 +46,8 @@ def find_qemu_binary(config: MkosiConfig) -> str: def find_qemu_firmware(config: MkosiConfig) -> tuple[Path, bool]: FIRMWARE_LOCATIONS = { - "x86_64": ["/usr/share/ovmf/x64/OVMF_CODE.secboot.fd"], - "i386": [ + Architecture.x86_64: ["/usr/share/ovmf/x64/OVMF_CODE.secboot.fd"], + Architecture.x86: [ "/usr/share/edk2/ovmf-ia32/OVMF_CODE.secboot.fd", "/usr/share/OVMF/OVMF32_CODE_4M.secboot.fd" ], @@ -57,14 +58,14 @@ def find_qemu_firmware(config: MkosiConfig) -> tuple[Path, bool]: return Path(firmware), True FIRMWARE_LOCATIONS = { - "x86_64": [ + Architecture.x86_64: [ "/usr/share/ovmf/ovmf_code_x64.bin", "/usr/share/ovmf/x64/OVMF_CODE.fd", "/usr/share/qemu/ovmf-x86_64.bin", ], - "i386": ["/usr/share/ovmf/ovmf_code_ia32.bin", "/usr/share/edk2/ovmf-ia32/OVMF_CODE.fd"], - "aarch64": ["/usr/share/AAVMF/AAVMF_CODE.fd"], - "armhfp": ["/usr/share/AAVMF/AAVMF32_CODE.fd"], + Architecture.x86: ["/usr/share/ovmf/ovmf_code_ia32.bin", "/usr/share/edk2/ovmf-ia32/OVMF_CODE.fd"], + Architecture.arm64: ["/usr/share/AAVMF/AAVMF_CODE.fd"], + Architecture.arm: ["/usr/share/AAVMF/AAVMF32_CODE.fd"], }.get(config.architecture, []) for firmware in FIRMWARE_LOCATIONS: @@ -107,16 +108,16 @@ def find_qemu_firmware(config: MkosiConfig) -> tuple[Path, bool]: def find_ovmf_vars(config: MkosiConfig) -> Path: OVMF_VARS_LOCATIONS = [] - if config.architecture == "x86_64": + if config.architecture == Architecture.x86_64: OVMF_VARS_LOCATIONS += ["/usr/share/ovmf/x64/OVMF_VARS.fd"] - elif config.architecture == "i386": + elif config.architecture == Architecture.x86: OVMF_VARS_LOCATIONS += [ "/usr/share/edk2/ovmf-ia32/OVMF_VARS.fd", "/usr/share/OVMF/OVMF32_VARS_4M.fd", ] - elif config.architecture == "armhfp": + elif config.architecture == Architecture.arm: OVMF_VARS_LOCATIONS += ["/usr/share/AAVMF/AAVMF32_VARS.fd"] - elif config.architecture == "aarch64": + elif config.architecture == Architecture.arm64: OVMF_VARS_LOCATIONS += ["/usr/share/AAVMF/AAVMF_VARS.fd"] OVMF_VARS_LOCATIONS += ["/usr/share/edk2/ovmf/OVMF_VARS.fd", @@ -199,7 +200,7 @@ def run_qemu(args: MkosiArgs, config: MkosiConfig) -> None: firmware, fw_supports_sb = find_qemu_firmware(config) smm = "on" if fw_supports_sb else "off" - if config.architecture == "aarch64": + if config.architecture == Architecture.arm64: machine = f"type=virt,accel={accel}" else: machine = f"type=q35,accel={accel},smm={smm}" @@ -292,9 +293,9 @@ def run_qemu(args: MkosiArgs, config: MkosiConfig) -> None: cmdline += ["-chardev", f"socket,id=chrtpm,path={swtpm_socket}", "-tpmdev", "emulator,id=tpm0,chardev=chrtpm"] - if config.architecture == "x86_64": + if config.architecture == Architecture.x86_64: cmdline += ["-device", "tpm-tis,tpmdev=tpm0"] - elif config.architecture == "aarch64": + elif config.architecture == Architecture.arm64: cmdline += ["-device", "tpm-tis-device,tpmdev=tpm0"] if use_vsock: