# Copyright 2024 Caleb Connolly # SPDX-License-Identifier: GPL-3.0-or-later 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 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 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: RunOutputType 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