# Copyright 2024 Caleb Connolly # SPDX-License-Identifier: GPL-3.0-or-later from __future__ import annotations import enum import subprocess from argparse import Namespace from pathlib import Path from typing import Any, Literal, TypedDict from pmb.core.arch import Arch from pmb.core.chroot import Chroot class CrossCompile(enum.Enum): # Cross compilation isn't needed for this package: # 1) Either because the arch we will build for is exactly the same as the # native arch, or # 2) because CPU emulation is not needed (e.g. x86 on x86_64) UNNECESSARY = "unnecessary" # Cross compilation disabled, only use QEMU QEMU_ONLY = "qemu-only" # Cross compilation will use crossdirect CROSSDIRECT = "crossdirect" # Cross compilation will use cross-native CROSS_NATIVE = "cross-native" # Cross compilation will use cross-native2 CROSS_NATIVE2 = "cross-native2" def __str__(self) -> str: return self.value def enabled(self) -> bool: """Are we cross-compiling for this value of cross?""" return self not in [CrossCompile.UNNECESSARY, CrossCompile.QEMU_ONLY] def host_chroot(self, arch: Arch) -> Chroot: """Chroot for the package target architecture (the "host" machine). Cross native (v1) is the exception, since we exclusively use the native chroot for that.""" if arch == Arch.native(): return Chroot.native() match self: case CrossCompile.CROSS_NATIVE: return Chroot.native() case _: return Chroot.buildroot(arch) def build_chroot(self, arch: Arch) -> Chroot: """Chroot for the package build architecture (the "build" machine).""" if arch == Arch.native(): return Chroot.native() match self: case CrossCompile.UNNECESSARY | CrossCompile.CROSSDIRECT | CrossCompile.QEMU_ONLY: return Chroot.buildroot(arch) case CrossCompile.CROSS_NATIVE | CrossCompile.CROSS_NATIVE2: return Chroot.native() class RunOutputTypeDefault(enum.Enum): LOG = enum.auto() STDOUT = enum.auto() INTERACTIVE = enum.auto() TUI = enum.auto() NULL = enum.auto() def is_to_stdout(self) -> bool: match self: case self.STDOUT | self.INTERACTIVE: return True case self.LOG | self.TUI | self.NULL: return False case _: raise AssertionError def has_timeout(self) -> bool: match self: case self.LOG | self.STDOUT: return True case self.INTERACTIVE | self.TUI | self.NULL: return False case _: raise AssertionError def has_pass_stdin(self) -> bool: match self: case self.INTERACTIVE | self.TUI: return True case self.LOG | self.STDOUT | self.NULL: return False case _: raise AssertionError def __str__(self) -> str: return self.name @staticmethod def from_string(string: str) -> RunOutputTypeDefault: match string: case "log": return RunOutputTypeDefault.LOG case "stdout": return RunOutputTypeDefault.STDOUT case "interactive": return RunOutputTypeDefault.INTERACTIVE case "tui": return RunOutputTypeDefault.TUI case "null": return RunOutputTypeDefault.NULL case _: raise ValueError class RunOutputTypePopen(enum.Enum): BACKGROUND = enum.auto() PIPE = enum.auto() def is_to_stdout(self) -> bool: return False def has_timeout(self) -> bool: return False def has_pass_stdin(self) -> bool: return False RunOutputType = RunOutputTypeDefault | RunOutputTypePopen RunReturnType = str | int | subprocess.Popen PathString = Path | str Env = dict[str, PathString] Apkbuild = dict[str, Any] WithExtraRepos = Literal["default", "enabled", "disabled"] # These types are not definitive / API, they exist to describe the current # state of things so that we can improve our type hinting coverage and make # future refactoring efforts easier. class PartitionLayout(TypedDict): kernel: int | None boot: int reserve: int | None root: int class AportGenEntry(TypedDict): prefixes: list[str] confirm_overwrite: bool class Bootimg(TypedDict): cmdline: str bootimg_qcdt: str bootimg_qcdt_type: str | None bootimg_qcdt_exynos_platform: str | None bootimg_qcdt_exynos_subtype: str | None dtb_offset: str | None dtb_second: str base: str kernel_offset: str ramdisk_offset: str second_offset: str tags_offset: str pagesize: str header_version: str | None mtk_label_kernel: str mtk_label_ramdisk: str # Property list generated with: # $ rg --vimgrep "((^|\s)args\.\w+)" --only-matching | cut -d"." -f3 | sort | uniq class PmbArgs(Namespace): action_flasher: str action_initfs: str action_kconfig: str action_netboot: str action_test: str add: str all: bool all_git: bool all_stable: bool android_recovery_zip: bool apkindex_path: Path aports: list[Path] | None arch: Arch | None as_root: bool assume_yes: bool auto: bool autoinstall: bool boot_size: str build_default_device_arch: str buildroot: str built: bool ccache: bool ccache_size: str chroot_usb: bool cipher: str clear_log: bool cmdline: str command: str config: Path cross: bool details: bool details_to_stdout: bool deviceinfo_parse_kernel: str devices: str disk: Path dry: bool efi: bool envkernel: bool export_folder: Path extra_space: str fast: bool file: str filesystem: str flash_method: str folder: str force: bool fork_alpine: bool fork_alpine_retain_branch: bool full_disk_encryption: bool go_mod_cache: bool hook: str host: str host_qemu: bool http: bool ignore_depends: bool image_size: str image: bool install_base: bool install_blockdev: bool install_cgpt: bool install_key: bool install_local_pkgs: bool install_recommends: bool is_default_channel: str iter_time: str jobs: str kconfig_check_details: bool kernel: str keymap: str keep_going: bool lines: int log: Path mirror_alpine: str mirror_postmarketos: str name: str nconfig: bool netboot: bool no_depends: bool no_fde: bool no_firewall: bool no_image: bool no_reboot: bool no_sshd: bool non_existing: str odin_flashable_tar: bool offline: bool on_device_installer: bool ondev_cp: list[tuple[str, str]] ondev_no_rootfs: bool output: RunOutputTypeDefault overview: bool # FIXME (#2324): figure out the args.package vs args.packages situation package: str | list[str] packages: list[str] partition: str password: str path: Path pkgname: str pkgname_pkgver_srcurl: str pkgs_local: bool pkgs_local_mismatch: bool pkgs_online_mismatch: bool port: str qemu_audio: str qemu_cpu: str qemu_display: str qemu_gl: bool qemu_kvm: bool qemu_redir_stdio: str qemu_tablet: bool qemu_video: str recovery_flash_kernel: bool recovery_install_partition: str ref: str replace: bool repository: str reset: bool resume: bool rootfs: bool rsync: bool scripts: str second_storage: str sector_size: int | None selected_providers: dict[str, str] sparse: bool split: bool src: str ssh_keys: str strict: bool sudo_timer: bool suffix: str systemd: str timeout: float user: str value: str verbose: bool verify: bool work: Path xauth: bool xconfig: bool zap: bool