forked from Mirror/pmbootstrap
pmb: Add lots of type hints (MR 2464)
This commit is contained in:
parent
d05d57b37e
commit
225d8b30a0
71 changed files with 566 additions and 325 deletions
|
@ -161,7 +161,7 @@ def rewrite(
|
||||||
handle.truncate()
|
handle.truncate()
|
||||||
|
|
||||||
|
|
||||||
def get_upstream_aport(pkgname: str, arch: Arch | None = None, retain_branch: bool = False):
|
def get_upstream_aport(pkgname: str, arch: Arch | None = None, retain_branch: bool = False) -> Path:
|
||||||
"""
|
"""
|
||||||
Perform a git checkout of Alpine's aports and get the path to the aport.
|
Perform a git checkout of Alpine's aports and get the path to the aport.
|
||||||
|
|
||||||
|
|
|
@ -193,8 +193,8 @@ def generate_deviceinfo(
|
||||||
chassis: str,
|
chassis: str,
|
||||||
has_external_storage: bool,
|
has_external_storage: bool,
|
||||||
flash_method: str,
|
flash_method: str,
|
||||||
bootimg=None,
|
bootimg: Bootimg | None = None,
|
||||||
):
|
) -> None:
|
||||||
codename = "-".join(pkgname.split("-")[1:])
|
codename = "-".join(pkgname.split("-")[1:])
|
||||||
external_storage = "true" if has_external_storage else "false"
|
external_storage = "true" if has_external_storage else "false"
|
||||||
# Note: New variables must be added to pmb/config/__init__.py as well
|
# Note: New variables must be added to pmb/config/__init__.py as well
|
||||||
|
@ -281,7 +281,7 @@ def generate_modules_initfs() -> None:
|
||||||
handle.write(line.lstrip() + "\n")
|
handle.write(line.lstrip() + "\n")
|
||||||
|
|
||||||
|
|
||||||
def generate_apkbuild(pkgname: str, name: str, arch: Arch, flash_method: str):
|
def generate_apkbuild(pkgname: str, name: str, arch: Arch, flash_method: str) -> None:
|
||||||
# Dependencies
|
# Dependencies
|
||||||
depends = ["postmarketos-base", "linux-" + "-".join(pkgname.split("-")[1:])]
|
depends = ["postmarketos-base", "linux-" + "-".join(pkgname.split("-")[1:])]
|
||||||
if flash_method in ["fastboot", "heimdall-bootimg"]:
|
if flash_method in ["fastboot", "heimdall-bootimg"]:
|
||||||
|
@ -331,7 +331,7 @@ def generate_apkbuild(pkgname: str, name: str, arch: Arch, flash_method: str):
|
||||||
handle.write(line[8:].replace(" " * 4, "\t") + "\n")
|
handle.write(line[8:].replace(" " * 4, "\t") + "\n")
|
||||||
|
|
||||||
|
|
||||||
def generate(pkgname: str):
|
def generate(pkgname: str) -> None:
|
||||||
arch = ask_for_architecture()
|
arch = ask_for_architecture()
|
||||||
manufacturer = ask_for_manufacturer()
|
manufacturer = ask_for_manufacturer()
|
||||||
name = ask_for_name(manufacturer)
|
name = ask_for_name(manufacturer)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import pmb.helpers.git
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
|
|
||||||
|
|
||||||
def generate(pkgname: str):
|
def generate(pkgname: str) -> None:
|
||||||
# Copy original aport
|
# Copy original aport
|
||||||
prefix = pkgname.split("-")[0]
|
prefix = pkgname.split("-")[0]
|
||||||
arch = Arch.from_str(pkgname.split("-")[1])
|
arch = Arch.from_str(pkgname.split("-")[1])
|
||||||
|
|
|
@ -7,7 +7,7 @@ import pmb.aportgen.core
|
||||||
import pmb.parse.apkindex
|
import pmb.parse.apkindex
|
||||||
|
|
||||||
|
|
||||||
def generate_apkbuild(pkgname: str, deviceinfo: Deviceinfo, patches: list[str]):
|
def generate_apkbuild(pkgname: str, deviceinfo: Deviceinfo, patches: list[str]) -> None:
|
||||||
device = "-".join(pkgname.split("-")[1:])
|
device = "-".join(pkgname.split("-")[1:])
|
||||||
carch = deviceinfo.arch.kernel()
|
carch = deviceinfo.arch.kernel()
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ def generate_apkbuild(pkgname: str, deviceinfo: Deviceinfo, patches: list[str]):
|
||||||
hndl.write(line[8:].replace(" " * 4, "\t") + "\n")
|
hndl.write(line[8:].replace(" " * 4, "\t") + "\n")
|
||||||
|
|
||||||
|
|
||||||
def generate(pkgname: str):
|
def generate(pkgname: str) -> None:
|
||||||
device = "-".join(pkgname.split("-")[1:])
|
device = "-".join(pkgname.split("-")[1:])
|
||||||
deviceinfo = pmb.parse.deviceinfo(device)
|
deviceinfo = pmb.parse.deviceinfo(device)
|
||||||
work = get_context().config.work
|
work = get_context().config.work
|
||||||
|
|
|
@ -30,7 +30,7 @@ from pmb.core import Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def check_build_for_arch(pkgname: str, arch: Arch):
|
def check_build_for_arch(pkgname: str, arch: Arch) -> bool:
|
||||||
"""Check if pmaport can be built or exists as binary for a specific arch.
|
"""Check if pmaport can be built or exists as binary for a specific arch.
|
||||||
|
|
||||||
:returns: * True when it can be built
|
:returns: * True when it can be built
|
||||||
|
@ -67,7 +67,7 @@ def check_build_for_arch(pkgname: str, arch: Arch):
|
||||||
raise RuntimeError(f"Can't build '{pkgname}' for architecture {arch}")
|
raise RuntimeError(f"Can't build '{pkgname}' for architecture {arch}")
|
||||||
|
|
||||||
|
|
||||||
def get_depends(context: Context, apkbuild):
|
def get_depends(context: Context, apkbuild: dict[str, Any]) -> list[str]:
|
||||||
"""Alpine's abuild always builds/installs the "depends" and "makedepends" of a package
|
"""Alpine's abuild always builds/installs the "depends" and "makedepends" of a package
|
||||||
before building it.
|
before building it.
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ def get_depends(context: Context, apkbuild):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def get_pkgver(original_pkgver: str, original_source=False):
|
def get_pkgver(original_pkgver: str, original_source: bool = False) -> str:
|
||||||
"""Get the original pkgver when using the original source.
|
"""Get the original pkgver when using the original source.
|
||||||
|
|
||||||
Otherwise, get the pkgver with an appended suffix of current date and time.
|
Otherwise, get the pkgver with an appended suffix of current date and time.
|
||||||
|
@ -122,7 +122,14 @@ def output_path(arch: Arch, pkgname: str, pkgver: str, pkgrel: str) -> Path:
|
||||||
return arch / f"{pkgname}-{pkgver}-r{pkgrel}.apk"
|
return arch / f"{pkgname}-{pkgver}-r{pkgrel}.apk"
|
||||||
|
|
||||||
|
|
||||||
def finish(apkbuild, channel, arch, output: Path, chroot: Chroot, strict=False):
|
def finish(
|
||||||
|
apkbuild: dict[str, Any],
|
||||||
|
channel: str,
|
||||||
|
arch: Arch,
|
||||||
|
output: Path,
|
||||||
|
chroot: Chroot,
|
||||||
|
strict: bool = False,
|
||||||
|
) -> None:
|
||||||
"""Various finishing tasks that need to be done after a build."""
|
"""Various finishing tasks that need to be done after a build."""
|
||||||
# Verify output file
|
# Verify output file
|
||||||
out_dir = get_context().config.work / "packages" / channel
|
out_dir = get_context().config.work / "packages" / channel
|
||||||
|
@ -212,7 +219,9 @@ class BuildQueueItem(TypedDict):
|
||||||
chroot: Chroot
|
chroot: Chroot
|
||||||
|
|
||||||
|
|
||||||
def has_cyclical_dependency(unmet_deps: dict[str, list[str]], item: BuildQueueItem, dep: str):
|
def has_cyclical_dependency(
|
||||||
|
unmet_deps: dict[str, list[str]], item: BuildQueueItem, dep: str
|
||||||
|
) -> bool:
|
||||||
pkgnames = [item["name"]] + list(item["apkbuild"]["subpackages"].keys())
|
pkgnames = [item["name"]] + list(item["apkbuild"]["subpackages"].keys())
|
||||||
|
|
||||||
for pkgname in pkgnames:
|
for pkgname in pkgnames:
|
||||||
|
@ -245,7 +254,7 @@ def prioritise_build_queue(disarray: list[BuildQueueItem]) -> list[BuildQueueIte
|
||||||
all_pkgnames.append(item["name"])
|
all_pkgnames.append(item["name"])
|
||||||
all_pkgnames += item["apkbuild"]["subpackages"].keys()
|
all_pkgnames += item["apkbuild"]["subpackages"].keys()
|
||||||
|
|
||||||
def queue_item(item: BuildQueueItem):
|
def queue_item(item: BuildQueueItem) -> None:
|
||||||
queue.append(item)
|
queue.append(item)
|
||||||
disarray.remove(item)
|
disarray.remove(item)
|
||||||
all_pkgnames.remove(item["name"])
|
all_pkgnames.remove(item["name"])
|
||||||
|
@ -443,10 +452,10 @@ def packages(
|
||||||
context: Context,
|
context: Context,
|
||||||
pkgnames: list[str],
|
pkgnames: list[str],
|
||||||
arch: Arch | None = None,
|
arch: Arch | None = None,
|
||||||
force=False,
|
force: bool = False,
|
||||||
strict=False,
|
strict: bool = False,
|
||||||
src=None,
|
src: str | None = None,
|
||||||
bootstrap_stage=BootstrapStage.NONE,
|
bootstrap_stage: int = BootstrapStage.NONE,
|
||||||
log_callback: Callable | None = None,
|
log_callback: Callable | None = None,
|
||||||
) -> list[str]:
|
) -> list[str]:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pmb.core.arch import Arch
|
from pmb.core.arch import Arch
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import pmb.config
|
import pmb.config
|
||||||
import pmb.chroot.apk
|
import pmb.chroot.apk
|
||||||
|
@ -11,11 +10,11 @@ import pmb.helpers.pmaports
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
from pmb.meta import Cache
|
from pmb.meta import Cache
|
||||||
from pmb.types import CrossCompileType
|
from pmb.types import Apkbuild, CrossCompileType
|
||||||
|
|
||||||
|
|
||||||
# FIXME (#2324): type hint Arch
|
# FIXME (#2324): type hint Arch
|
||||||
def arch_from_deviceinfo(pkgname, aport: Path) -> Arch | None:
|
def arch_from_deviceinfo(pkgname: str, aport: Path) -> Arch | None:
|
||||||
"""
|
"""
|
||||||
The device- packages are noarch packages. But it only makes sense to build
|
The device- packages are noarch packages. But it only makes sense to build
|
||||||
them for the device's architecture, which is specified in the deviceinfo
|
them for the device's architecture, which is specified in the deviceinfo
|
||||||
|
@ -39,7 +38,7 @@ def arch_from_deviceinfo(pkgname, aport: Path) -> Arch | None:
|
||||||
|
|
||||||
|
|
||||||
@Cache("package")
|
@Cache("package")
|
||||||
def arch(package: str | dict[str, Any]) -> Arch:
|
def arch(package: str | Apkbuild) -> Arch:
|
||||||
"""
|
"""
|
||||||
Find a good default in case the user did not specify for which architecture
|
Find a good default in case the user did not specify for which architecture
|
||||||
a package should be built.
|
a package should be built.
|
||||||
|
@ -84,7 +83,7 @@ def arch(package: str | dict[str, Any]) -> Arch:
|
||||||
return Arch.native()
|
return Arch.native()
|
||||||
|
|
||||||
|
|
||||||
def chroot(apkbuild: dict[str, str], arch: Arch) -> Chroot:
|
def chroot(apkbuild: Apkbuild, arch: Arch) -> Chroot:
|
||||||
if arch == Arch.native():
|
if arch == Arch.native():
|
||||||
return Chroot.native()
|
return Chroot.native()
|
||||||
|
|
||||||
|
@ -94,7 +93,7 @@ def chroot(apkbuild: dict[str, str], arch: Arch) -> Chroot:
|
||||||
return Chroot.buildroot(arch)
|
return Chroot.buildroot(arch)
|
||||||
|
|
||||||
|
|
||||||
def crosscompile(apkbuild, arch: Arch) -> CrossCompileType:
|
def crosscompile(apkbuild: Apkbuild, arch: Arch) -> CrossCompileType:
|
||||||
"""Decide the type of compilation necessary to build a given APKBUILD."""
|
"""Decide the type of compilation necessary to build a given APKBUILD."""
|
||||||
if not get_context().cross:
|
if not get_context().cross:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import enum
|
import enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
|
||||||
from pmb.core.pkgrepo import pkgrepo_paths
|
from pmb.core.pkgrepo import pkgrepo_paths
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
import pmb.chroot
|
import pmb.chroot
|
||||||
|
@ -9,6 +8,7 @@ from pmb.core import Context
|
||||||
from pmb.core.arch import Arch
|
from pmb.core.arch import Arch
|
||||||
from pmb.core.chroot import Chroot
|
from pmb.core.chroot import Chroot
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
|
from pmb.types import Apkbuild, CrossCompileType, Env
|
||||||
|
|
||||||
|
|
||||||
class BootstrapStage(enum.IntEnum):
|
class BootstrapStage(enum.IntEnum):
|
||||||
|
@ -21,7 +21,9 @@ class BootstrapStage(enum.IntEnum):
|
||||||
# We don't need explicit representations of the other numbers.
|
# We don't need explicit representations of the other numbers.
|
||||||
|
|
||||||
|
|
||||||
def override_source(apkbuild, pkgver, src, chroot: Chroot = Chroot.native()):
|
def override_source(
|
||||||
|
apkbuild: Apkbuild, pkgver: str, src: str | None, chroot: Chroot = Chroot.native()
|
||||||
|
) -> None:
|
||||||
"""Mount local source inside chroot and append new functions (prepare() etc.)
|
"""Mount local source inside chroot and append new functions (prepare() etc.)
|
||||||
to the APKBUILD to make it use the local source.
|
to the APKBUILD to make it use the local source.
|
||||||
"""
|
"""
|
||||||
|
@ -132,7 +134,7 @@ def mount_pmaports(chroot: Chroot = Chroot.native()) -> dict[str, Path]:
|
||||||
return dest_paths
|
return dest_paths
|
||||||
|
|
||||||
|
|
||||||
def link_to_git_dir(chroot: Chroot):
|
def link_to_git_dir(chroot: Chroot) -> None:
|
||||||
"""Make ``/home/pmos/build/.git`` point to the .git dir from pmaports.git, with a
|
"""Make ``/home/pmos/build/.git`` point to the .git dir from pmaports.git, with a
|
||||||
symlink so abuild does not fail (#1841).
|
symlink so abuild does not fail (#1841).
|
||||||
|
|
||||||
|
@ -158,7 +160,7 @@ def link_to_git_dir(chroot: Chroot):
|
||||||
pmb.chroot.user(["ln", "-sf", dest_paths["pmaports"] / ".git", "/home/pmos/build/.git"], chroot)
|
pmb.chroot.user(["ln", "-sf", dest_paths["pmaports"] / ".git", "/home/pmos/build/.git"], chroot)
|
||||||
|
|
||||||
|
|
||||||
def handle_csum_failure(apkbuild, chroot: Chroot):
|
def handle_csum_failure(apkbuild: Apkbuild, chroot: Chroot) -> None:
|
||||||
csum_fail_path = chroot / "tmp/apkbuild_verify_failed"
|
csum_fail_path = chroot / "tmp/apkbuild_verify_failed"
|
||||||
if not csum_fail_path.exists():
|
if not csum_fail_path.exists():
|
||||||
return
|
return
|
||||||
|
@ -181,17 +183,17 @@ def handle_csum_failure(apkbuild, chroot: Chroot):
|
||||||
|
|
||||||
def run_abuild(
|
def run_abuild(
|
||||||
context: Context,
|
context: Context,
|
||||||
apkbuild: dict[str, Any],
|
apkbuild: Apkbuild,
|
||||||
pkgver: str,
|
pkgver: str,
|
||||||
channel,
|
channel: str,
|
||||||
arch: Arch,
|
arch: Arch,
|
||||||
strict=False,
|
strict: bool = False,
|
||||||
force=False,
|
force: bool = False,
|
||||||
cross=None,
|
cross: CrossCompileType = None,
|
||||||
suffix: Chroot = Chroot.native(),
|
suffix: Chroot = Chroot.native(),
|
||||||
src=None,
|
src: str | None = None,
|
||||||
bootstrap_stage=BootstrapStage.NONE,
|
bootstrap_stage: int = BootstrapStage.NONE,
|
||||||
):
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Set up all environment variables and construct the abuild command (all
|
Set up all environment variables and construct the abuild command (all
|
||||||
depending on the cross-compiler method and target architecture), copy
|
depending on the cross-compiler method and target architecture), copy
|
||||||
|
@ -234,7 +236,7 @@ def run_abuild(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Environment variables
|
# Environment variables
|
||||||
env = {"CARCH": arch, "SUDO_APK": "abuild-apk --no-progress"}
|
env: Env = {"CARCH": str(arch), "SUDO_APK": "abuild-apk --no-progress"}
|
||||||
if cross == "native":
|
if cross == "native":
|
||||||
hostspec = arch.alpine_triple()
|
hostspec = arch.alpine_triple()
|
||||||
env["CROSS_COMPILE"] = hostspec + "-"
|
env["CROSS_COMPILE"] = hostspec + "-"
|
||||||
|
|
|
@ -12,7 +12,7 @@ import pmb.aportgen.core
|
||||||
import pmb.build
|
import pmb.build
|
||||||
import pmb.build.autodetect
|
import pmb.build.autodetect
|
||||||
import pmb.chroot
|
import pmb.chroot
|
||||||
from pmb.types import PathString, PmbArgs
|
from pmb.types import Env, PathString, PmbArgs
|
||||||
import pmb.helpers
|
import pmb.helpers
|
||||||
import pmb.helpers.mount
|
import pmb.helpers.mount
|
||||||
import pmb.helpers.pmaports
|
import pmb.helpers.pmaports
|
||||||
|
@ -97,7 +97,7 @@ def find_kbuild_output_dir(function_body):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def modify_apkbuild(pkgname: str, aport: Path):
|
def modify_apkbuild(pkgname: str, aport: Path) -> None:
|
||||||
"""Modify kernel APKBUILD to package build output from envkernel.sh."""
|
"""Modify kernel APKBUILD to package build output from envkernel.sh."""
|
||||||
work = get_context().config.work
|
work = get_context().config.work
|
||||||
apkbuild_path = aport / "APKBUILD"
|
apkbuild_path = aport / "APKBUILD"
|
||||||
|
@ -119,7 +119,9 @@ def modify_apkbuild(pkgname: str, aport: Path):
|
||||||
pmb.aportgen.core.rewrite(pkgname, apkbuild_path, fields=fields)
|
pmb.aportgen.core.rewrite(pkgname, apkbuild_path, fields=fields)
|
||||||
|
|
||||||
|
|
||||||
def run_abuild(context: Context, pkgname: str, arch: Arch, apkbuild_path: Path, kbuild_out):
|
def run_abuild(
|
||||||
|
context: Context, pkgname: str, arch: Arch, apkbuild_path: Path, kbuild_out: str
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Prepare build environment and run abuild.
|
Prepare build environment and run abuild.
|
||||||
|
|
||||||
|
@ -190,7 +192,7 @@ def run_abuild(context: Context, pkgname: str, arch: Arch, apkbuild_path: Path,
|
||||||
pmb.helpers.run.root(cmd)
|
pmb.helpers.run.root(cmd)
|
||||||
|
|
||||||
# Create the apk package
|
# Create the apk package
|
||||||
env = {
|
env: Env = {
|
||||||
"CARCH": str(arch),
|
"CARCH": str(arch),
|
||||||
"CHOST": str(arch),
|
"CHOST": str(arch),
|
||||||
"CBUILD": str(Arch.native()),
|
"CBUILD": str(Arch.native()),
|
||||||
|
@ -211,7 +213,7 @@ def run_abuild(context: Context, pkgname: str, arch: Arch, apkbuild_path: Path,
|
||||||
pmb.chroot.root(["rm", build_path / "src"])
|
pmb.chroot.root(["rm", build_path / "src"])
|
||||||
|
|
||||||
|
|
||||||
def package_kernel(args: PmbArgs):
|
def package_kernel(args: PmbArgs) -> None:
|
||||||
"""Frontend for 'pmbootstrap build --envkernel': creates a package from envkernel output."""
|
"""Frontend for 'pmbootstrap build --envkernel': creates a package from envkernel output."""
|
||||||
pkgname = args.packages[0]
|
pkgname = args.packages[0]
|
||||||
if len(args.packages) > 1 or not pkgname.startswith("linux-"):
|
if len(args.packages) > 1 or not pkgname.startswith("linux-"):
|
||||||
|
|
|
@ -13,9 +13,10 @@ import pmb.chroot.apk
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
from pmb.types import CrossCompileType
|
||||||
|
|
||||||
|
|
||||||
def init_abuild_minimal(chroot: Chroot = Chroot.native(), build_pkgs: list[str] = []):
|
def init_abuild_minimal(chroot: Chroot = Chroot.native(), build_pkgs: list[str] = []) -> None:
|
||||||
"""Initialize a minimal chroot with abuild where one can do 'abuild checksum'."""
|
"""Initialize a minimal chroot with abuild where one can do 'abuild checksum'."""
|
||||||
marker = chroot / "tmp/pmb_chroot_abuild_init_done"
|
marker = chroot / "tmp/pmb_chroot_abuild_init_done"
|
||||||
if os.path.exists(marker):
|
if os.path.exists(marker):
|
||||||
|
@ -111,7 +112,9 @@ def init(chroot: Chroot = Chroot.native()) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def init_compiler(context: Context, depends, cross, arch: Arch):
|
def init_compiler(
|
||||||
|
context: Context, depends: list[str], cross: CrossCompileType, arch: Arch
|
||||||
|
) -> None:
|
||||||
arch_str = str(arch)
|
arch_str = str(arch)
|
||||||
cross_pkgs = ["ccache-cross-symlinks", "abuild"]
|
cross_pkgs = ["ccache-cross-symlinks", "abuild"]
|
||||||
if "gcc4" in depends:
|
if "gcc4" in depends:
|
||||||
|
|
|
@ -18,6 +18,7 @@ import pmb.helpers.pmaports
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
import pmb.parse
|
import pmb.parse
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
from pmb.types import Apkbuild, Env
|
||||||
|
|
||||||
|
|
||||||
class KConfigUI(enum.Enum):
|
class KConfigUI(enum.Enum):
|
||||||
|
@ -45,7 +46,7 @@ class KConfigUI(enum.Enum):
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
def get_arch(apkbuild: dict[str, Any]) -> Arch:
|
def get_arch(apkbuild: Apkbuild) -> Arch:
|
||||||
"""Take the architecture from the APKBUILD or complain if it's ambiguous.
|
"""Take the architecture from the APKBUILD or complain if it's ambiguous.
|
||||||
|
|
||||||
This function only gets called if --arch is not set.
|
This function only gets called if --arch is not set.
|
||||||
|
@ -76,7 +77,7 @@ def get_arch(apkbuild: dict[str, Any]) -> Arch:
|
||||||
return Arch.from_str(apkbuild["arch"][0])
|
return Arch.from_str(apkbuild["arch"][0])
|
||||||
|
|
||||||
|
|
||||||
def get_outputdir(pkgname: str, apkbuild: dict[str, Any]) -> Path:
|
def get_outputdir(pkgname: str, apkbuild: Apkbuild) -> Path:
|
||||||
"""Get the folder for the kernel compilation output.
|
"""Get the folder for the kernel compilation output.
|
||||||
|
|
||||||
For most APKBUILDs, this is $builddir. But some older ones still use
|
For most APKBUILDs, this is $builddir. But some older ones still use
|
||||||
|
@ -121,7 +122,7 @@ def get_outputdir(pkgname: str, apkbuild: dict[str, Any]) -> Path:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def extract_and_patch_sources(pkgname: str, arch) -> None:
|
def extract_and_patch_sources(pkgname: str, arch: Arch) -> None:
|
||||||
pmb.build.copy_to_buildpath(pkgname)
|
pmb.build.copy_to_buildpath(pkgname)
|
||||||
logging.info("(native) extract kernel source")
|
logging.info("(native) extract kernel source")
|
||||||
pmb.chroot.user(["abuild", "unpack"], working_dir=Path("/home/pmos/build"))
|
pmb.chroot.user(["abuild", "unpack"], working_dir=Path("/home/pmos/build"))
|
||||||
|
@ -130,11 +131,18 @@ def extract_and_patch_sources(pkgname: str, arch) -> None:
|
||||||
["abuild", "prepare"],
|
["abuild", "prepare"],
|
||||||
working_dir=Path("/home/pmos/build"),
|
working_dir=Path("/home/pmos/build"),
|
||||||
output="interactive",
|
output="interactive",
|
||||||
env={"CARCH": arch},
|
env={"CARCH": str(arch)},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _make(chroot: pmb.core.Chroot, make_command: str, env, pkgname, arch, apkbuild) -> None:
|
def _make(
|
||||||
|
chroot: pmb.core.Chroot,
|
||||||
|
make_command: str,
|
||||||
|
env: Env,
|
||||||
|
pkgname: str,
|
||||||
|
arch: Arch,
|
||||||
|
apkbuild: Apkbuild,
|
||||||
|
) -> None:
|
||||||
aport = pmb.helpers.pmaports.find(pkgname)
|
aport = pmb.helpers.pmaports.find(pkgname)
|
||||||
outputdir = get_outputdir(pkgname, apkbuild)
|
outputdir = get_outputdir(pkgname, apkbuild)
|
||||||
|
|
||||||
|
@ -155,7 +163,7 @@ def _make(chroot: pmb.core.Chroot, make_command: str, env, pkgname, arch, apkbui
|
||||||
pmb.build.checksum.update(pkgname)
|
pmb.build.checksum.update(pkgname)
|
||||||
|
|
||||||
|
|
||||||
def _init(pkgname: str, arch: Arch | None) -> tuple[str, Arch, Any, Chroot, dict[str, str]]:
|
def _init(pkgname: str, arch: Arch | None) -> tuple[str, Arch, Any, Chroot, Env]:
|
||||||
"""
|
"""
|
||||||
:returns: pkgname, arch, apkbuild, chroot, env
|
:returns: pkgname, arch, apkbuild, chroot, env
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -4,6 +4,7 @@ import enum
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
import shlex
|
import shlex
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
@ -17,10 +18,13 @@ import pmb.helpers.run
|
||||||
import pmb.parse.apkindex
|
import pmb.parse.apkindex
|
||||||
import pmb.parse.version
|
import pmb.parse.version
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
from pmb.core.arch import Arch
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def copy_to_buildpath(package, chroot: Chroot = Chroot.native(), no_override: bool = False):
|
def copy_to_buildpath(
|
||||||
|
package: str, chroot: Chroot = Chroot.native(), no_override: bool = False
|
||||||
|
) -> None:
|
||||||
# Sanity check
|
# Sanity check
|
||||||
aport = pmb.helpers.pmaports.find(package)
|
aport = pmb.helpers.pmaports.find(package)
|
||||||
if not os.path.exists(aport / "APKBUILD"):
|
if not os.path.exists(aport / "APKBUILD"):
|
||||||
|
@ -49,7 +53,7 @@ def copy_to_buildpath(package, chroot: Chroot = Chroot.native(), no_override: bo
|
||||||
pmb.chroot.root(["chown", "-R", "pmos:pmos", "/home/pmos/build"], chroot)
|
pmb.chroot.root(["chown", "-R", "pmos:pmos", "/home/pmos/build"], chroot)
|
||||||
|
|
||||||
|
|
||||||
def abuild_overrides(apkbuild: Path):
|
def abuild_overrides(apkbuild: Path) -> None:
|
||||||
"""Override some abuild functions by patching the APKBUILD file."""
|
"""Override some abuild functions by patching the APKBUILD file."""
|
||||||
|
|
||||||
if apkbuild.is_relative_to(get_context().config.work / "cache_git"):
|
if apkbuild.is_relative_to(get_context().config.work / "cache_git"):
|
||||||
|
@ -77,7 +81,7 @@ class BuildStatus(enum.Enum):
|
||||||
return self in [BuildStatus.OUTDATED, BuildStatus.NEW]
|
return self in [BuildStatus.OUTDATED, BuildStatus.NEW]
|
||||||
|
|
||||||
|
|
||||||
def get_status(arch, apkbuild) -> BuildStatus:
|
def get_status(arch: Arch | None, apkbuild: dict[str, Any]) -> BuildStatus:
|
||||||
"""Check if the package has already been built.
|
"""Check if the package has already been built.
|
||||||
|
|
||||||
Compared to abuild's check, this check also works for different architectures.
|
Compared to abuild's check, this check also works for different architectures.
|
||||||
|
@ -170,7 +174,7 @@ def index_repo(arch=None):
|
||||||
pmb.parse.apkindex.clear_cache(path / "APKINDEX.tar.gz")
|
pmb.parse.apkindex.clear_cache(path / "APKINDEX.tar.gz")
|
||||||
|
|
||||||
|
|
||||||
def configure_abuild(chroot: Chroot, verify=False):
|
def configure_abuild(chroot: Chroot, verify: bool = False) -> None:
|
||||||
"""Set the correct JOBS count in ``abuild.conf``.
|
"""Set the correct JOBS count in ``abuild.conf``.
|
||||||
|
|
||||||
:param verify: internally used to test if changing the config has worked.
|
:param verify: internally used to test if changing the config has worked.
|
||||||
|
@ -198,7 +202,7 @@ def configure_abuild(chroot: Chroot, verify=False):
|
||||||
pmb.chroot.root(["sed", "-i", f"$ a\\{prefix}{jobs}", "/etc/abuild.conf"], chroot)
|
pmb.chroot.root(["sed", "-i", f"$ a\\{prefix}{jobs}", "/etc/abuild.conf"], chroot)
|
||||||
|
|
||||||
|
|
||||||
def configure_ccache(chroot: Chroot = Chroot.native(), verify=False):
|
def configure_ccache(chroot: Chroot = Chroot.native(), verify: bool = False) -> None:
|
||||||
"""Set the maximum ccache size.
|
"""Set the maximum ccache size.
|
||||||
|
|
||||||
:param verify: internally used to test if changing the config has worked.
|
:param verify: internally used to test if changing the config has worked.
|
||||||
|
|
|
@ -32,8 +32,11 @@ from pmb.helpers.exceptions import NonBugError
|
||||||
|
|
||||||
@Cache("chroot", "user_repository", mirrors_exclude=[])
|
@Cache("chroot", "user_repository", mirrors_exclude=[])
|
||||||
def update_repository_list(
|
def update_repository_list(
|
||||||
chroot: Chroot, user_repository=False, mirrors_exclude: list[str] = [], check=False
|
chroot: Chroot,
|
||||||
):
|
user_repository: bool = False,
|
||||||
|
mirrors_exclude: list[str] = [],
|
||||||
|
check: bool = False,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Update /etc/apk/repositories, if it is outdated (when the user changed the
|
Update /etc/apk/repositories, if it is outdated (when the user changed the
|
||||||
--mirror-alpine or --mirror-pmOS parameters).
|
--mirror-alpine or --mirror-pmOS parameters).
|
||||||
|
@ -79,7 +82,7 @@ def update_repository_list(
|
||||||
|
|
||||||
|
|
||||||
@Cache("chroot")
|
@Cache("chroot")
|
||||||
def check_min_version(chroot: Chroot = Chroot.native()):
|
def check_min_version(chroot: Chroot = Chroot.native()) -> None:
|
||||||
"""
|
"""
|
||||||
Check the minimum apk version, before running it the first time in the
|
Check the minimum apk version, before running it the first time in the
|
||||||
current session (lifetime of one pmbootstrap call).
|
current session (lifetime of one pmbootstrap call).
|
||||||
|
@ -179,7 +182,9 @@ def packages_get_locally_built_apks(package_list: list[str], arch: Arch) -> list
|
||||||
|
|
||||||
# FIXME: list[Sequence[PathString]] weirdness
|
# FIXME: list[Sequence[PathString]] weirdness
|
||||||
# mypy: disable-error-code="operator"
|
# mypy: disable-error-code="operator"
|
||||||
def install_run_apk(to_add: list[str], to_add_local: list[Path], to_del: list[str], chroot: Chroot):
|
def install_run_apk(
|
||||||
|
to_add: list[str], to_add_local: list[Path], to_del: list[str], chroot: Chroot
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Run apk to add packages, and ensure only the desired packages get
|
Run apk to add packages, and ensure only the desired packages get
|
||||||
explicitly marked as installed.
|
explicitly marked as installed.
|
||||||
|
@ -248,7 +253,7 @@ def install_run_apk(to_add: list[str], to_add_local: list[Path], to_del: list[st
|
||||||
pmb.chroot.root(["apk", "--no-progress"] + command, chroot)
|
pmb.chroot.root(["apk", "--no-progress"] + command, chroot)
|
||||||
|
|
||||||
|
|
||||||
def install(packages, chroot: Chroot, build=True, quiet: bool = False):
|
def install(packages: list[str], chroot: Chroot, build: bool = True, quiet: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Install packages from pmbootstrap's local package index or the pmOS/Alpine
|
Install packages from pmbootstrap's local package index or the pmOS/Alpine
|
||||||
binary package mirrors. Iterate over all dependencies recursively, and
|
binary package mirrors. Iterate over all dependencies recursively, and
|
||||||
|
|
|
@ -11,11 +11,11 @@ import pmb.parse
|
||||||
import pmb.chroot.apk
|
import pmb.chroot.apk
|
||||||
|
|
||||||
|
|
||||||
def is_registered(arch_qemu: Arch):
|
def is_registered(arch_qemu: Arch) -> bool:
|
||||||
return os.path.exists(f"/proc/sys/fs/binfmt_misc/qemu-{arch_qemu}")
|
return os.path.exists(f"/proc/sys/fs/binfmt_misc/qemu-{arch_qemu}")
|
||||||
|
|
||||||
|
|
||||||
def register(arch: Arch):
|
def register(arch: Arch) -> None:
|
||||||
"""
|
"""
|
||||||
Get arch, magic, mask.
|
Get arch, magic, mask.
|
||||||
"""
|
"""
|
||||||
|
@ -56,7 +56,7 @@ def register(arch: Arch):
|
||||||
pmb.helpers.run.root(["sh", "-c", 'echo "' + code + '" > ' + register])
|
pmb.helpers.run.root(["sh", "-c", 'echo "' + code + '" > ' + register])
|
||||||
|
|
||||||
|
|
||||||
def unregister(arch: Arch):
|
def unregister(arch: Arch) -> None:
|
||||||
arch_qemu = arch.qemu()
|
arch_qemu = arch.qemu()
|
||||||
binfmt_file = "/proc/sys/fs/binfmt_misc/qemu-" + arch_qemu
|
binfmt_file = "/proc/sys/fs/binfmt_misc/qemu-" + arch_qemu
|
||||||
if not os.path.exists(binfmt_file):
|
if not os.path.exists(binfmt_file):
|
||||||
|
|
|
@ -30,7 +30,7 @@ class UsrMerge(enum.Enum):
|
||||||
OFF = 2
|
OFF = 2
|
||||||
|
|
||||||
|
|
||||||
def copy_resolv_conf(chroot: Chroot):
|
def copy_resolv_conf(chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Use pythons super fast file compare function (due to caching)
|
Use pythons super fast file compare function (due to caching)
|
||||||
and copy the /etc/resolv.conf to the chroot, in case it is
|
and copy the /etc/resolv.conf to the chroot, in case it is
|
||||||
|
@ -46,7 +46,7 @@ def copy_resolv_conf(chroot: Chroot):
|
||||||
pmb.helpers.run.root(["touch", resolv_path])
|
pmb.helpers.run.root(["touch", resolv_path])
|
||||||
|
|
||||||
|
|
||||||
def mark_in_chroot(chroot: Chroot = Chroot.native()):
|
def mark_in_chroot(chroot: Chroot = Chroot.native()) -> None:
|
||||||
"""
|
"""
|
||||||
Touch a flag so we can know when we're running in chroot (and
|
Touch a flag so we can know when we're running in chroot (and
|
||||||
don't accidentally flash partitions on our host). This marker
|
don't accidentally flash partitions on our host). This marker
|
||||||
|
@ -74,7 +74,7 @@ def init_keys():
|
||||||
pmb.helpers.run.root(["cp", key, target])
|
pmb.helpers.run.root(["cp", key, target])
|
||||||
|
|
||||||
|
|
||||||
def init_usr_merge(chroot: Chroot):
|
def init_usr_merge(chroot: Chroot) -> None:
|
||||||
logging.info(f"({chroot}) merge /usr")
|
logging.info(f"({chroot}) merge /usr")
|
||||||
script = f"{pmb.config.pmb_src}/pmb/data/merge-usr.sh"
|
script = f"{pmb.config.pmb_src}/pmb/data/merge-usr.sh"
|
||||||
pmb.helpers.run.root(["sh", "-e", script, "CALLED_FROM_PMB", chroot.path])
|
pmb.helpers.run.root(["sh", "-e", script, "CALLED_FROM_PMB", chroot.path])
|
||||||
|
@ -104,7 +104,7 @@ def warn_if_chroots_outdated():
|
||||||
|
|
||||||
|
|
||||||
@Cache("chroot")
|
@Cache("chroot")
|
||||||
def init(chroot: Chroot, usr_merge=UsrMerge.AUTO):
|
def init(chroot: Chroot, usr_merge: UsrMerge = UsrMerge.AUTO) -> None:
|
||||||
"""
|
"""
|
||||||
Initialize a chroot by copying the resolv.conf and updating
|
Initialize a chroot by copying the resolv.conf and updating
|
||||||
/etc/apk/repositories. If /bin/sh is missing, create the chroot from
|
/etc/apk/repositories. If /bin/sh is missing, create the chroot from
|
||||||
|
|
|
@ -12,7 +12,7 @@ from pmb.core import Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def build(flavor, chroot: Chroot):
|
def build(flavor: str | None, chroot: Chroot) -> None:
|
||||||
# Update mkinitfs and hooks
|
# Update mkinitfs and hooks
|
||||||
pmb.chroot.apk.install(["postmarketos-mkinitfs"], chroot)
|
pmb.chroot.apk.install(["postmarketos-mkinitfs"], chroot)
|
||||||
pmb.chroot.initfs_hooks.update(chroot)
|
pmb.chroot.initfs_hooks.update(chroot)
|
||||||
|
@ -31,7 +31,7 @@ def build(flavor, chroot: Chroot):
|
||||||
pmb.chroot.root(["mkinitfs", "-o", f"/boot/initramfs-{flavor}", release], chroot)
|
pmb.chroot.root(["mkinitfs", "-o", f"/boot/initramfs-{flavor}", release], chroot)
|
||||||
|
|
||||||
|
|
||||||
def extract(flavor, chroot: Chroot, extra=False):
|
def extract(flavor: str | None, chroot: Chroot, extra: bool = False) -> Path:
|
||||||
"""
|
"""
|
||||||
Extract the initramfs to /tmp/initfs-extracted or the initramfs-extra to
|
Extract the initramfs to /tmp/initfs-extracted or the initramfs-extra to
|
||||||
/tmp/initfs-extra-extracted and return the outside extraction path.
|
/tmp/initfs-extra-extracted and return the outside extraction path.
|
||||||
|
@ -86,7 +86,7 @@ def ls(flavor, suffix, extra=False):
|
||||||
pmb.chroot.root(["rm", "-r", tmp], suffix)
|
pmb.chroot.root(["rm", "-r", tmp], suffix)
|
||||||
|
|
||||||
|
|
||||||
def frontend(args: PmbArgs):
|
def frontend(args: PmbArgs) -> None:
|
||||||
# Find the appropriate kernel flavor
|
# Find the appropriate kernel flavor
|
||||||
context = get_context()
|
context = get_context()
|
||||||
chroot = Chroot.rootfs(context.config.device)
|
chroot = Chroot.rootfs(context.config.device)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import pmb.chroot.apk
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
|
||||||
|
|
||||||
def list_chroot(suffix: Chroot, remove_prefix=True):
|
def list_chroot(suffix: Chroot, remove_prefix: bool = True) -> list[str]:
|
||||||
ret = []
|
ret = []
|
||||||
prefix = pmb.config.initfs_hook_prefix
|
prefix = pmb.config.initfs_hook_prefix
|
||||||
for pkgname in pmb.chroot.apk.installed(suffix).keys():
|
for pkgname in pmb.chroot.apk.installed(suffix).keys():
|
||||||
|
@ -21,7 +21,7 @@ def list_chroot(suffix: Chroot, remove_prefix=True):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def list_aports():
|
def list_aports() -> list[str]:
|
||||||
ret = []
|
ret = []
|
||||||
prefix = pmb.config.initfs_hook_prefix
|
prefix = pmb.config.initfs_hook_prefix
|
||||||
for path in pkgrepo_iglob(f"*/{prefix}*"):
|
for path in pkgrepo_iglob(f"*/{prefix}*"):
|
||||||
|
@ -29,7 +29,7 @@ def list_aports():
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def ls(suffix: Chroot):
|
def ls(suffix: Chroot) -> None:
|
||||||
hooks_chroot = list_chroot(suffix)
|
hooks_chroot = list_chroot(suffix)
|
||||||
hooks_aports = list_aports()
|
hooks_aports = list_aports()
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ def ls(suffix: Chroot):
|
||||||
logging.info(line)
|
logging.info(line)
|
||||||
|
|
||||||
|
|
||||||
def add(hook, suffix: Chroot):
|
def add(hook: str, suffix: Chroot) -> None:
|
||||||
if hook not in list_aports():
|
if hook not in list_aports():
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Invalid hook name!" " Run 'pmbootstrap initfs hook_ls'" " to get a list of all hooks."
|
"Invalid hook name!" " Run 'pmbootstrap initfs hook_ls'" " to get a list of all hooks."
|
||||||
|
@ -47,14 +47,14 @@ def add(hook, suffix: Chroot):
|
||||||
pmb.chroot.apk.install([f"{prefix}{hook}"], suffix)
|
pmb.chroot.apk.install([f"{prefix}{hook}"], suffix)
|
||||||
|
|
||||||
|
|
||||||
def delete(hook, suffix: Chroot):
|
def delete(hook: str, suffix: Chroot) -> None:
|
||||||
if hook not in list_chroot(suffix):
|
if hook not in list_chroot(suffix):
|
||||||
raise RuntimeError("There is no such hook installed!")
|
raise RuntimeError("There is no such hook installed!")
|
||||||
prefix = pmb.config.initfs_hook_prefix
|
prefix = pmb.config.initfs_hook_prefix
|
||||||
pmb.chroot.root(["apk", "del", f"{prefix}{hook}"], suffix)
|
pmb.chroot.root(["apk", "del", f"{prefix}{hook}"], suffix)
|
||||||
|
|
||||||
|
|
||||||
def update(suffix: Chroot):
|
def update(suffix: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Rebuild and update all hooks that are out of date
|
Rebuild and update all hooks that are out of date
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -15,7 +15,7 @@ from pmb.core import Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def mount_chroot_image(chroot: Chroot):
|
def mount_chroot_image(chroot: Chroot) -> None:
|
||||||
"""Mount an IMAGE type chroot, to modify an existing rootfs image. This
|
"""Mount an IMAGE type chroot, to modify an existing rootfs image. This
|
||||||
doesn't support split images yet!"""
|
doesn't support split images yet!"""
|
||||||
# Make sure everything is nicely unmounted just to be super safe
|
# Make sure everything is nicely unmounted just to be super safe
|
||||||
|
@ -42,7 +42,7 @@ def mount_chroot_image(chroot: Chroot):
|
||||||
logging.info(f"({chroot}) mounted {chroot.name}")
|
logging.info(f"({chroot}) mounted {chroot.name}")
|
||||||
|
|
||||||
|
|
||||||
def create_device_nodes(chroot: Chroot):
|
def create_device_nodes(chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Create device nodes for null, zero, full, random, urandom in the chroot.
|
Create device nodes for null, zero, full, random, urandom in the chroot.
|
||||||
"""
|
"""
|
||||||
|
@ -90,7 +90,7 @@ def create_device_nodes(chroot: Chroot):
|
||||||
raise RuntimeError(f"Failed to create device nodes in the '{chroot}' chroot.")
|
raise RuntimeError(f"Failed to create device nodes in the '{chroot}' chroot.")
|
||||||
|
|
||||||
|
|
||||||
def mount_dev_tmpfs(chroot: Chroot = Chroot.native()):
|
def mount_dev_tmpfs(chroot: Chroot = Chroot.native()) -> None:
|
||||||
"""
|
"""
|
||||||
Mount tmpfs inside the chroot's dev folder to make sure we can create
|
Mount tmpfs inside the chroot's dev folder to make sure we can create
|
||||||
device nodes, even if the filesystem of the work folder does not support
|
device nodes, even if the filesystem of the work folder does not support
|
||||||
|
@ -116,7 +116,7 @@ def mount_dev_tmpfs(chroot: Chroot = Chroot.native()):
|
||||||
pmb.helpers.run.root(["ln", "-sf", "/proc/self/fd", f"{dev}/"])
|
pmb.helpers.run.root(["ln", "-sf", "/proc/self/fd", f"{dev}/"])
|
||||||
|
|
||||||
|
|
||||||
def mount(chroot: Chroot):
|
def mount(chroot: Chroot) -> None:
|
||||||
if chroot.type == ChrootType.IMAGE and not pmb.mount.ismount(chroot.path):
|
if chroot.type == ChrootType.IMAGE and not pmb.mount.ismount(chroot.path):
|
||||||
mount_chroot_image(chroot)
|
mount_chroot_image(chroot)
|
||||||
|
|
||||||
|
@ -154,7 +154,7 @@ def mount(chroot: Chroot):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def mount_native_into_foreign(chroot: Chroot):
|
def mount_native_into_foreign(chroot: Chroot) -> None:
|
||||||
source = Chroot.native().path
|
source = Chroot.native().path
|
||||||
target = chroot / "native"
|
target = chroot / "native"
|
||||||
pmb.helpers.mount.bind(source, target)
|
pmb.helpers.mount.bind(source, target)
|
||||||
|
@ -166,7 +166,7 @@ def mount_native_into_foreign(chroot: Chroot):
|
||||||
# pmb.helpers.run.root(["ln", "-sf", "/native/usr/bin/pigz", "/usr/local/bin/pigz"])
|
# pmb.helpers.run.root(["ln", "-sf", "/native/usr/bin/pigz", "/usr/local/bin/pigz"])
|
||||||
|
|
||||||
|
|
||||||
def remove_mnt_pmbootstrap(chroot: Chroot):
|
def remove_mnt_pmbootstrap(chroot: Chroot) -> None:
|
||||||
"""Safely remove /mnt/pmbootstrap directories from the chroot, without
|
"""Safely remove /mnt/pmbootstrap directories from the chroot, without
|
||||||
running rm -r as root and potentially removing data inside the
|
running rm -r as root and potentially removing data inside the
|
||||||
mountpoint in case it was still mounted (bug in pmbootstrap, or user
|
mountpoint in case it was still mounted (bug in pmbootstrap, or user
|
||||||
|
|
|
@ -8,7 +8,7 @@ import pmb.install
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
|
||||||
|
|
||||||
def kernel_flavor_installed(chroot: Chroot, autoinstall=True) -> str | None:
|
def kernel_flavor_installed(chroot: Chroot, autoinstall: bool = True) -> str | None:
|
||||||
"""
|
"""
|
||||||
Get installed kernel flavor. Optionally install the device's kernel
|
Get installed kernel flavor. Optionally install the device's kernel
|
||||||
beforehand.
|
beforehand.
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
import os
|
import os
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
from typing import overload, Literal
|
||||||
|
|
||||||
import pmb.config
|
import pmb.config
|
||||||
import pmb.chroot
|
import pmb.chroot
|
||||||
|
@ -11,7 +13,14 @@ import pmb.chroot.binfmt
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
import pmb.helpers.run_core
|
import pmb.helpers.run_core
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
from pmb.types import Env, PathString
|
from pmb.types import (
|
||||||
|
Env,
|
||||||
|
PathString,
|
||||||
|
RunOutputType,
|
||||||
|
RunOutputTypeDefault,
|
||||||
|
RunOutputTypePopen,
|
||||||
|
RunReturnType,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def executables_absolute_path():
|
def executables_absolute_path():
|
||||||
|
@ -35,13 +44,13 @@ def rootm(
|
||||||
cmds: Sequence[Sequence[PathString]],
|
cmds: Sequence[Sequence[PathString]],
|
||||||
chroot: Chroot = Chroot.native(),
|
chroot: Chroot = Chroot.native(),
|
||||||
working_dir: PurePath = PurePath("/"),
|
working_dir: PurePath = PurePath("/"),
|
||||||
output="log",
|
output: RunOutputType = "log",
|
||||||
output_return=False,
|
output_return: bool = False,
|
||||||
check=None,
|
check: bool | None = None,
|
||||||
env={},
|
env: Env = {},
|
||||||
disable_timeout=False,
|
disable_timeout: bool = False,
|
||||||
add_proxy_env_vars=True,
|
add_proxy_env_vars: bool = True,
|
||||||
):
|
) -> RunReturnType:
|
||||||
"""
|
"""
|
||||||
Run a list of commands inside a chroot as root.
|
Run a list of commands inside a chroot as root.
|
||||||
|
|
||||||
|
@ -110,17 +119,59 @@ def rootm(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def root(
|
||||||
|
cmds: Sequence[PathString],
|
||||||
|
chroot: Chroot = ...,
|
||||||
|
working_dir: PurePath = ...,
|
||||||
|
output: RunOutputTypePopen = ...,
|
||||||
|
output_return: Literal[False] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
disable_timeout: bool = ...,
|
||||||
|
add_proxy_env_vars: bool = ...,
|
||||||
|
) -> subprocess.Popen: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def root(
|
||||||
|
cmds: Sequence[PathString],
|
||||||
|
chroot: Chroot = ...,
|
||||||
|
working_dir: PurePath = ...,
|
||||||
|
output: RunOutputTypeDefault = ...,
|
||||||
|
output_return: Literal[False] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
disable_timeout: bool = ...,
|
||||||
|
add_proxy_env_vars: bool = ...,
|
||||||
|
) -> int: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def root(
|
||||||
|
cmds: Sequence[PathString],
|
||||||
|
chroot: Chroot = ...,
|
||||||
|
working_dir: PurePath = ...,
|
||||||
|
output: RunOutputType = ...,
|
||||||
|
output_return: Literal[True] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
disable_timeout: bool = ...,
|
||||||
|
add_proxy_env_vars: bool = ...,
|
||||||
|
) -> str: ...
|
||||||
|
|
||||||
|
|
||||||
def root(
|
def root(
|
||||||
cmds: Sequence[PathString],
|
cmds: Sequence[PathString],
|
||||||
chroot: Chroot = Chroot.native(),
|
chroot: Chroot = Chroot.native(),
|
||||||
working_dir: PurePath = PurePath("/"),
|
working_dir: PurePath = PurePath("/"),
|
||||||
output="log",
|
output: RunOutputType = "log",
|
||||||
output_return=False,
|
output_return: bool = False,
|
||||||
check=None,
|
check: bool | None = None,
|
||||||
env={},
|
env: Env = {},
|
||||||
disable_timeout=False,
|
disable_timeout: bool = False,
|
||||||
add_proxy_env_vars=True,
|
add_proxy_env_vars: bool = True,
|
||||||
):
|
) -> RunReturnType:
|
||||||
return rootm(
|
return rootm(
|
||||||
[cmds],
|
[cmds],
|
||||||
chroot,
|
chroot,
|
||||||
|
@ -138,11 +189,11 @@ def userm(
|
||||||
cmds: Sequence[Sequence[PathString]],
|
cmds: Sequence[Sequence[PathString]],
|
||||||
chroot: Chroot = Chroot.native(),
|
chroot: Chroot = Chroot.native(),
|
||||||
working_dir: Path = Path("/"),
|
working_dir: Path = Path("/"),
|
||||||
output="log",
|
output: RunOutputType = "log",
|
||||||
output_return=False,
|
output_return: bool = False,
|
||||||
check=None,
|
check: bool | None = None,
|
||||||
env={},
|
env: Env = {},
|
||||||
):
|
) -> RunReturnType:
|
||||||
"""
|
"""
|
||||||
Run a command inside a chroot as "user". We always use the BusyBox
|
Run a command inside a chroot as "user". We always use the BusyBox
|
||||||
implementation of 'su', because other implementations may override the PATH
|
implementation of 'su', because other implementations may override the PATH
|
||||||
|
@ -162,24 +213,61 @@ def userm(
|
||||||
|
|
||||||
flat_cmd = pmb.helpers.run_core.flat_cmd(cmds, env=env)
|
flat_cmd = pmb.helpers.run_core.flat_cmd(cmds, env=env)
|
||||||
cmd = ["busybox", "su", "pmos", "-c", flat_cmd]
|
cmd = ["busybox", "su", "pmos", "-c", flat_cmd]
|
||||||
return pmb.chroot.root(
|
# Can't figure out why this one fails :(
|
||||||
|
return pmb.chroot.root( # type: ignore[call-overload]
|
||||||
cmd, chroot, working_dir, output, output_return, check, {}, add_proxy_env_vars=False
|
cmd, chroot, working_dir, output, output_return, check, {}, add_proxy_env_vars=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def user(
|
||||||
|
cmd: Sequence[PathString],
|
||||||
|
chroot: Chroot = ...,
|
||||||
|
working_dir: Path = ...,
|
||||||
|
output: RunOutputTypePopen = ...,
|
||||||
|
output_return: Literal[False] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
) -> subprocess.Popen: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def user(
|
||||||
|
cmd: Sequence[PathString],
|
||||||
|
chroot: Chroot = ...,
|
||||||
|
working_dir: Path = ...,
|
||||||
|
output: RunOutputTypeDefault = ...,
|
||||||
|
output_return: Literal[False] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
) -> int: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def user(
|
||||||
|
cmd: Sequence[PathString],
|
||||||
|
chroot: Chroot = ...,
|
||||||
|
working_dir: Path = ...,
|
||||||
|
output: RunOutputType = ...,
|
||||||
|
output_return: Literal[True] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
) -> str: ...
|
||||||
|
|
||||||
|
|
||||||
def user(
|
def user(
|
||||||
cmd: Sequence[PathString],
|
cmd: Sequence[PathString],
|
||||||
chroot: Chroot = Chroot.native(),
|
chroot: Chroot = Chroot.native(),
|
||||||
working_dir: Path = Path("/"),
|
working_dir: Path = Path("/"),
|
||||||
output="log",
|
output: RunOutputType = "log",
|
||||||
output_return=False,
|
output_return: bool = False,
|
||||||
check=None,
|
check: bool | None = None,
|
||||||
env={},
|
env: Env = {},
|
||||||
):
|
) -> RunReturnType:
|
||||||
return userm([cmd], chroot, working_dir, output, output_return, check, env)
|
return userm([cmd], chroot, working_dir, output, output_return, check, env)
|
||||||
|
|
||||||
|
|
||||||
def exists(username, chroot: Chroot = Chroot.native()):
|
def exists(username: str, chroot: Chroot = Chroot.native()) -> bool:
|
||||||
"""
|
"""
|
||||||
Checks if username exists in the system
|
Checks if username exists in the system
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ def kill_sccache():
|
||||||
pmb.chroot.root(["sccache", "--stop-server"])
|
pmb.chroot.root(["sccache", "--stop-server"])
|
||||||
|
|
||||||
|
|
||||||
def shutdown_cryptsetup_device(name: str):
|
def shutdown_cryptsetup_device(name: str) -> None:
|
||||||
"""
|
"""
|
||||||
:param name: cryptsetup device name, usually "pm_crypt" in pmbootstrap
|
:param name: cryptsetup device name, usually "pm_crypt" in pmbootstrap
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -20,7 +20,7 @@ from pmb.core import Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def del_chroot(path: Path, confirm=True, dry=False):
|
def del_chroot(path: Path, confirm: bool = True, dry: bool = False) -> None:
|
||||||
if confirm and not pmb.helpers.cli.confirm(f"Remove {path}?"):
|
if confirm and not pmb.helpers.cli.confirm(f"Remove {path}?"):
|
||||||
return
|
return
|
||||||
if dry:
|
if dry:
|
||||||
|
@ -37,16 +37,16 @@ def del_chroot(path: Path, confirm=True, dry=False):
|
||||||
|
|
||||||
|
|
||||||
def zap(
|
def zap(
|
||||||
confirm=True,
|
confirm: bool = True,
|
||||||
dry=False,
|
dry: bool = False,
|
||||||
pkgs_local=False,
|
pkgs_local: bool = False,
|
||||||
http=False,
|
http: bool = False,
|
||||||
pkgs_local_mismatch=False,
|
pkgs_local_mismatch: bool = False,
|
||||||
pkgs_online_mismatch=False,
|
pkgs_online_mismatch: bool = False,
|
||||||
distfiles=False,
|
distfiles: bool = False,
|
||||||
rust=False,
|
rust: bool = False,
|
||||||
netboot=False,
|
netboot: bool = False,
|
||||||
):
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Shutdown everything inside the chroots (e.g. adb), umount
|
Shutdown everything inside the chroots (e.g. adb), umount
|
||||||
everything and then safely remove folders from the work-directory.
|
everything and then safely remove folders from the work-directory.
|
||||||
|
|
|
@ -6,7 +6,7 @@ from pmb.helpers import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pmb.chroot
|
import pmb.chroot
|
||||||
from pmb.types import PmbArgs
|
from pmb.types import Env, PmbArgs
|
||||||
import pmb.helpers.cli
|
import pmb.helpers.cli
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ def run_scripts(topdir, scripts):
|
||||||
copy_git_repo_to_chroot(topdir)
|
copy_git_repo_to_chroot(topdir)
|
||||||
repo_copied = True
|
repo_copied = True
|
||||||
|
|
||||||
env = {"TESTUSER": "pmos"}
|
env: Env = {"TESTUSER": "pmos"}
|
||||||
rc = pmb.chroot.root(
|
rc = pmb.chroot.root(
|
||||||
[script_path], check=False, env=env, working_dir=Path("/home/pmos/ci"), output="tui"
|
[script_path], check=False, env=env, working_dir=Path("/home/pmos/ci"), output="tui"
|
||||||
)
|
)
|
||||||
|
|
|
@ -55,7 +55,7 @@ unmigrated_commands = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def run_command(args: PmbArgs):
|
def run_command(args: PmbArgs) -> None:
|
||||||
# Handle deprecated command format
|
# Handle deprecated command format
|
||||||
if args.action in unmigrated_commands:
|
if args.action in unmigrated_commands:
|
||||||
getattr(frontend, args.action)(args)
|
getattr(frontend, args.action)(args)
|
||||||
|
|
|
@ -114,7 +114,7 @@ class RepoBootstrap(commands.Command):
|
||||||
|
|
||||||
bootstrap_stage = int(step.split("bootstrap_", 1)[1])
|
bootstrap_stage = int(step.split("bootstrap_", 1)[1])
|
||||||
|
|
||||||
def log_wrapper(pkg: BuildQueueItem):
|
def log_wrapper(pkg: BuildQueueItem) -> None:
|
||||||
self.log_progress(f"building {pkg['name']}")
|
self.log_progress(f"building {pkg['name']}")
|
||||||
|
|
||||||
packages = self.get_packages(bootstrap_line)
|
packages = self.get_packages(bootstrap_line)
|
||||||
|
|
|
@ -50,7 +50,7 @@ def load(path: Path) -> Config:
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def serialize(config: Config, skip_defaults=True) -> configparser.ConfigParser:
|
def serialize(config: Config, skip_defaults: bool = True) -> configparser.ConfigParser:
|
||||||
"""Serialize the config object into a ConfigParser to write it out
|
"""Serialize the config object into a ConfigParser to write it out
|
||||||
in the pmbootstrap_v3.cfg INI format.
|
in the pmbootstrap_v3.cfg INI format.
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ def serialize(config: Config, skip_defaults=True) -> configparser.ConfigParser:
|
||||||
|
|
||||||
|
|
||||||
# FIXME: we should have distinct Config and ConfigFile types
|
# FIXME: we should have distinct Config and ConfigFile types
|
||||||
def save(output: Path, config: Config):
|
def save(output: Path, config: Config) -> None:
|
||||||
"""Save the config object to the specified path.
|
"""Save the config object to the specified path.
|
||||||
|
|
||||||
IMPORTANT: The global config (available via get_context().config)
|
IMPORTANT: The global config (available via get_context().config)
|
||||||
|
|
|
@ -210,7 +210,7 @@ def ask_for_ui(deviceinfo: Deviceinfo) -> str:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def ask_for_ui_extras(config: Config, ui):
|
def ask_for_ui_extras(config: Config, ui: str) -> bool:
|
||||||
apkbuild = pmb.helpers.pmaports.get(
|
apkbuild = pmb.helpers.pmaports.get(
|
||||||
f"postmarketos-ui-{ui}", subpackages=False, must_exist=False
|
f"postmarketos-ui-{ui}", subpackages=False, must_exist=False
|
||||||
)
|
)
|
||||||
|
@ -226,7 +226,7 @@ def ask_for_ui_extras(config: Config, ui):
|
||||||
return pmb.helpers.cli.confirm("Enable this package?", default=config.ui_extras)
|
return pmb.helpers.cli.confirm("Enable this package?", default=config.ui_extras)
|
||||||
|
|
||||||
|
|
||||||
def ask_for_systemd(config: Config, ui):
|
def ask_for_systemd(config: Config, ui: str) -> SystemdConfig:
|
||||||
if "systemd" not in pmb.config.pmaports.read_config_repos():
|
if "systemd" not in pmb.config.pmaports.read_config_repos():
|
||||||
return config.systemd
|
return config.systemd
|
||||||
|
|
||||||
|
@ -292,7 +292,7 @@ def ask_for_timezone() -> str:
|
||||||
return "GMT"
|
return "GMT"
|
||||||
|
|
||||||
|
|
||||||
def ask_for_provider_select(apkbuild, providers_cfg) -> None:
|
def ask_for_provider_select(apkbuild: dict[str, Any], providers_cfg: dict[str, str]) -> None:
|
||||||
"""Ask for selectable providers that are specified using "_pmb_select" in a APKBUILD.
|
"""Ask for selectable providers that are specified using "_pmb_select" in a APKBUILD.
|
||||||
|
|
||||||
:param apkbuild: the APKBUILD with the _pmb_select
|
:param apkbuild: the APKBUILD with the _pmb_select
|
||||||
|
|
|
@ -8,7 +8,7 @@ from pmb.meta import Cache
|
||||||
|
|
||||||
|
|
||||||
@Cache()
|
@Cache()
|
||||||
def is_systemd_selected(config: Config):
|
def is_systemd_selected(config: Config) -> bool:
|
||||||
if "systemd" not in pmb.config.pmaports.read_config_repos():
|
if "systemd" not in pmb.config.pmaports.read_config_repos():
|
||||||
return False
|
return False
|
||||||
if pmb.helpers.ui.check_option(config.ui, "pmb:systemd-never", skip_extra_repos=True):
|
if pmb.helpers.ui.check_option(config.ui, "pmb:systemd-never", skip_extra_repos=True):
|
||||||
|
@ -20,7 +20,7 @@ def is_systemd_selected(config: Config):
|
||||||
return pmb.helpers.ui.check_option(config.ui, "pmb:systemd", skip_extra_repos=True)
|
return pmb.helpers.ui.check_option(config.ui, "pmb:systemd", skip_extra_repos=True)
|
||||||
|
|
||||||
|
|
||||||
def systemd_selected_str(config: Config):
|
def systemd_selected_str(config: Config) -> tuple[str, str]:
|
||||||
if "systemd" not in pmb.config.pmaports.read_config_repos():
|
if "systemd" not in pmb.config.pmaports.read_config_repos():
|
||||||
return "no", "not supported by pmaports branch"
|
return "no", "not supported by pmaports branch"
|
||||||
if pmb.helpers.ui.check_option(config.ui, "pmb:systemd-never"):
|
if pmb.helpers.ui.check_option(config.ui, "pmb:systemd-never"):
|
||||||
|
|
|
@ -6,6 +6,7 @@ from pmb.core.pkgrepo import pkgrepo_default_path, pkgrepo_paths, pkgrepo_relati
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from typing import cast, Any
|
||||||
|
|
||||||
import pmb.config
|
import pmb.config
|
||||||
from pmb.meta import Cache
|
from pmb.meta import Cache
|
||||||
|
@ -14,7 +15,7 @@ import pmb.helpers.pmaports
|
||||||
import pmb.parse.version
|
import pmb.parse.version
|
||||||
|
|
||||||
|
|
||||||
def clone():
|
def clone() -> None:
|
||||||
logging.info(
|
logging.info(
|
||||||
"Setting up the native chroot and cloning the package build" " recipes (pmaports)..."
|
"Setting up the native chroot and cloning the package build" " recipes (pmaports)..."
|
||||||
)
|
)
|
||||||
|
@ -23,7 +24,7 @@ def clone():
|
||||||
pmb.helpers.git.clone("pmaports")
|
pmb.helpers.git.clone("pmaports")
|
||||||
|
|
||||||
|
|
||||||
def check_version_pmaports(real):
|
def check_version_pmaports(real: str) -> None:
|
||||||
# Compare versions
|
# Compare versions
|
||||||
min = pmb.config.pmaports_min_version
|
min = pmb.config.pmaports_min_version
|
||||||
if pmb.parse.version.compare(real, min) >= 0:
|
if pmb.parse.version.compare(real, min) >= 0:
|
||||||
|
@ -41,7 +42,7 @@ def check_version_pmaports(real):
|
||||||
raise RuntimeError("Run 'pmbootstrap pull' to update your pmaports.")
|
raise RuntimeError("Run 'pmbootstrap pull' to update your pmaports.")
|
||||||
|
|
||||||
|
|
||||||
def check_version_pmbootstrap(min_ver):
|
def check_version_pmbootstrap(min_ver: str) -> None:
|
||||||
# Compare versions
|
# Compare versions
|
||||||
real = pmb.__version__
|
real = pmb.__version__
|
||||||
if pmb.parse.version.compare(real, min_ver) >= 0:
|
if pmb.parse.version.compare(real, min_ver) >= 0:
|
||||||
|
@ -71,7 +72,7 @@ def check_version_pmbootstrap(min_ver):
|
||||||
|
|
||||||
|
|
||||||
@Cache()
|
@Cache()
|
||||||
def read_config_repos():
|
def read_config_repos() -> dict[str, configparser.SectionProxy]:
|
||||||
"""Read the sections starting with "repo:" from pmaports.cfg."""
|
"""Read the sections starting with "repo:" from pmaports.cfg."""
|
||||||
|
|
||||||
cfg = configparser.ConfigParser()
|
cfg = configparser.ConfigParser()
|
||||||
|
@ -88,7 +89,7 @@ def read_config_repos():
|
||||||
|
|
||||||
|
|
||||||
@Cache("aports")
|
@Cache("aports")
|
||||||
def read_config(aports: Path | None = None):
|
def read_config(aports: Path | None = None) -> dict[str, Any]:
|
||||||
"""Read and verify pmaports.cfg. If aports is not
|
"""Read and verify pmaports.cfg. If aports is not
|
||||||
specified and systemd is enabled, the returned channel
|
specified and systemd is enabled, the returned channel
|
||||||
will be the systemd one (e.g. systemd-edge instead of edge)
|
will be the systemd one (e.g. systemd-edge instead of edge)
|
||||||
|
@ -128,7 +129,8 @@ def read_config(aports: Path | None = None):
|
||||||
if systemd:
|
if systemd:
|
||||||
ret["channel"] = "systemd-" + ret["channel"]
|
ret["channel"] = "systemd-" + ret["channel"]
|
||||||
|
|
||||||
return ret
|
# FIXME: This is a hack to work around python/typeshed issue #12919
|
||||||
|
return cast(dict[str, Any], ret)
|
||||||
|
|
||||||
|
|
||||||
def all_channels() -> list[str]:
|
def all_channels() -> list[str]:
|
||||||
|
@ -141,7 +143,7 @@ def all_channels() -> list[str]:
|
||||||
return list(ret)
|
return list(ret)
|
||||||
|
|
||||||
|
|
||||||
def read_config_channel():
|
def read_config_channel() -> dict[str, str]:
|
||||||
"""Get the properties of the currently active channel in pmaports.git.
|
"""Get the properties of the currently active channel in pmaports.git.
|
||||||
|
|
||||||
As specified in channels.cfg (https://postmarketos.org/channels.cfg).
|
As specified in channels.cfg (https://postmarketos.org/channels.cfg).
|
||||||
|
@ -180,13 +182,13 @@ def read_config_channel():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def init():
|
def init() -> None:
|
||||||
if not os.path.exists(pkgrepo_default_path()):
|
if not os.path.exists(pkgrepo_default_path()):
|
||||||
clone()
|
clone()
|
||||||
read_config()
|
read_config()
|
||||||
|
|
||||||
|
|
||||||
def switch_to_channel_branch(channel_new):
|
def switch_to_channel_branch(channel_new: str) -> bool:
|
||||||
"""Checkout the channel's branch in pmaports.git.
|
"""Checkout the channel's branch in pmaports.git.
|
||||||
|
|
||||||
:channel_new: channel name (e.g. "edge", "v21.03")
|
:channel_new: channel name (e.g. "edge", "v21.03")
|
||||||
|
@ -236,7 +238,7 @@ def switch_to_channel_branch(channel_new):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def install_githooks():
|
def install_githooks() -> None:
|
||||||
aports = pkgrepo_default_path()
|
aports = pkgrepo_default_path()
|
||||||
hooks_dir = aports / ".githooks"
|
hooks_dir = aports / ".githooks"
|
||||||
if not hooks_dir.exists():
|
if not hooks_dir.exists():
|
||||||
|
|
|
@ -17,7 +17,7 @@ from pmb.core.context import get_context
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
|
|
||||||
|
|
||||||
def chroot_save_init(suffix: Chroot):
|
def chroot_save_init(suffix: Chroot) -> None:
|
||||||
"""Save the chroot initialization data in $WORK/workdir.cfg."""
|
"""Save the chroot initialization data in $WORK/workdir.cfg."""
|
||||||
# Read existing cfg
|
# Read existing cfg
|
||||||
cfg = configparser.ConfigParser()
|
cfg = configparser.ConfigParser()
|
||||||
|
@ -48,7 +48,7 @@ def chroots_outdated() -> list[Chroot]: ...
|
||||||
def chroots_outdated(chroot: Chroot) -> bool: ...
|
def chroots_outdated(chroot: Chroot) -> bool: ...
|
||||||
|
|
||||||
|
|
||||||
def chroots_outdated(chroot: Chroot | None = None):
|
def chroots_outdated(chroot: Chroot | None = None) -> bool | list[Chroot]:
|
||||||
"""Check if init dates from workdir.cfg indicate that any chroot is
|
"""Check if init dates from workdir.cfg indicate that any chroot is
|
||||||
outdated.
|
outdated.
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ class Config:
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Invalid dotted key: {dotted_key}")
|
raise ValueError(f"Invalid dotted key: {dotted_key}")
|
||||||
|
|
||||||
def __setattr__(self, key: str, value: Any):
|
def __setattr__(self, key: str, value: Any) -> None:
|
||||||
"""Allow for setattr() to be used with a dotted key
|
"""Allow for setattr() to be used with a dotted key
|
||||||
to set nested dictionaries (e.g. "mirrors.alpine")."""
|
to set nested dictionaries (e.g. "mirrors.alpine")."""
|
||||||
keys = key.split(".")
|
keys = key.split(".")
|
||||||
|
|
|
@ -56,7 +56,7 @@ def get_context(allow_failure: bool = False) -> Context:
|
||||||
return __context
|
return __context
|
||||||
|
|
||||||
|
|
||||||
def set_context(context: Context):
|
def set_context(context: Context) -> None:
|
||||||
"""Set global runtime context."""
|
"""Set global runtime context."""
|
||||||
global __context
|
global __context
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from pmb.meta import Cache
|
||||||
|
|
||||||
|
|
||||||
@Cache(skip_extras=False)
|
@Cache(skip_extras=False)
|
||||||
def pkgrepo_paths(skip_extras=False) -> list[Path]:
|
def pkgrepo_paths(skip_extras: bool = False) -> list[Path]:
|
||||||
config = get_context().config
|
config = get_context().config
|
||||||
paths = list(map(lambda x: Path(x), config.aports))
|
paths = list(map(lambda x: Path(x), config.aports))
|
||||||
if not paths:
|
if not paths:
|
||||||
|
@ -32,7 +32,7 @@ def pkgrepo_default_path() -> Path:
|
||||||
return pkgrepo_paths(skip_extras=True)[0]
|
return pkgrepo_paths(skip_extras=True)[0]
|
||||||
|
|
||||||
|
|
||||||
def pkgrepo_names(skip_exras=False) -> list[str]:
|
def pkgrepo_names(skip_exras: bool = False) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Return a list of all the package repository names.
|
Return a list of all the package repository names.
|
||||||
"""
|
"""
|
||||||
|
@ -78,7 +78,7 @@ def pkgrepo_glob_one(path: str) -> Path | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def pkgrepo_iglob(path: str, recursive=False) -> Generator[Path, None, None]:
|
def pkgrepo_iglob(path: str, recursive: bool = False) -> Generator[Path, None, None]:
|
||||||
"""
|
"""
|
||||||
Yield each matching glob over each aports repository.
|
Yield each matching glob over each aports repository.
|
||||||
"""
|
"""
|
||||||
|
@ -91,7 +91,7 @@ def pkgrepo_iglob(path: str, recursive=False) -> Generator[Path, None, None]:
|
||||||
yield pdir
|
yield pdir
|
||||||
|
|
||||||
|
|
||||||
def pkgrepo_iter_package_dirs(skip_extra_repos=False) -> Generator[Path, None, None]:
|
def pkgrepo_iter_package_dirs(skip_extra_repos: bool = False) -> Generator[Path, None, None]:
|
||||||
"""
|
"""
|
||||||
Yield each matching glob over each aports repository.
|
Yield each matching glob over each aports repository.
|
||||||
Detect duplicates within the same aports repository but otherwise
|
Detect duplicates within the same aports repository but otherwise
|
||||||
|
|
|
@ -10,7 +10,7 @@ import pmb.export
|
||||||
from pmb.core import Chroot, ChrootType
|
from pmb.core import Chroot, ChrootType
|
||||||
|
|
||||||
|
|
||||||
def frontend(args: PmbArgs): # FIXME: ARGS_REFACTOR
|
def frontend(args: PmbArgs) -> None: # FIXME: ARGS_REFACTOR
|
||||||
config = get_context().config
|
config = get_context().config
|
||||||
# Create the export folder
|
# Create the export folder
|
||||||
target = args.export_folder
|
target = args.export_folder
|
||||||
|
|
|
@ -11,7 +11,7 @@ import pmb.helpers.file
|
||||||
from pmb.core import Chroot, ChrootType
|
from pmb.core import Chroot, ChrootType
|
||||||
|
|
||||||
|
|
||||||
def odin(device: str, flavor, folder: Path):
|
def odin(device: str, flavor: str, folder: Path) -> None:
|
||||||
"""
|
"""
|
||||||
Create Odin flashable tar file with kernel and initramfs
|
Create Odin flashable tar file with kernel and initramfs
|
||||||
for devices configured with the flasher method 'heimdall-isorec'
|
for devices configured with the flasher method 'heimdall-isorec'
|
||||||
|
|
|
@ -13,7 +13,7 @@ import pmb.helpers.file
|
||||||
from pmb.core import Chroot, ChrootType
|
from pmb.core import Chroot, ChrootType
|
||||||
|
|
||||||
|
|
||||||
def symlinks(flavor, folder: Path):
|
def symlinks(flavor: str, folder: Path) -> None:
|
||||||
"""
|
"""
|
||||||
Create convenience symlinks to the rootfs and boot files.
|
Create convenience symlinks to the rootfs and boot files.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -42,7 +42,7 @@ def install_depends(method: str) -> None:
|
||||||
pmb.chroot.apk.install(depends, Chroot.native())
|
pmb.chroot.apk.install(depends, Chroot.native())
|
||||||
|
|
||||||
|
|
||||||
def init(device: str, method: str):
|
def init(device: str, method: str) -> None:
|
||||||
install_depends(method)
|
install_depends(method)
|
||||||
|
|
||||||
# Mount folders from host system
|
# Mount folders from host system
|
||||||
|
|
|
@ -6,7 +6,7 @@ import pmb.chroot.initfs
|
||||||
import pmb.helpers.args
|
import pmb.helpers.args
|
||||||
|
|
||||||
|
|
||||||
def check_partition_blacklist(deviceinfo: Deviceinfo, key, value):
|
def check_partition_blacklist(deviceinfo: Deviceinfo, key: str, value: str) -> None:
|
||||||
if not key.startswith("$PARTITION_"):
|
if not key.startswith("$PARTITION_"):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ def variables(
|
||||||
no_reboot: bool | None,
|
no_reboot: bool | None,
|
||||||
partition: str | None,
|
partition: str | None,
|
||||||
resume: bool | None,
|
resume: bool | None,
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str | None]:
|
||||||
device = get_context().config.device
|
device = get_context().config.device
|
||||||
deviceinfo = pmb.parse.deviceinfo()
|
deviceinfo = pmb.parse.deviceinfo()
|
||||||
_cmdline = deviceinfo.kernel_cmdline or ""
|
_cmdline = deviceinfo.kernel_cmdline or ""
|
||||||
|
|
|
@ -66,7 +66,7 @@ def _compute_progress(line):
|
||||||
return cur / tot if tot > 0 else 0
|
return cur / tot if tot > 0 else 0
|
||||||
|
|
||||||
|
|
||||||
def apk_with_progress(command: Sequence[PathString], chroot: Chroot | None = None):
|
def apk_with_progress(command: Sequence[PathString], chroot: Chroot | None = None) -> None:
|
||||||
"""Run an apk subcommand while printing a progress bar to STDOUT.
|
"""Run an apk subcommand while printing a progress bar to STDOUT.
|
||||||
|
|
||||||
:param command: apk subcommand in list form
|
:param command: apk subcommand in list form
|
||||||
|
@ -86,7 +86,10 @@ def apk_with_progress(command: Sequence[PathString], chroot: Chroot | None = Non
|
||||||
with pmb.helpers.run.root(["cat", fifo], output="pipe") as p_cat:
|
with pmb.helpers.run.root(["cat", fifo], output="pipe") as p_cat:
|
||||||
with pmb.helpers.run.root(command_with_progress, output="background") as p_apk:
|
with pmb.helpers.run.root(command_with_progress, output="background") as p_apk:
|
||||||
while p_apk.poll() is None:
|
while p_apk.poll() is None:
|
||||||
line = p_cat.stdout.readline().decode("utf-8")
|
p_cat_stdout = p_cat.stdout
|
||||||
|
if p_cat_stdout is None:
|
||||||
|
raise RuntimeError("cat process had no stdout?")
|
||||||
|
line = p_cat_stdout.readline().decode("utf-8")
|
||||||
progress = _compute_progress(line)
|
progress = _compute_progress(line)
|
||||||
pmb.helpers.cli.progress_print(progress)
|
pmb.helpers.cli.progress_print(progress)
|
||||||
pmb.helpers.cli.progress_flush()
|
pmb.helpers.cli.progress_flush()
|
||||||
|
|
|
@ -6,12 +6,19 @@ from pmb.helpers import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
from pmb.types import PmbArgs
|
from pmb.types import Apkbuild, PmbArgs
|
||||||
import pmb.helpers.file
|
import pmb.helpers.file
|
||||||
import pmb.helpers.http
|
import pmb.helpers.http
|
||||||
import pmb.helpers.pmaports
|
import pmb.helpers.pmaports
|
||||||
|
|
||||||
|
|
||||||
|
class PackageVersionInfo(TypedDict):
|
||||||
|
sha: str
|
||||||
|
date: datetime.datetime
|
||||||
|
|
||||||
|
|
||||||
req_headers: dict[str, str] = {}
|
req_headers: dict[str, str] = {}
|
||||||
req_headers_github: dict[str, str] = {}
|
req_headers_github: dict[str, str] = {}
|
||||||
|
|
||||||
|
@ -47,7 +54,7 @@ def init_req_headers() -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_package_version_info_github(repo_name: str, ref: str | None):
|
def get_package_version_info_github(repo_name: str, ref: str | None) -> PackageVersionInfo:
|
||||||
logging.debug(f"Trying GitHub repository: {repo_name}")
|
logging.debug(f"Trying GitHub repository: {repo_name}")
|
||||||
|
|
||||||
# Get the URL argument to request a special ref, if needed
|
# Get the URL argument to request a special ref, if needed
|
||||||
|
@ -63,13 +70,15 @@ def get_package_version_info_github(repo_name: str, ref: str | None):
|
||||||
commit_date = latest_commit["commit"]["committer"]["date"]
|
commit_date = latest_commit["commit"]["committer"]["date"]
|
||||||
# Extract the time from the field
|
# Extract the time from the field
|
||||||
date = datetime.datetime.strptime(commit_date, "%Y-%m-%dT%H:%M:%SZ")
|
date = datetime.datetime.strptime(commit_date, "%Y-%m-%dT%H:%M:%SZ")
|
||||||
return {
|
return PackageVersionInfo(
|
||||||
"sha": latest_commit["sha"],
|
sha=latest_commit["sha"],
|
||||||
"date": date,
|
date=date,
|
||||||
}
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_package_version_info_gitlab(gitlab_host: str, repo_name: str, ref: str | None):
|
def get_package_version_info_gitlab(
|
||||||
|
gitlab_host: str, repo_name: str, ref: str | None
|
||||||
|
) -> PackageVersionInfo:
|
||||||
logging.debug(f"Trying GitLab repository: {repo_name}")
|
logging.debug(f"Trying GitLab repository: {repo_name}")
|
||||||
|
|
||||||
repo_name_safe = urllib.parse.quote(repo_name, safe="")
|
repo_name_safe = urllib.parse.quote(repo_name, safe="")
|
||||||
|
@ -89,13 +98,13 @@ def get_package_version_info_gitlab(gitlab_host: str, repo_name: str, ref: str |
|
||||||
# Extract the time from the field
|
# Extract the time from the field
|
||||||
# 2019-10-14T09:32:00.000Z / 2019-12-27T07:58:53.000-05:00
|
# 2019-10-14T09:32:00.000Z / 2019-12-27T07:58:53.000-05:00
|
||||||
date = datetime.datetime.strptime(commit_date, "%Y-%m-%dT%H:%M:%S.000%z")
|
date = datetime.datetime.strptime(commit_date, "%Y-%m-%dT%H:%M:%S.000%z")
|
||||||
return {
|
return PackageVersionInfo(
|
||||||
"sha": latest_commit["id"],
|
sha=latest_commit["id"],
|
||||||
"date": date,
|
date=date,
|
||||||
}
|
)
|
||||||
|
|
||||||
|
|
||||||
def upgrade_git_package(args: PmbArgs, pkgname: str, package) -> None:
|
def upgrade_git_package(args: PmbArgs, pkgname: str, package: Apkbuild) -> None:
|
||||||
"""Update _commit/pkgver/pkgrel in a git-APKBUILD (or pretend to do it if args.dry is set).
|
"""Update _commit/pkgver/pkgrel in a git-APKBUILD (or pretend to do it if args.dry is set).
|
||||||
|
|
||||||
:param pkgname: the package name
|
:param pkgname: the package name
|
||||||
|
@ -169,7 +178,7 @@ def upgrade_git_package(args: PmbArgs, pkgname: str, package) -> None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def upgrade_stable_package(args: PmbArgs, pkgname: str, package) -> None:
|
def upgrade_stable_package(args: PmbArgs, pkgname: str, package: Apkbuild) -> None:
|
||||||
"""
|
"""
|
||||||
Update _commit/pkgver/pkgrel in an APKBUILD (or pretend to do it if
|
Update _commit/pkgver/pkgrel in an APKBUILD (or pretend to do it if
|
||||||
args.dry is set).
|
args.dry is set).
|
||||||
|
@ -254,7 +263,7 @@ def upgrade_stable_package(args: PmbArgs, pkgname: str, package) -> None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def upgrade(args: PmbArgs, pkgname, git=True, stable=True) -> None:
|
def upgrade(args: PmbArgs, pkgname: str, git: bool = True, stable: bool = True) -> None:
|
||||||
"""Find new versions of a single package and upgrade it.
|
"""Find new versions of a single package and upgrade it.
|
||||||
|
|
||||||
:param pkgname: the name of the package
|
:param pkgname: the name of the package
|
||||||
|
|
|
@ -5,7 +5,7 @@ from pathlib import Path
|
||||||
from pmb.core.pkgrepo import pkgrepo_glob_one, pkgrepo_iglob
|
from pmb.core.pkgrepo import pkgrepo_glob_one, pkgrepo_iglob
|
||||||
|
|
||||||
|
|
||||||
def find_path(codename: str, file="") -> Path | None:
|
def find_path(codename: str, file: str = "") -> Path | None:
|
||||||
"""Find path to device APKBUILD under `device/*/device-`.
|
"""Find path to device APKBUILD under `device/*/device-`.
|
||||||
|
|
||||||
:param codename: device codename
|
:param codename: device codename
|
||||||
|
@ -36,7 +36,7 @@ def list_codenames(vendor=None, archived=True):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def list_vendors():
|
def list_vendors() -> set[str]:
|
||||||
"""Get all device vendors, for which aports are available.
|
"""Get all device vendors, for which aports are available.
|
||||||
|
|
||||||
:returns: {"vendor1", "vendor2", ...}
|
:returns: {"vendor1", "vendor2", ...}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import pmb.helpers.run
|
||||||
import pmb.helpers.pmaports
|
import pmb.helpers.pmaports
|
||||||
|
|
||||||
|
|
||||||
def replace(path: Path, old: str, new: str):
|
def replace(path: Path, old: str, new: str) -> None:
|
||||||
text = ""
|
text = ""
|
||||||
with path.open("r", encoding="utf-8") as handle:
|
with path.open("r", encoding="utf-8") as handle:
|
||||||
text = handle.read()
|
text = handle.read()
|
||||||
|
@ -21,7 +21,9 @@ def replace(path: Path, old: str, new: str):
|
||||||
handle.write(text)
|
handle.write(text)
|
||||||
|
|
||||||
|
|
||||||
def replace_apkbuild(args: PmbArgs, pkgname, key, new, in_quotes=False):
|
def replace_apkbuild(
|
||||||
|
args: PmbArgs, pkgname: str, key: str, new: int | str, in_quotes: bool = False
|
||||||
|
) -> None:
|
||||||
"""Replace one key=value line in an APKBUILD and verify it afterwards.
|
"""Replace one key=value line in an APKBUILD and verify it afterwards.
|
||||||
|
|
||||||
:param pkgname: package name, e.g. "hello-world"
|
:param pkgname: package name, e.g. "hello-world"
|
||||||
|
@ -90,7 +92,7 @@ def is_older_than(path, seconds):
|
||||||
return lastmod + seconds < time.time()
|
return lastmod + seconds < time.time()
|
||||||
|
|
||||||
|
|
||||||
def symlink(file: Path, link: Path):
|
def symlink(file: Path, link: Path) -> None:
|
||||||
"""Check if the symlink is already present, otherwise create it."""
|
"""Check if the symlink is already present, otherwise create it."""
|
||||||
if os.path.exists(link):
|
if os.path.exists(link):
|
||||||
if os.path.islink(link) and os.path.realpath(os.readlink(link)) == os.path.realpath(file):
|
if os.path.islink(link) and os.path.realpath(os.readlink(link)) == os.path.realpath(file):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from pmb.helpers import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, NoReturn
|
from typing import cast, Any, NoReturn
|
||||||
|
|
||||||
import pmb.aportgen
|
import pmb.aportgen
|
||||||
import pmb.build
|
import pmb.build
|
||||||
|
@ -19,7 +19,7 @@ import pmb.chroot.other
|
||||||
import pmb.ci
|
import pmb.ci
|
||||||
import pmb.config
|
import pmb.config
|
||||||
from pmb.core import Config
|
from pmb.core import Config
|
||||||
from pmb.types import PmbArgs
|
from pmb.types import Env, PmbArgs, RunOutputType
|
||||||
import pmb.export
|
import pmb.export
|
||||||
import pmb.flasher
|
import pmb.flasher
|
||||||
import pmb.helpers.aportupgrade
|
import pmb.helpers.aportupgrade
|
||||||
|
@ -43,7 +43,7 @@ from pmb.core import ChrootType, Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def _parse_flavor(device: str, autoinstall=True) -> str:
|
def _parse_flavor(device: str, autoinstall: bool = True) -> str:
|
||||||
"""Verify the flavor argument if specified, or return a default value.
|
"""Verify the flavor argument if specified, or return a default value.
|
||||||
|
|
||||||
:param autoinstall: make sure that at least one kernel flavor is installed
|
:param autoinstall: make sure that at least one kernel flavor is installed
|
||||||
|
@ -189,10 +189,13 @@ def chroot(args: PmbArgs) -> None:
|
||||||
pmb.chroot.init(chroot)
|
pmb.chroot.init(chroot)
|
||||||
|
|
||||||
# Xauthority
|
# Xauthority
|
||||||
env = {}
|
env: Env = {}
|
||||||
if args.xauth:
|
if args.xauth:
|
||||||
pmb.chroot.other.copy_xauthority(chroot)
|
pmb.chroot.other.copy_xauthority(chroot)
|
||||||
env["DISPLAY"] = os.environ.get("DISPLAY")
|
x11_display = os.environ.get("DISPLAY")
|
||||||
|
if x11_display is None:
|
||||||
|
raise AssertionError("$DISPLAY was unset despite that it should be set at this point")
|
||||||
|
env["DISPLAY"] = x11_display
|
||||||
env["XAUTHORITY"] = "/home/pmos/.Xauthority"
|
env["XAUTHORITY"] = "/home/pmos/.Xauthority"
|
||||||
|
|
||||||
# Install blockdevice
|
# Install blockdevice
|
||||||
|
@ -210,13 +213,16 @@ def chroot(args: PmbArgs) -> None:
|
||||||
|
|
||||||
pmb.chroot.apk.update_repository_list(chroot, user_repository=True)
|
pmb.chroot.apk.update_repository_list(chroot, user_repository=True)
|
||||||
|
|
||||||
|
# TODO: Maybe this could be done better.
|
||||||
|
output_type = cast(RunOutputType, args.output)
|
||||||
|
|
||||||
# Run the command as user/root
|
# Run the command as user/root
|
||||||
if user:
|
if user:
|
||||||
logging.info(f"({chroot}) % su pmos -c '" + " ".join(args.command) + "'")
|
logging.info(f"({chroot}) % su pmos -c '" + " ".join(args.command) + "'")
|
||||||
pmb.chroot.user(args.command, chroot, output=args.output, env=env)
|
pmb.chroot.user(args.command, chroot, output=output_type, env=env)
|
||||||
else:
|
else:
|
||||||
logging.info(f"({chroot}) % " + " ".join(args.command))
|
logging.info(f"({chroot}) % " + " ".join(args.command))
|
||||||
pmb.chroot.root(args.command, chroot, output=args.output, env=env)
|
pmb.chroot.root(args.command, chroot, output=output_type, env=env)
|
||||||
|
|
||||||
|
|
||||||
def config(args: PmbArgs) -> None:
|
def config(args: PmbArgs) -> None:
|
||||||
|
|
|
@ -65,7 +65,7 @@ def clone(name_repo: str) -> None:
|
||||||
open(fetch_head, "w").close()
|
open(fetch_head, "w").close()
|
||||||
|
|
||||||
|
|
||||||
def rev_parse(path: Path, revision="HEAD", extra_args: list = []) -> str:
|
def rev_parse(path: Path, revision: str = "HEAD", extra_args: list = []) -> str:
|
||||||
"""Run "git rev-parse" in a specific repository dir.
|
"""Run "git rev-parse" in a specific repository dir.
|
||||||
|
|
||||||
:param path: to the git repository
|
:param path: to the git repository
|
||||||
|
@ -79,7 +79,7 @@ def rev_parse(path: Path, revision="HEAD", extra_args: list = []) -> str:
|
||||||
return rev.rstrip()
|
return rev.rstrip()
|
||||||
|
|
||||||
|
|
||||||
def can_fast_forward(path, branch_upstream, branch="HEAD") -> bool:
|
def can_fast_forward(path: Path, branch_upstream: str, branch: str = "HEAD") -> bool:
|
||||||
command = ["git", "merge-base", "--is-ancestor", branch, branch_upstream]
|
command = ["git", "merge-base", "--is-ancestor", branch, branch_upstream]
|
||||||
ret = pmb.helpers.run.user(command, path, check=False)
|
ret = pmb.helpers.run.user(command, path, check=False)
|
||||||
if ret == 0:
|
if ret == 0:
|
||||||
|
@ -244,7 +244,7 @@ def parse_channels_cfg(aports: Path) -> dict:
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def branch_looks_official(repo: Path, branch) -> bool:
|
def branch_looks_official(repo: Path, branch: str) -> bool:
|
||||||
"""Check if a given branch follows the patterns of official branches in
|
"""Check if a given branch follows the patterns of official branches in
|
||||||
pmaports or aports.
|
pmaports or aports.
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ def get_topdir(repo: Path) -> Path:
|
||||||
return Path(res.strip())
|
return Path(res.strip())
|
||||||
|
|
||||||
|
|
||||||
def get_files(repo: Path):
|
def get_files(repo: Path) -> list[str]:
|
||||||
"""Get all files inside a git repository, that are either already in the git tree or are not in gitignore.
|
"""Get all files inside a git repository, that are either already in the git tree or are not in gitignore.
|
||||||
|
|
||||||
Do not list deleted files. To be used for creating a tarball of the git repository.
|
Do not list deleted files. To be used for creating a tarball of the git repository.
|
||||||
|
|
|
@ -45,7 +45,7 @@ def get_custom_valid_options() -> list[str]:
|
||||||
# FIXME: dest_paths[repo], repo expected to be a Literal.
|
# FIXME: dest_paths[repo], repo expected to be a Literal.
|
||||||
# We should really make Config.mirrors not a TypedDict.
|
# We should really make Config.mirrors not a TypedDict.
|
||||||
# mypy: disable-error-code="index"
|
# mypy: disable-error-code="index"
|
||||||
def check(pkgnames: Sequence[str]):
|
def check(pkgnames: Sequence[str]) -> None:
|
||||||
"""Run apkbuild-lint on the supplied packages.
|
"""Run apkbuild-lint on the supplied packages.
|
||||||
|
|
||||||
:param pkgnames: Names of the packages to lint
|
:param pkgnames: Names of the packages to lint
|
||||||
|
|
|
@ -4,7 +4,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sys
|
import sys
|
||||||
from typing import Final, TextIO
|
from typing import Any, Final, TextIO
|
||||||
import pmb.config
|
import pmb.config
|
||||||
from pmb.meta import Cache
|
from pmb.meta import Cache
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ VERBOSE: Final[int] = 5
|
||||||
class log_handler(logging.StreamHandler):
|
class log_handler(logging.StreamHandler):
|
||||||
"""Write to stdout and to the already opened log file."""
|
"""Write to stdout and to the already opened log file."""
|
||||||
|
|
||||||
def __init__(self, details_to_stdout: bool = False, quiet: bool = False):
|
def __init__(self, details_to_stdout: bool = False, quiet: bool = False) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.details_to_stdout = details_to_stdout
|
self.details_to_stdout = details_to_stdout
|
||||||
self.quiet = False
|
self.quiet = False
|
||||||
|
@ -90,7 +90,7 @@ class log_handler(logging.StreamHandler):
|
||||||
self.handleError(record)
|
self.handleError(record)
|
||||||
|
|
||||||
|
|
||||||
def add_verbose_log_level():
|
def add_verbose_log_level() -> None:
|
||||||
"""Add a new log level "verbose", which is below "debug".
|
"""Add a new log level "verbose", which is below "debug".
|
||||||
|
|
||||||
Also monkeypatch logging, so it can be used with logging.verbose().
|
Also monkeypatch logging, so it can be used with logging.verbose().
|
||||||
|
@ -112,7 +112,7 @@ def add_verbose_log_level():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def init(logfile: Path, verbose: bool, details_to_stdout: bool = False):
|
def init(logfile: Path, verbose: bool, details_to_stdout: bool = False) -> None:
|
||||||
"""Set log format and add the log file descriptor to logfd, add the verbose log level."""
|
"""Set log format and add the log file descriptor to logfd, add the verbose log level."""
|
||||||
global logfd
|
global logfd
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ def init(logfile: Path, verbose: bool, details_to_stdout: bool = False):
|
||||||
logging.debug(f"$ pmbootstrap {' '.join(sys.argv)}")
|
logging.debug(f"$ pmbootstrap {' '.join(sys.argv)}")
|
||||||
|
|
||||||
|
|
||||||
def disable():
|
def disable() -> None:
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.disabled = True
|
logger.disabled = True
|
||||||
|
|
||||||
|
@ -162,38 +162,38 @@ def disable():
|
||||||
# by not calling the (undefined) logging.verbose() function.
|
# by not calling the (undefined) logging.verbose() function.
|
||||||
|
|
||||||
|
|
||||||
def critical(msg: object, *args, **kwargs):
|
def critical(msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.critical(msg, *args, **kwargs)
|
logging.critical(msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def fatal(msg: object, *args, **kwargs):
|
def fatal(msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.fatal(msg, *args, **kwargs)
|
logging.fatal(msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def error(msg: object, *args, **kwargs):
|
def error(msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.error(msg, *args, **kwargs)
|
logging.error(msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def warning(msg: object, *args, **kwargs):
|
def warning(msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.warning(msg, *args, **kwargs)
|
logging.warning(msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@Cache("msg")
|
@Cache("msg")
|
||||||
def warn_once(msg: str):
|
def warn_once(msg: str) -> None:
|
||||||
logging.warning(msg)
|
logging.warning(msg)
|
||||||
|
|
||||||
|
|
||||||
def info(msg: object, *args, **kwargs):
|
def info(msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.info(msg, *args, **kwargs)
|
logging.info(msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def debug(msg: object, *args, **kwargs):
|
def debug(msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.debug(msg, *args, **kwargs)
|
logging.debug(msg, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def verbose(msg: object, *args, **kwargs):
|
def verbose(msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.verbose(msg, *args, **kwargs) # type: ignore[attr-defined]
|
logging.verbose(msg, *args, **kwargs) # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
|
||||||
def log(level: int, msg: object, *args, **kwargs):
|
def log(level: int, msg: object, *args: str, **kwargs: Any) -> None:
|
||||||
logging.log(level, msg, *args, **kwargs)
|
logging.log(level, msg, *args, **kwargs)
|
||||||
|
|
|
@ -4,6 +4,7 @@ import os
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path, PurePath
|
||||||
import pmb.helpers
|
import pmb.helpers
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
from pmb.types import PathString
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ def ismount(folder: Path) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def bind(
|
def bind(
|
||||||
source: Path, destination: Path, create_folders: bool = True, umount: bool = False
|
source: PathString, destination: Path, create_folders: bool = True, umount: bool = False
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Mount --bind a folder and create necessary directory structure.
|
"""Mount --bind a folder and create necessary directory structure.
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ from typing import Any
|
||||||
from pmb.helpers.exceptions import NonBugError
|
from pmb.helpers.exceptions import NonBugError
|
||||||
|
|
||||||
|
|
||||||
def folder_size(path: Path):
|
def folder_size(path: Path) -> int:
|
||||||
"""Run `du` to calculate the size of a folder.
|
"""Run `du` to calculate the size of a folder.
|
||||||
|
|
||||||
(this is less code and faster than doing the same task in pure Python)
|
(this is less code and faster than doing the same task in pure Python)
|
||||||
|
@ -32,7 +32,7 @@ def folder_size(path: Path):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def check_grsec():
|
def check_grsec() -> None:
|
||||||
"""Check if the current kernel is based on the grsec patchset.
|
"""Check if the current kernel is based on the grsec patchset.
|
||||||
|
|
||||||
Also check if the chroot_deny_chmod option is enabled.
|
Also check if the chroot_deny_chmod option is enabled.
|
||||||
|
@ -47,7 +47,7 @@ def check_grsec():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def check_binfmt_misc():
|
def check_binfmt_misc() -> None:
|
||||||
"""Check if the 'binfmt_misc' module is loaded.
|
"""Check if the 'binfmt_misc' module is loaded.
|
||||||
|
|
||||||
This is done by checking, if /proc/sys/fs/binfmt_misc/ exists.
|
This is done by checking, if /proc/sys/fs/binfmt_misc/ exists.
|
||||||
|
@ -72,13 +72,13 @@ def check_binfmt_misc():
|
||||||
raise RuntimeError(f"Failed to set up binfmt_misc, see: {link}")
|
raise RuntimeError(f"Failed to set up binfmt_misc, see: {link}")
|
||||||
|
|
||||||
|
|
||||||
def migrate_success(work: Path, version):
|
def migrate_success(work: Path, version: int) -> None:
|
||||||
logging.info("Migration to version " + str(version) + " done")
|
logging.info("Migration to version " + str(version) + " done")
|
||||||
with open(work / "version", "w") as handle:
|
with open(work / "version", "w") as handle:
|
||||||
handle.write(str(version) + "\n")
|
handle.write(str(version) + "\n")
|
||||||
|
|
||||||
|
|
||||||
def migrate_work_folder():
|
def migrate_work_folder() -> None:
|
||||||
# Read current version
|
# Read current version
|
||||||
context = get_context()
|
context = get_context()
|
||||||
current = 0
|
current = 0
|
||||||
|
@ -182,7 +182,7 @@ def normalize_hostname(hostname: str) -> str:
|
||||||
return hostname
|
return hostname
|
||||||
|
|
||||||
|
|
||||||
def validate_hostname(hostname):
|
def validate_hostname(hostname: str) -> bool:
|
||||||
"""Check whether the string is a valid hostname.
|
"""Check whether the string is a valid hostname.
|
||||||
|
|
||||||
Check is performed according to
|
Check is performed according to
|
||||||
|
|
|
@ -20,7 +20,7 @@ class BumpType(Enum):
|
||||||
|
|
||||||
|
|
||||||
def package(
|
def package(
|
||||||
pkgname: str, reason="", dry: bool = False, bump_type: BumpType = BumpType.PKGREL
|
pkgname: str, reason: str = "", dry: bool = False, bump_type: BumpType = BumpType.PKGREL
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Increase the pkgrel or pkgver in the APKBUILD of a specific package.
|
"""Increase the pkgrel or pkgver in the APKBUILD of a specific package.
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ from pmb.meta import Cache
|
||||||
import pmb.parse
|
import pmb.parse
|
||||||
|
|
||||||
|
|
||||||
def _find_apkbuilds(skip_extra_repos=False) -> dict[str, Path]:
|
def _find_apkbuilds(skip_extra_repos: bool = False) -> dict[str, Path]:
|
||||||
# Try to get a cached result first (we assume that the aports don't change
|
# Try to get a cached result first (we assume that the aports don't change
|
||||||
# in one pmbootstrap call)
|
# in one pmbootstrap call)
|
||||||
apkbuilds = pmb.helpers.other.cache.get("pmb.helpers.pmaports.apkbuilds")
|
apkbuilds = pmb.helpers.other.cache.get("pmb.helpers.pmaports.apkbuilds")
|
||||||
|
@ -50,7 +50,7 @@ def get_list() -> list[str]:
|
||||||
return list(_find_apkbuilds().keys())
|
return list(_find_apkbuilds().keys())
|
||||||
|
|
||||||
|
|
||||||
def guess_main_dev(subpkgname) -> Path | None:
|
def guess_main_dev(subpkgname: str) -> Path | None:
|
||||||
"""Check if a package without "-dev" at the end exists in pmaports or not, and log the appropriate message.
|
"""Check if a package without "-dev" at the end exists in pmaports or not, and log the appropriate message.
|
||||||
|
|
||||||
Don't call this function directly, use guess_main() instead.
|
Don't call this function directly, use guess_main() instead.
|
||||||
|
@ -76,7 +76,7 @@ def guess_main_dev(subpkgname) -> Path | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def guess_main(subpkgname) -> Path | None:
|
def guess_main(subpkgname: str) -> Path | None:
|
||||||
"""Find the main package by assuming it is a prefix of the subpkgname.
|
"""Find the main package by assuming it is a prefix of the subpkgname.
|
||||||
|
|
||||||
We do that, because in some APKBUILDs the subpkgname="" variable gets
|
We do that, because in some APKBUILDs the subpkgname="" variable gets
|
||||||
|
@ -243,7 +243,9 @@ def get_with_path(
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
def get(pkgname, must_exist=True, subpackages=True, skip_extra_repos=False) -> dict[str, Any]:
|
def get(
|
||||||
|
pkgname: str, must_exist: bool = True, subpackages: bool = True, skip_extra_repos: bool = False
|
||||||
|
) -> dict[str, Any]:
|
||||||
return get_with_path(pkgname, must_exist, subpackages, skip_extra_repos)[1]
|
return get_with_path(pkgname, must_exist, subpackages, skip_extra_repos)[1]
|
||||||
|
|
||||||
|
|
||||||
|
@ -273,7 +275,7 @@ def find_providers(provide: str, default: list[str]) -> list[tuple[Any, Any]]:
|
||||||
return sorted(providers.items(), reverse=True, key=lambda p: p[1].get("provider_priority", 0))
|
return sorted(providers.items(), reverse=True, key=lambda p: p[1].get("provider_priority", 0))
|
||||||
|
|
||||||
|
|
||||||
def get_repo(pkgname) -> str | None:
|
def get_repo(pkgname: str) -> str | None:
|
||||||
"""Get the repository folder of an aport.
|
"""Get the repository folder of an aport.
|
||||||
|
|
||||||
:pkgname: package name
|
:pkgname: package name
|
||||||
|
@ -289,7 +291,7 @@ def get_repo(pkgname) -> str | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def check_arches(arches, arch: Arch):
|
def check_arches(arches: list[str], arch: Arch) -> bool:
|
||||||
"""Check if building for a certain arch is allowed.
|
"""Check if building for a certain arch is allowed.
|
||||||
|
|
||||||
:param arches: list of all supported arches, as it can be found in the
|
:param arches: list of all supported arches, as it can be found in the
|
||||||
|
|
|
@ -54,7 +54,7 @@ def apkindex_hash(url: str, length: int = 8) -> Path:
|
||||||
# FIXME: make config.mirrors a normal dict
|
# FIXME: make config.mirrors a normal dict
|
||||||
# mypy: disable-error-code="literal-required"
|
# mypy: disable-error-code="literal-required"
|
||||||
@Cache("user_repository", "mirrors_exclude")
|
@Cache("user_repository", "mirrors_exclude")
|
||||||
def urls(user_repository=False, mirrors_exclude: list[str] = []):
|
def urls(user_repository: bool = False, mirrors_exclude: list[str] = []) -> list[str]:
|
||||||
"""Get a list of repository URLs, as they are in /etc/apk/repositories.
|
"""Get a list of repository URLs, as they are in /etc/apk/repositories.
|
||||||
|
|
||||||
:param user_repository: add /mnt/pmbootstrap/packages
|
:param user_repository: add /mnt/pmbootstrap/packages
|
||||||
|
@ -118,7 +118,7 @@ def urls(user_repository=False, mirrors_exclude: list[str] = []):
|
||||||
|
|
||||||
|
|
||||||
def apkindex_files(
|
def apkindex_files(
|
||||||
arch: Arch | None = None, user_repository=True, exclude_mirrors: list[str] = []
|
arch: Arch | None = None, user_repository: bool = True, exclude_mirrors: list[str] = []
|
||||||
) -> list[Path]:
|
) -> list[Path]:
|
||||||
"""Get a list of outside paths to all resolved APKINDEX.tar.gz files for a specific arch.
|
"""Get a list of outside paths to all resolved APKINDEX.tar.gz files for a specific arch.
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ def apkindex_files(
|
||||||
|
|
||||||
|
|
||||||
@Cache("arch", force=False)
|
@Cache("arch", force=False)
|
||||||
def update(arch: Arch | None = None, force=False, existing_only=False):
|
def update(arch: Arch | None = None, force: bool = False, existing_only: bool = False) -> bool:
|
||||||
"""Download the APKINDEX files for all URLs depending on the architectures.
|
"""Download the APKINDEX files for all URLs depending on the architectures.
|
||||||
|
|
||||||
:param arch: * one Alpine architecture name ("x86_64", "armhf", ...)
|
:param arch: * one Alpine architecture name ("x86_64", "armhf", ...)
|
||||||
|
@ -223,7 +223,7 @@ def update(arch: Arch | None = None, force=False, existing_only=False):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def alpine_apkindex_path(repo="main", arch: Arch | None = None):
|
def alpine_apkindex_path(repo: str = "main", arch: Arch | None = None) -> Path:
|
||||||
"""Get the path to a specific Alpine APKINDEX file on disk and download it if necessary.
|
"""Get the path to a specific Alpine APKINDEX file on disk and download it if necessary.
|
||||||
|
|
||||||
:param repo: Alpine repository name (e.g. "main")
|
:param repo: Alpine repository name (e.g. "main")
|
||||||
|
|
|
@ -6,18 +6,26 @@ import subprocess
|
||||||
from pmb.core.arch import Arch
|
from pmb.core.arch import Arch
|
||||||
import pmb.helpers.run_core
|
import pmb.helpers.run_core
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from pmb.types import Env, PathString
|
from typing import overload, Literal
|
||||||
|
from pmb.types import (
|
||||||
|
Env,
|
||||||
|
PathString,
|
||||||
|
RunOutputType,
|
||||||
|
RunOutputTypeDefault,
|
||||||
|
RunOutputTypePopen,
|
||||||
|
RunReturnType,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def user(
|
def user(
|
||||||
cmd: Sequence[PathString],
|
cmd: Sequence[PathString],
|
||||||
working_dir: Path | None = None,
|
working_dir: Path | None = None,
|
||||||
output: str = "log",
|
output: RunOutputType = "log",
|
||||||
output_return: bool = False,
|
output_return: bool = False,
|
||||||
check: bool | None = None,
|
check: bool | None = None,
|
||||||
env: Env = {},
|
env: Env = {},
|
||||||
sudo: bool = False,
|
sudo: bool = False,
|
||||||
) -> str | int | subprocess.Popen:
|
) -> RunReturnType:
|
||||||
"""
|
"""
|
||||||
Run a command on the host system as user.
|
Run a command on the host system as user.
|
||||||
|
|
||||||
|
@ -56,7 +64,7 @@ def user(
|
||||||
def user_output(
|
def user_output(
|
||||||
cmd: Sequence[PathString],
|
cmd: Sequence[PathString],
|
||||||
working_dir: Path | None = None,
|
working_dir: Path | None = None,
|
||||||
output: str = "log",
|
output: RunOutputType = "log",
|
||||||
check: bool | None = None,
|
check: bool | None = None,
|
||||||
env: Env = {},
|
env: Env = {},
|
||||||
sudo: bool = False,
|
sudo: bool = False,
|
||||||
|
@ -68,14 +76,47 @@ def user_output(
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
def root(
|
def root(
|
||||||
cmd: Sequence[PathString],
|
cmd: Sequence[PathString],
|
||||||
working_dir=None,
|
working_dir: Path | None = ...,
|
||||||
output="log",
|
output: RunOutputTypePopen = ...,
|
||||||
output_return=False,
|
output_return: Literal[False] = ...,
|
||||||
check=None,
|
check: bool | None = ...,
|
||||||
env={},
|
env: Env = ...,
|
||||||
):
|
) -> subprocess.Popen: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def root(
|
||||||
|
cmd: Sequence[PathString],
|
||||||
|
working_dir: Path | None = ...,
|
||||||
|
output: RunOutputTypeDefault = ...,
|
||||||
|
output_return: Literal[False] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
) -> int: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def root(
|
||||||
|
cmd: Sequence[PathString],
|
||||||
|
working_dir: Path | None = ...,
|
||||||
|
output: RunOutputType = ...,
|
||||||
|
output_return: Literal[True] = ...,
|
||||||
|
check: bool | None = ...,
|
||||||
|
env: Env = ...,
|
||||||
|
) -> str: ...
|
||||||
|
|
||||||
|
|
||||||
|
def root(
|
||||||
|
cmd: Sequence[PathString],
|
||||||
|
working_dir: Path | None = None,
|
||||||
|
output: RunOutputType = "log",
|
||||||
|
output_return: bool = False,
|
||||||
|
check: bool | None = None,
|
||||||
|
env: Env = {},
|
||||||
|
) -> RunReturnType:
|
||||||
"""Run a command on the host system as root, with sudo or doas.
|
"""Run a command on the host system as root, with sudo or doas.
|
||||||
|
|
||||||
:param env: dict of environment variables to be passed to the command, e.g.
|
:param env: dict of environment variables to be passed to the command, e.g.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import fcntl
|
import fcntl
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
from pmb.core.arch import Arch
|
from pmb.core.arch import Arch
|
||||||
from pmb.types import PathString, Env
|
from pmb.types import PathString, Env, RunOutputType
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -22,7 +22,9 @@ import pmb.helpers.run
|
||||||
called by core(). """
|
called by core(). """
|
||||||
|
|
||||||
|
|
||||||
def flat_cmd(cmds: Sequence[Sequence[PathString]], working_dir: Path | None = None, env: Env = {}):
|
def flat_cmd(
|
||||||
|
cmds: Sequence[Sequence[PathString]], working_dir: Path | None = None, env: Env = {}
|
||||||
|
) -> str:
|
||||||
"""Convert a shell command passed as list into a flat shell string with proper escaping.
|
"""Convert a shell command passed as list into a flat shell string with proper escaping.
|
||||||
|
|
||||||
:param cmds: list of commands as list, e.g. ["echo", "string with spaces"]
|
:param cmds: list of commands as list, e.g. ["echo", "string with spaces"]
|
||||||
|
@ -53,7 +55,9 @@ def flat_cmd(cmds: Sequence[Sequence[PathString]], working_dir: Path | None = No
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def sanity_checks(output="log", output_return=False, check=None):
|
def sanity_checks(
|
||||||
|
output: RunOutputType = "log", output_return: bool = False, check: bool | None = None
|
||||||
|
) -> None:
|
||||||
"""Raise an exception if the parameters passed to core() don't make sense.
|
"""Raise an exception if the parameters passed to core() don't make sense.
|
||||||
|
|
||||||
(all parameters are described in core() below).
|
(all parameters are described in core() below).
|
||||||
|
|
|
@ -9,7 +9,7 @@ from pmb.types import PmbArgs
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def print_status_line(key: str, value: str):
|
def print_status_line(key: str, value: str) -> None:
|
||||||
styles = pmb.config.styles
|
styles = pmb.config.styles
|
||||||
key = f"{styles['GREEN']}{key}{styles['END']}:"
|
key = f"{styles['GREEN']}{key}{styles['END']}:"
|
||||||
padding = 17
|
padding = 17
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
# Copyright 2024 Oliver Smith
|
# Copyright 2024 Oliver Smith
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from pmb.meta import Cache
|
from pmb.meta import Cache
|
||||||
from pmb.helpers.exceptions import NonBugError
|
from pmb.helpers.exceptions import NonBugError
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
@Cache("path")
|
@Cache("path")
|
||||||
def load_toml_file(path) -> dict:
|
def load_toml_file(path: Path) -> dict:
|
||||||
"""Read a toml file into a dict and show the path on error."""
|
"""Read a toml file into a dict and show the path on error."""
|
||||||
with open(path, mode="rb") as f:
|
with open(path, mode="rb") as f:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -38,7 +38,7 @@ get_recommends_visited: list[str] = []
|
||||||
get_selected_providers_visited: list[str] = []
|
get_selected_providers_visited: list[str] = []
|
||||||
|
|
||||||
|
|
||||||
def get_subpartitions_size(chroot: Chroot):
|
def get_subpartitions_size(chroot: Chroot) -> tuple[int, int]:
|
||||||
"""
|
"""
|
||||||
Calculate the size of the boot and root subpartition.
|
Calculate the size of the boot and root subpartition.
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ def get_nonfree_packages(device):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def get_kernel_package(config: Config):
|
def get_kernel_package(config: Config) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Get the device's kernel subpackage based on the user's choice in
|
Get the device's kernel subpackage based on the user's choice in
|
||||||
"pmbootstrap init".
|
"pmbootstrap init".
|
||||||
|
@ -110,7 +110,7 @@ def get_kernel_package(config: Config):
|
||||||
return ["device-" + config.device + "-kernel-" + config.kernel]
|
return ["device-" + config.device + "-kernel-" + config.kernel]
|
||||||
|
|
||||||
|
|
||||||
def copy_files_from_chroot(args: PmbArgs, chroot: Chroot):
|
def copy_files_from_chroot(args: PmbArgs, chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Copy all files from the rootfs chroot to /mnt/install, except
|
Copy all files from the rootfs chroot to /mnt/install, except
|
||||||
for the home folder (because /home will contain some empty
|
for the home folder (because /home will contain some empty
|
||||||
|
@ -155,7 +155,7 @@ def copy_files_from_chroot(args: PmbArgs, chroot: Chroot):
|
||||||
pmb.chroot.root(["cp", "-a"] + folders + ["/mnt/install/"], working_dir=mountpoint)
|
pmb.chroot.root(["cp", "-a"] + folders + ["/mnt/install/"], working_dir=mountpoint)
|
||||||
|
|
||||||
|
|
||||||
def create_home_from_skel(filesystem: str, user: str):
|
def create_home_from_skel(filesystem: str, user: str) -> None:
|
||||||
"""
|
"""
|
||||||
Create /home/{user} from /etc/skel
|
Create /home/{user} from /etc/skel
|
||||||
"""
|
"""
|
||||||
|
@ -172,7 +172,7 @@ def create_home_from_skel(filesystem: str, user: str):
|
||||||
pmb.helpers.run.root(["chown", "-R", "10000", home])
|
pmb.helpers.run.root(["chown", "-R", "10000", home])
|
||||||
|
|
||||||
|
|
||||||
def configure_apk(args: PmbArgs):
|
def configure_apk(args: PmbArgs) -> None:
|
||||||
"""
|
"""
|
||||||
Copy over all official keys, and the keys used to compile local packages
|
Copy over all official keys, and the keys used to compile local packages
|
||||||
(unless --no-local-pkgs is set). Then copy the corresponding APKINDEX files
|
(unless --no-local-pkgs is set). Then copy the corresponding APKINDEX files
|
||||||
|
@ -204,7 +204,7 @@ def configure_apk(args: PmbArgs):
|
||||||
pmb.helpers.run.user(["cat", rootfs / "etc/apk/repositories"])
|
pmb.helpers.run.user(["cat", rootfs / "etc/apk/repositories"])
|
||||||
|
|
||||||
|
|
||||||
def set_user(config: Config):
|
def set_user(config: Config) -> None:
|
||||||
"""
|
"""
|
||||||
Create user with UID 10000 if it doesn't exist.
|
Create user with UID 10000 if it doesn't exist.
|
||||||
Usually the ID for the first user created is 1000, but higher ID is
|
Usually the ID for the first user created is 1000, but higher ID is
|
||||||
|
@ -228,7 +228,7 @@ def set_user(config: Config):
|
||||||
pmb.chroot.root(["addgroup", config.user, group], chroot)
|
pmb.chroot.root(["addgroup", config.user, group], chroot)
|
||||||
|
|
||||||
|
|
||||||
def setup_login_chpasswd_user_from_arg(args: PmbArgs, user: str, chroot: Chroot):
|
def setup_login_chpasswd_user_from_arg(args: PmbArgs, user: str, chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Set the user's password from what the user passed as --password. Make an
|
Set the user's password from what the user passed as --password. Make an
|
||||||
effort to not have the password end up in the log file by writing it to
|
effort to not have the password end up in the log file by writing it to
|
||||||
|
@ -251,7 +251,7 @@ def setup_login_chpasswd_user_from_arg(args: PmbArgs, user: str, chroot: Chroot)
|
||||||
os.unlink(path_outside)
|
os.unlink(path_outside)
|
||||||
|
|
||||||
|
|
||||||
def is_root_locked(chroot: Chroot):
|
def is_root_locked(chroot: Chroot) -> bool:
|
||||||
"""
|
"""
|
||||||
Figure out from /etc/shadow if root is already locked. The output of this
|
Figure out from /etc/shadow if root is already locked. The output of this
|
||||||
is stored in the log, so use grep to only log the line for root, not the
|
is stored in the log, so use grep to only log the line for root, not the
|
||||||
|
@ -265,7 +265,7 @@ def is_root_locked(chroot: Chroot):
|
||||||
return shadow_root.startswith("root:!:")
|
return shadow_root.startswith("root:!:")
|
||||||
|
|
||||||
|
|
||||||
def setup_login(args: PmbArgs, config: Config, chroot: Chroot):
|
def setup_login(args: PmbArgs, config: Config, chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Loop until the password for user has been set successfully, and disable
|
Loop until the password for user has been set successfully, and disable
|
||||||
root login.
|
root login.
|
||||||
|
@ -294,7 +294,7 @@ def setup_login(args: PmbArgs, config: Config, chroot: Chroot):
|
||||||
pmb.chroot.root(["passwd", "-l", "root"], chroot)
|
pmb.chroot.root(["passwd", "-l", "root"], chroot)
|
||||||
|
|
||||||
|
|
||||||
def copy_ssh_keys(config: Config):
|
def copy_ssh_keys(config: Config) -> None:
|
||||||
"""
|
"""
|
||||||
If requested, copy user's SSH public keys to the device if they exist
|
If requested, copy user's SSH public keys to the device if they exist
|
||||||
"""
|
"""
|
||||||
|
@ -327,7 +327,7 @@ def copy_ssh_keys(config: Config):
|
||||||
pmb.helpers.run.root(["chown", "-R", "10000:10000", target])
|
pmb.helpers.run.root(["chown", "-R", "10000:10000", target])
|
||||||
|
|
||||||
|
|
||||||
def setup_keymap(config: Config):
|
def setup_keymap(config: Config) -> None:
|
||||||
"""
|
"""
|
||||||
Set the keymap with the setup-keymap utility if the device requires it
|
Set the keymap with the setup-keymap utility if the device requires it
|
||||||
"""
|
"""
|
||||||
|
@ -369,7 +369,7 @@ def setup_keymap(config: Config):
|
||||||
logging.info("NOTE: No valid keymap specified for device")
|
logging.info("NOTE: No valid keymap specified for device")
|
||||||
|
|
||||||
|
|
||||||
def setup_timezone(chroot: Chroot, timezone: str):
|
def setup_timezone(chroot: Chroot, timezone: str) -> None:
|
||||||
# We don't care about the arch since it's built for all!
|
# We don't care about the arch since it's built for all!
|
||||||
alpine_conf = pmb.helpers.package.get("alpine-conf", Arch.native())
|
alpine_conf = pmb.helpers.package.get("alpine-conf", Arch.native())
|
||||||
version = alpine_conf.version.split("-r")[0]
|
version = alpine_conf.version.split("-r")[0]
|
||||||
|
@ -387,7 +387,7 @@ def setup_timezone(chroot: Chroot, timezone: str):
|
||||||
pmb.chroot.root(setup_tz_cmd, chroot)
|
pmb.chroot.root(setup_tz_cmd, chroot)
|
||||||
|
|
||||||
|
|
||||||
def setup_hostname(device: str, hostname: str | None):
|
def setup_hostname(device: str, hostname: str | None) -> None:
|
||||||
"""
|
"""
|
||||||
Set the hostname and update localhost address in /etc/hosts
|
Set the hostname and update localhost address in /etc/hosts
|
||||||
"""
|
"""
|
||||||
|
@ -417,7 +417,7 @@ def setup_hostname(device: str, hostname: str | None):
|
||||||
pmb.chroot.root(["sed", "-i", "-e", regex, "/etc/hosts"], suffix)
|
pmb.chroot.root(["sed", "-i", "-e", regex, "/etc/hosts"], suffix)
|
||||||
|
|
||||||
|
|
||||||
def setup_appstream(offline: bool, chroot: Chroot):
|
def setup_appstream(offline: bool, chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
If alpine-appstream-downloader has been downloaded, execute it to have
|
If alpine-appstream-downloader has been downloaded, execute it to have
|
||||||
update AppStream data on new installs
|
update AppStream data on new installs
|
||||||
|
@ -444,7 +444,7 @@ def setup_appstream(offline: bool, chroot: Chroot):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def disable_sshd(chroot: Chroot):
|
def disable_sshd(chroot: Chroot) -> None:
|
||||||
# check=False: rc-update doesn't exit with 0 if already disabled
|
# check=False: rc-update doesn't exit with 0 if already disabled
|
||||||
pmb.chroot.root(["rc-update", "del", "sshd", "default"], chroot, check=False)
|
pmb.chroot.root(["rc-update", "del", "sshd", "default"], chroot, check=False)
|
||||||
|
|
||||||
|
@ -456,7 +456,7 @@ def disable_sshd(chroot: Chroot):
|
||||||
raise RuntimeError(f"Failed to disable sshd service: {sshd_files}")
|
raise RuntimeError(f"Failed to disable sshd service: {sshd_files}")
|
||||||
|
|
||||||
|
|
||||||
def print_sshd_info(args: PmbArgs):
|
def print_sshd_info(args: PmbArgs) -> None:
|
||||||
logging.info("") # make the note stand out
|
logging.info("") # make the note stand out
|
||||||
logging.info("*** SSH DAEMON INFORMATION ***")
|
logging.info("*** SSH DAEMON INFORMATION ***")
|
||||||
|
|
||||||
|
@ -480,7 +480,7 @@ def print_sshd_info(args: PmbArgs):
|
||||||
logging.info("More info: https://postmarketos.org/ondev-debug")
|
logging.info("More info: https://postmarketos.org/ondev-debug")
|
||||||
|
|
||||||
|
|
||||||
def disable_firewall(chroot: Chroot):
|
def disable_firewall(chroot: Chroot) -> None:
|
||||||
# check=False: rc-update doesn't exit with 0 if already disabled
|
# check=False: rc-update doesn't exit with 0 if already disabled
|
||||||
pmb.chroot.root(["rc-update", "del", "nftables", "default"], chroot, check=False)
|
pmb.chroot.root(["rc-update", "del", "nftables", "default"], chroot, check=False)
|
||||||
|
|
||||||
|
@ -492,7 +492,7 @@ def disable_firewall(chroot: Chroot):
|
||||||
raise RuntimeError(f"Failed to disable firewall: {nftables_files}")
|
raise RuntimeError(f"Failed to disable firewall: {nftables_files}")
|
||||||
|
|
||||||
|
|
||||||
def print_firewall_info(disabled: bool, arch: Arch):
|
def print_firewall_info(disabled: bool, arch: Arch) -> None:
|
||||||
pmaports_cfg = pmb.config.pmaports.read_config()
|
pmaports_cfg = pmb.config.pmaports.read_config()
|
||||||
pmaports_ok = pmaports_cfg.get("supported_firewall", None) == "nftables"
|
pmaports_ok = pmaports_cfg.get("supported_firewall", None) == "nftables"
|
||||||
|
|
||||||
|
@ -532,7 +532,7 @@ def print_firewall_info(disabled: bool, arch: Arch):
|
||||||
logging.info("For more information: https://postmarketos.org/firewall")
|
logging.info("For more information: https://postmarketos.org/firewall")
|
||||||
|
|
||||||
|
|
||||||
def generate_binary_list(args: PmbArgs, chroot: Chroot, step):
|
def generate_binary_list(args: PmbArgs, chroot: Chroot, step: int) -> list[tuple[str, int]]:
|
||||||
"""
|
"""
|
||||||
Perform three checks prior to writing binaries to disk: 1) that binaries
|
Perform three checks prior to writing binaries to disk: 1) that binaries
|
||||||
exist, 2) that binaries do not extend into the first partition, 3) that
|
exist, 2) that binaries do not extend into the first partition, 3) that
|
||||||
|
@ -587,7 +587,7 @@ def generate_binary_list(args: PmbArgs, chroot: Chroot, step):
|
||||||
return binary_list
|
return binary_list
|
||||||
|
|
||||||
|
|
||||||
def embed_firmware(args: PmbArgs, suffix: Chroot):
|
def embed_firmware(args: PmbArgs, suffix: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
This method will embed firmware, located at /usr/share, that are specified
|
This method will embed firmware, located at /usr/share, that are specified
|
||||||
by the "sd_embed_firmware" deviceinfo parameter into the SD card image
|
by the "sd_embed_firmware" deviceinfo parameter into the SD card image
|
||||||
|
@ -626,7 +626,7 @@ def embed_firmware(args: PmbArgs, suffix: Chroot):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def write_cgpt_kpart(args: PmbArgs, layout, suffix: Chroot):
|
def write_cgpt_kpart(args: PmbArgs, layout: PartitionLayout, suffix: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Write the kernel to the ChromeOS kernel partition.
|
Write the kernel to the ChromeOS kernel partition.
|
||||||
|
|
||||||
|
@ -658,7 +658,7 @@ def sanity_check_boot_size():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def sanity_check_disk(args: PmbArgs):
|
def sanity_check_disk(args: PmbArgs) -> None:
|
||||||
device = args.disk
|
device = args.disk
|
||||||
device_name = os.path.basename(device)
|
device_name = os.path.basename(device)
|
||||||
if not os.path.exists(device):
|
if not os.path.exists(device):
|
||||||
|
@ -670,7 +670,7 @@ def sanity_check_disk(args: PmbArgs):
|
||||||
raise RuntimeError(f"{device} is read-only, maybe a locked SD card?")
|
raise RuntimeError(f"{device} is read-only, maybe a locked SD card?")
|
||||||
|
|
||||||
|
|
||||||
def sanity_check_disk_size(args: PmbArgs):
|
def sanity_check_disk_size(args: PmbArgs) -> None:
|
||||||
device = args.disk
|
device = args.disk
|
||||||
devpath = os.path.realpath(device)
|
devpath = os.path.realpath(device)
|
||||||
sysfs = "/sys/class/block/{}/size".format(devpath.replace("/dev/", ""))
|
sysfs = "/sys/class/block/{}/size".format(devpath.replace("/dev/", ""))
|
||||||
|
@ -697,13 +697,13 @@ def sanity_check_disk_size(args: PmbArgs):
|
||||||
raise RuntimeError("Aborted.")
|
raise RuntimeError("Aborted.")
|
||||||
|
|
||||||
|
|
||||||
def get_ondev_pkgver(args: PmbArgs):
|
def get_ondev_pkgver(args: PmbArgs) -> str:
|
||||||
arch = pmb.parse.deviceinfo().arch
|
arch = pmb.parse.deviceinfo().arch
|
||||||
package = pmb.helpers.package.get("postmarketos-ondev", arch)
|
package = pmb.helpers.package.get("postmarketos-ondev", arch)
|
||||||
return package.version.split("-r")[0]
|
return package.version.split("-r")[0]
|
||||||
|
|
||||||
|
|
||||||
def sanity_check_ondev_version(args: PmbArgs):
|
def sanity_check_ondev_version(args: PmbArgs) -> None:
|
||||||
ver_pkg = get_ondev_pkgver(args)
|
ver_pkg = get_ondev_pkgver(args)
|
||||||
ver_min = pmb.config.ondev_min_version
|
ver_min = pmb.config.ondev_min_version
|
||||||
if pmb.parse.version.compare(ver_pkg, ver_min) == -1:
|
if pmb.parse.version.compare(ver_pkg, ver_min) == -1:
|
||||||
|
@ -715,7 +715,7 @@ def sanity_check_ondev_version(args: PmbArgs):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_partition_layout(reserve, kernel):
|
def get_partition_layout(reserve: bool | int, kernel: bool) -> PartitionLayout:
|
||||||
"""
|
"""
|
||||||
:param reserve: create an empty partition between root and boot (pma#463)
|
:param reserve: create an empty partition between root and boot (pma#463)
|
||||||
:param kernel: create a separate kernel partition before all other
|
:param kernel: create a separate kernel partition before all other
|
||||||
|
@ -741,7 +741,7 @@ def get_partition_layout(reserve, kernel):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def get_uuid(args: PmbArgs, partition: Path):
|
def get_uuid(args: PmbArgs, partition: Path) -> str:
|
||||||
"""
|
"""
|
||||||
Get UUID of a partition
|
Get UUID of a partition
|
||||||
|
|
||||||
|
@ -760,7 +760,7 @@ def get_uuid(args: PmbArgs, partition: Path):
|
||||||
).rstrip()
|
).rstrip()
|
||||||
|
|
||||||
|
|
||||||
def create_crypttab(args: PmbArgs, layout, chroot: Chroot):
|
def create_crypttab(args: PmbArgs, layout: PartitionLayout, chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Create /etc/crypttab config
|
Create /etc/crypttab config
|
||||||
|
|
||||||
|
@ -776,7 +776,7 @@ def create_crypttab(args: PmbArgs, layout, chroot: Chroot):
|
||||||
pmb.chroot.root(["mv", "/tmp/crypttab", "/etc/crypttab"], chroot)
|
pmb.chroot.root(["mv", "/tmp/crypttab", "/etc/crypttab"], chroot)
|
||||||
|
|
||||||
|
|
||||||
def create_fstab(args: PmbArgs, layout, chroot: Chroot):
|
def create_fstab(args: PmbArgs, layout: PartitionLayout, chroot: Chroot) -> None:
|
||||||
"""
|
"""
|
||||||
Create /etc/fstab config
|
Create /etc/fstab config
|
||||||
|
|
||||||
|
@ -832,15 +832,15 @@ def create_fstab(args: PmbArgs, layout, chroot: Chroot):
|
||||||
|
|
||||||
def install_system_image(
|
def install_system_image(
|
||||||
args: PmbArgs,
|
args: PmbArgs,
|
||||||
size_reserve,
|
size_reserve: int,
|
||||||
chroot: Chroot,
|
chroot: Chroot,
|
||||||
step,
|
step: int,
|
||||||
steps,
|
steps: int,
|
||||||
boot_label="pmOS_boot",
|
boot_label: str = "pmOS_boot",
|
||||||
root_label="pmOS_root",
|
root_label: str = "pmOS_root",
|
||||||
split=False,
|
split: bool = False,
|
||||||
disk: Path | None = None,
|
disk: Path | None = None,
|
||||||
):
|
) -> None:
|
||||||
"""
|
"""
|
||||||
:param size_reserve: empty partition between root and boot in MiB (pma#463)
|
:param size_reserve: empty partition between root and boot in MiB (pma#463)
|
||||||
:param suffix: the chroot suffix, where the rootfs that will be installed
|
:param suffix: the chroot suffix, where the rootfs that will be installed
|
||||||
|
@ -944,7 +944,7 @@ def install_system_image(
|
||||||
pmb.chroot.user(["mv", "-f", sys_image_patched, sys_image], working_dir=workdir)
|
pmb.chroot.user(["mv", "-f", sys_image_patched, sys_image], working_dir=workdir)
|
||||||
|
|
||||||
|
|
||||||
def print_flash_info(device: str, deviceinfo: Deviceinfo, split: bool, have_disk: bool):
|
def print_flash_info(device: str, deviceinfo: Deviceinfo, split: bool, have_disk: bool) -> None:
|
||||||
"""Print flashing information, based on the deviceinfo data and the
|
"""Print flashing information, based on the deviceinfo data and the
|
||||||
pmbootstrap arguments."""
|
pmbootstrap arguments."""
|
||||||
logging.info("") # make the note stand out
|
logging.info("") # make the note stand out
|
||||||
|
@ -1042,7 +1042,7 @@ def print_flash_info(device: str, deviceinfo: Deviceinfo, split: bool, have_disk
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def install_recovery_zip(args: PmbArgs, device: str, arch: Arch, steps):
|
def install_recovery_zip(args: PmbArgs, device: str, arch: Arch, steps: int) -> None:
|
||||||
logging.info(f"*** ({steps}/{steps}) CREATING RECOVERY-FLASHABLE ZIP ***")
|
logging.info(f"*** ({steps}/{steps}) CREATING RECOVERY-FLASHABLE ZIP ***")
|
||||||
chroot = Chroot(ChrootType.BUILDROOT, arch)
|
chroot = Chroot(ChrootType.BUILDROOT, arch)
|
||||||
mount_device_rootfs(Chroot.rootfs(device), chroot)
|
mount_device_rootfs(Chroot.rootfs(device), chroot)
|
||||||
|
@ -1054,7 +1054,7 @@ def install_recovery_zip(args: PmbArgs, device: str, arch: Arch, steps):
|
||||||
logging.info("https://postmarketos.org/recoveryzip")
|
logging.info("https://postmarketos.org/recoveryzip")
|
||||||
|
|
||||||
|
|
||||||
def install_on_device_installer(args: PmbArgs, step, steps):
|
def install_on_device_installer(args: PmbArgs, step: int, steps: int) -> None:
|
||||||
# Generate the rootfs image
|
# Generate the rootfs image
|
||||||
config = get_context().config
|
config = get_context().config
|
||||||
if not args.ondev_no_rootfs:
|
if not args.ondev_no_rootfs:
|
||||||
|
@ -1136,7 +1136,7 @@ def install_on_device_installer(args: PmbArgs, step, steps):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_selected_providers(args: PmbArgs, packages):
|
def get_selected_providers(args: PmbArgs, packages: list[str]) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Look through the specified packages and see which providers were selected
|
Look through the specified packages and see which providers were selected
|
||||||
in "pmbootstrap init". Install those as extra packages to select them
|
in "pmbootstrap init". Install those as extra packages to select them
|
||||||
|
@ -1182,7 +1182,7 @@ def get_selected_providers(args: PmbArgs, packages):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def get_recommends(args: PmbArgs, packages) -> Sequence[str]:
|
def get_recommends(args: PmbArgs, packages: list[str]) -> Sequence[str]:
|
||||||
"""
|
"""
|
||||||
Look through the specified packages and collect additional packages
|
Look through the specified packages and collect additional packages
|
||||||
specified under _pmb_recommends in them. This is recursive, so it will dive
|
specified under _pmb_recommends in them. This is recursive, so it will dive
|
||||||
|
@ -1240,7 +1240,7 @@ def get_recommends(args: PmbArgs, packages) -> Sequence[str]:
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def create_device_rootfs(args: PmbArgs, step, steps):
|
def create_device_rootfs(args: PmbArgs, step: int, steps: int) -> None:
|
||||||
# list all packages to be installed (including the ones specified by --add)
|
# list all packages to be installed (including the ones specified by --add)
|
||||||
# and upgrade the installed packages/apkindexes
|
# and upgrade the installed packages/apkindexes
|
||||||
context = get_context()
|
context = get_context()
|
||||||
|
@ -1348,7 +1348,7 @@ def create_device_rootfs(args: PmbArgs, step, steps):
|
||||||
disable_firewall(chroot)
|
disable_firewall(chroot)
|
||||||
|
|
||||||
|
|
||||||
def install(args: PmbArgs):
|
def install(args: PmbArgs) -> None:
|
||||||
device = get_context().config.device
|
device = get_context().config.device
|
||||||
chroot = Chroot(ChrootType.ROOTFS, device)
|
chroot = Chroot(ChrootType.ROOTFS, device)
|
||||||
deviceinfo = pmb.parse.deviceinfo()
|
deviceinfo = pmb.parse.deviceinfo()
|
||||||
|
|
|
@ -12,7 +12,7 @@ from pmb.core import Chroot
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def previous_install(path: Path):
|
def previous_install(path: Path) -> bool:
|
||||||
"""
|
"""
|
||||||
Search the disk for possible existence of a previous installation of
|
Search the disk for possible existence of a previous installation of
|
||||||
pmOS. We temporarily mount the possible pmOS_boot partition as
|
pmOS. We temporarily mount the possible pmOS_boot partition as
|
||||||
|
@ -39,7 +39,7 @@ def previous_install(path: Path):
|
||||||
return "pmOS_boot" in label
|
return "pmOS_boot" in label
|
||||||
|
|
||||||
|
|
||||||
def mount_disk(path: Path):
|
def mount_disk(path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
:param path: path to disk block device (e.g. /dev/mmcblk0)
|
:param path: path to disk block device (e.g. /dev/mmcblk0)
|
||||||
"""
|
"""
|
||||||
|
@ -61,7 +61,9 @@ def mount_disk(path: Path):
|
||||||
raise RuntimeError("Aborted.")
|
raise RuntimeError("Aborted.")
|
||||||
|
|
||||||
|
|
||||||
def create_and_mount_image(args: PmbArgs, size_boot, size_root, size_reserve, split=False):
|
def create_and_mount_image(
|
||||||
|
args: PmbArgs, size_boot: int, size_root: int, size_reserve: int, split: bool = False
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Create a new image file, and mount it as /dev/install.
|
Create a new image file, and mount it as /dev/install.
|
||||||
|
|
||||||
|
@ -121,7 +123,9 @@ def create_and_mount_image(args: PmbArgs, size_boot, size_root, size_reserve, sp
|
||||||
pmb.helpers.mount.bind_file(device, Chroot.native() / mount_point)
|
pmb.helpers.mount.bind_file(device, Chroot.native() / mount_point)
|
||||||
|
|
||||||
|
|
||||||
def create(args: PmbArgs, size_boot, size_root, size_reserve, split, disk: Path | None):
|
def create(
|
||||||
|
args: PmbArgs, size_boot: int, size_root: int, size_reserve: int, split: bool, disk: Path | None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Create /dev/install (the "install blockdevice").
|
Create /dev/install (the "install blockdevice").
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
import pmb.chroot
|
import pmb.chroot
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
from pmb.types import PmbArgs
|
from pmb.types import PartitionLayout, PmbArgs, PathString
|
||||||
|
|
||||||
|
|
||||||
def install_fsprogs(filesystem):
|
def install_fsprogs(filesystem):
|
||||||
|
@ -14,7 +14,7 @@ def install_fsprogs(filesystem):
|
||||||
pmb.chroot.apk.install([fsprogs], Chroot.native())
|
pmb.chroot.apk.install([fsprogs], Chroot.native())
|
||||||
|
|
||||||
|
|
||||||
def format_and_mount_boot(args: PmbArgs, device, boot_label):
|
def format_and_mount_boot(args: PmbArgs, device: str, boot_label: str) -> None:
|
||||||
"""
|
"""
|
||||||
:param device: boot partition on install block device (e.g. /dev/installp1)
|
:param device: boot partition on install block device (e.g. /dev/installp1)
|
||||||
:param boot_label: label of the root partition (e.g. "pmOS_boot")
|
:param boot_label: label of the root partition (e.g. "pmOS_boot")
|
||||||
|
@ -40,7 +40,7 @@ def format_and_mount_boot(args: PmbArgs, device, boot_label):
|
||||||
pmb.chroot.root(["mount", device, mountpoint])
|
pmb.chroot.root(["mount", device, mountpoint])
|
||||||
|
|
||||||
|
|
||||||
def format_luks_root(args: PmbArgs, device):
|
def format_luks_root(args: PmbArgs, device: str) -> None:
|
||||||
"""
|
"""
|
||||||
:param device: root partition on install block device (e.g. /dev/installp2)
|
:param device: root partition on install block device (e.g. /dev/installp2)
|
||||||
"""
|
"""
|
||||||
|
@ -72,7 +72,7 @@ def format_luks_root(args: PmbArgs, device):
|
||||||
raise RuntimeError("Failed to open cryptdevice!")
|
raise RuntimeError("Failed to open cryptdevice!")
|
||||||
|
|
||||||
|
|
||||||
def get_root_filesystem(args: PmbArgs):
|
def get_root_filesystem(args: PmbArgs) -> str:
|
||||||
ret = args.filesystem or pmb.parse.deviceinfo().root_filesystem or "ext4"
|
ret = args.filesystem or pmb.parse.deviceinfo().root_filesystem or "ext4"
|
||||||
pmaports_cfg = pmb.config.pmaports.read_config()
|
pmaports_cfg = pmb.config.pmaports.read_config()
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ def get_root_filesystem(args: PmbArgs):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def prepare_btrfs_subvolumes(args: PmbArgs, device, mountpoint):
|
def prepare_btrfs_subvolumes(args: PmbArgs, device: str, mountpoint: str) -> None:
|
||||||
"""
|
"""
|
||||||
Create separate subvolumes if root filesystem is btrfs.
|
Create separate subvolumes if root filesystem is btrfs.
|
||||||
This lets us do snapshots and rollbacks of relevant parts
|
This lets us do snapshots and rollbacks of relevant parts
|
||||||
|
@ -143,7 +143,9 @@ def prepare_btrfs_subvolumes(args: PmbArgs, device, mountpoint):
|
||||||
pmb.chroot.root(["chattr", "+C", f"{mountpoint}/var"])
|
pmb.chroot.root(["chattr", "+C", f"{mountpoint}/var"])
|
||||||
|
|
||||||
|
|
||||||
def format_and_mount_root(args: PmbArgs, device, root_label, disk):
|
def format_and_mount_root(
|
||||||
|
args: PmbArgs, device: str, root_label: str, disk: PathString | None
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
:param device: root partition on install block device (e.g. /dev/installp2)
|
:param device: root partition on install block device (e.g. /dev/installp2)
|
||||||
:param root_label: label of the root partition (e.g. "pmOS_root")
|
:param root_label: label of the root partition (e.g. "pmOS_root")
|
||||||
|
@ -185,7 +187,13 @@ def format_and_mount_root(args: PmbArgs, device, root_label, disk):
|
||||||
prepare_btrfs_subvolumes(args, device, mountpoint)
|
prepare_btrfs_subvolumes(args, device, mountpoint)
|
||||||
|
|
||||||
|
|
||||||
def format(args: PmbArgs, layout, boot_label, root_label, disk):
|
def format(
|
||||||
|
args: PmbArgs,
|
||||||
|
layout: PartitionLayout,
|
||||||
|
boot_label: str,
|
||||||
|
root_label: str,
|
||||||
|
disk: PathString | None,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
:param layout: partition layout from get_partition_layout()
|
:param layout: partition layout from get_partition_layout()
|
||||||
:param boot_label: label of the boot partition (e.g. "pmOS_boot")
|
:param boot_label: label of the boot partition (e.g. "pmOS_boot")
|
||||||
|
|
|
@ -8,12 +8,13 @@ import pmb.chroot
|
||||||
import pmb.config
|
import pmb.config
|
||||||
import pmb.install.losetup
|
import pmb.install.losetup
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
from pmb.types import PartitionLayout
|
||||||
import pmb.core.dps
|
import pmb.core.dps
|
||||||
|
|
||||||
|
|
||||||
# FIXME (#2324): this function drops disk to a string because it's easier
|
# FIXME (#2324): this function drops disk to a string because it's easier
|
||||||
# to manipulate, this is probably bad.
|
# to manipulate, this is probably bad.
|
||||||
def partitions_mount(device: str, layout, disk: Path | None):
|
def partitions_mount(device: str, layout: PartitionLayout, disk: Path | None) -> None:
|
||||||
"""
|
"""
|
||||||
Mount blockdevices of partitions inside native chroot
|
Mount blockdevices of partitions inside native chroot
|
||||||
:param layout: partition layout from get_partition_layout()
|
:param layout: partition layout from get_partition_layout()
|
||||||
|
@ -61,7 +62,7 @@ def partitions_mount(device: str, layout, disk: Path | None):
|
||||||
pmb.helpers.mount.bind_file(source, target)
|
pmb.helpers.mount.bind_file(source, target)
|
||||||
|
|
||||||
|
|
||||||
def partition(layout, size_boot, size_reserve):
|
def partition(layout: PartitionLayout, size_boot: int, size_reserve: int) -> None:
|
||||||
"""
|
"""
|
||||||
Partition /dev/install and create /dev/install{p1,p2,p3}:
|
Partition /dev/install and create /dev/install{p1,p2,p3}:
|
||||||
* /dev/installp1: boot
|
* /dev/installp1: boot
|
||||||
|
@ -122,7 +123,7 @@ def partition(layout, size_boot, size_reserve):
|
||||||
pmb.chroot.root(["parted", "-s", "/dev/install"] + command, check=False)
|
pmb.chroot.root(["parted", "-s", "/dev/install"] + command, check=False)
|
||||||
|
|
||||||
|
|
||||||
def partition_cgpt(layout, size_boot, size_reserve):
|
def partition_cgpt(layout: PartitionLayout, size_boot: int, size_reserve: int) -> None:
|
||||||
"""
|
"""
|
||||||
This function does similar functionality to partition(), but this
|
This function does similar functionality to partition(), but this
|
||||||
one is for ChromeOS devices which use special GPT. We don't follow
|
one is for ChromeOS devices which use special GPT. We don't follow
|
||||||
|
|
|
@ -12,7 +12,7 @@ import pmb.flasher
|
||||||
import pmb.helpers.frontend
|
import pmb.helpers.frontend
|
||||||
|
|
||||||
|
|
||||||
def create_zip(args: PmbArgs, chroot: Chroot, device: str):
|
def create_zip(args: PmbArgs, chroot: Chroot, device: str) -> None:
|
||||||
"""
|
"""
|
||||||
Create android recovery compatible installer zip.
|
Create android recovery compatible installer zip.
|
||||||
"""
|
"""
|
||||||
|
@ -51,7 +51,7 @@ def create_zip(args: PmbArgs, chroot: Chroot, device: str):
|
||||||
raise AssertionError("Partitions should not be None at this point")
|
raise AssertionError("Partitions should not be None at this point")
|
||||||
|
|
||||||
# Create config file for the recovery installer
|
# Create config file for the recovery installer
|
||||||
options = {
|
options: dict[str, bool | str] = {
|
||||||
"DEVICE": device,
|
"DEVICE": device,
|
||||||
"FLASH_KERNEL": args.recovery_flash_kernel,
|
"FLASH_KERNEL": args.recovery_flash_kernel,
|
||||||
"ISOREC": method == "heimdall-isorec",
|
"ISOREC": method == "heimdall-isorec",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
from typing import Generic, Optional, TypeVar, overload
|
from typing import Any, Generic, Optional, TypeVar, overload
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
@ -25,7 +25,7 @@ class Wrapper(Generic[FuncArgs, FuncReturn]):
|
||||||
# actually end up here. We first check if we have a cached
|
# actually end up here. We first check if we have a cached
|
||||||
# result and if not then we do the actual function call and
|
# result and if not then we do the actual function call and
|
||||||
# cache it if applicable
|
# cache it if applicable
|
||||||
def __call__(self, *args, **kwargs) -> FuncReturn:
|
def __call__(self, *args: Any, **kwargs: Any) -> FuncReturn:
|
||||||
if self.disabled:
|
if self.disabled:
|
||||||
return self.func(*args, **kwargs)
|
return self.func(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class Cache:
|
||||||
|
|
||||||
# Build the cache key, or return None to not cache in the case where
|
# Build the cache key, or return None to not cache in the case where
|
||||||
# we only cache when an argument has a specific value
|
# we only cache when an argument has a specific value
|
||||||
def build_key(self, func: Callable, *args, **kwargs) -> str | None:
|
def build_key(self, func: Callable, *args: Any, **kwargs: Any) -> str | None:
|
||||||
key = "~"
|
key = "~"
|
||||||
# Easy case: cache irrelevant of arguments
|
# Easy case: cache irrelevant of arguments
|
||||||
if not self.params and not self.kwargs:
|
if not self.params and not self.kwargs:
|
||||||
|
|
|
@ -12,7 +12,7 @@ import pmb.helpers.run
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
|
|
||||||
|
|
||||||
def start_nbd_server(device: str, replace: bool, ip="172.16.42.2", port=9999):
|
def start_nbd_server(device: str, replace: bool, ip: str = "172.16.42.2", port: int = 9999) -> None:
|
||||||
"""
|
"""
|
||||||
Start nbd server in chroot_native with pmOS rootfs.
|
Start nbd server in chroot_native with pmOS rootfs.
|
||||||
:param ip: IP address to serve nbd server for
|
:param ip: IP address to serve nbd server for
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# mypy: disable-error-code="attr-defined"
|
# mypy: disable-error-code="attr-defined"
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
|
from pmb.types import Apkbuild
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
|
@ -31,7 +32,7 @@ revar4 = re.compile(r"\${([a-zA-Z_]+[a-zA-Z0-9_]*)#(.*)}")
|
||||||
revar5 = re.compile(r"([a-zA-Z_]+[a-zA-Z0-9_]*)=")
|
revar5 = re.compile(r"([a-zA-Z_]+[a-zA-Z0-9_]*)=")
|
||||||
|
|
||||||
|
|
||||||
def replace_variable(apkbuild, value: str) -> str:
|
def replace_variable(apkbuild: Apkbuild, value: str) -> str:
|
||||||
def log_key_not_found(match):
|
def log_key_not_found(match):
|
||||||
logging.verbose(
|
logging.verbose(
|
||||||
f"{apkbuild['pkgname']}: key '{match.group(1)}' for"
|
f"{apkbuild['pkgname']}: key '{match.group(1)}' for"
|
||||||
|
@ -95,7 +96,7 @@ def replace_variable(apkbuild, value: str) -> str:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def function_body(path: Path, func: str):
|
def function_body(path: Path, func: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Get the body of a function in an APKBUILD.
|
Get the body of a function in an APKBUILD.
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ def function_body(path: Path, func: str):
|
||||||
return func_body
|
return func_body
|
||||||
|
|
||||||
|
|
||||||
def read_file(path: Path):
|
def read_file(path: Path) -> list[str]:
|
||||||
"""
|
"""
|
||||||
Read an APKBUILD file
|
Read an APKBUILD file
|
||||||
|
|
||||||
|
@ -321,7 +322,7 @@ def _parse_subpackage(path, lines, apkbuild, subpackages, subpkg):
|
||||||
|
|
||||||
|
|
||||||
@Cache("path")
|
@Cache("path")
|
||||||
def apkbuild(path: Path, check_pkgver=True, check_pkgname=True):
|
def apkbuild(path: Path, check_pkgver: bool = True, check_pkgname: bool = True) -> Apkbuild:
|
||||||
"""
|
"""
|
||||||
Parse relevant information out of the APKBUILD file. This is not meant
|
Parse relevant information out of the APKBUILD file. This is not meant
|
||||||
to be perfect and catch every edge case (for that, a full shell parser
|
to be perfect and catch every edge case (for that, a full shell parser
|
||||||
|
@ -371,7 +372,7 @@ def apkbuild(path: Path, check_pkgver=True, check_pkgname=True):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def kernels(device: str):
|
def kernels(device: str) -> dict[str, str] | None:
|
||||||
"""
|
"""
|
||||||
Get the possible kernels from a device-* APKBUILD.
|
Get the possible kernels from a device-* APKBUILD.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright 2023 Oliver Smith
|
# Copyright 2023 Oliver Smith
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
import os
|
import os
|
||||||
|
from typing import TextIO
|
||||||
|
|
||||||
from pmb.core.context import get_context
|
from pmb.core.context import get_context
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -9,10 +11,10 @@ import pmb.chroot
|
||||||
import pmb.chroot.other
|
import pmb.chroot.other
|
||||||
import pmb.chroot.apk
|
import pmb.chroot.apk
|
||||||
from pmb.core import Chroot
|
from pmb.core import Chroot
|
||||||
from pmb.types import Bootimg
|
from pmb.types import Bootimg, PathString
|
||||||
|
|
||||||
|
|
||||||
def is_dtb(path) -> bool:
|
def is_dtb(path: PathString) -> bool:
|
||||||
if not os.path.isfile(path):
|
if not os.path.isfile(path):
|
||||||
return False
|
return False
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
|
@ -20,7 +22,7 @@ def is_dtb(path) -> bool:
|
||||||
return f.read(4) == b"\xd0\x0d\xfe\xed"
|
return f.read(4) == b"\xd0\x0d\xfe\xed"
|
||||||
|
|
||||||
|
|
||||||
def get_mtk_label(path) -> str | None:
|
def get_mtk_label(path: PathString) -> str | None:
|
||||||
"""Read the label from the MediaTek header of the kernel or ramdisk inside
|
"""Read the label from the MediaTek header of the kernel or ramdisk inside
|
||||||
an extracted boot.img.
|
an extracted boot.img.
|
||||||
:param path: to either the kernel or ramdisk extracted from boot.img
|
:param path: to either the kernel or ramdisk extracted from boot.img
|
||||||
|
@ -52,7 +54,7 @@ def get_mtk_label(path) -> str | None:
|
||||||
return label
|
return label
|
||||||
|
|
||||||
|
|
||||||
def get_qcdt_type(path) -> str | None:
|
def get_qcdt_type(path: PathString) -> str | None:
|
||||||
"""Get the dt.img type by reading the first four bytes of the file.
|
"""Get the dt.img type by reading the first four bytes of the file.
|
||||||
:param path: to the qcdt image extracted from boot.img
|
:param path: to the qcdt image extracted from boot.img
|
||||||
:returns: * None: dt.img is of unknown type
|
:returns: * None: dt.img is of unknown type
|
||||||
|
@ -195,5 +197,5 @@ def bootimg(path: Path) -> Bootimg:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def trim_input(f) -> str:
|
def trim_input(f: TextIO) -> str:
|
||||||
return f.read().replace("\n", "")
|
return f.read().replace("\n", "")
|
||||||
|
|
|
@ -10,7 +10,7 @@ from pmb.core.context import get_context
|
||||||
|
|
||||||
|
|
||||||
def package_provider(
|
def package_provider(
|
||||||
pkgname, pkgnames_install, suffix: Chroot = Chroot.native()
|
pkgname: str, pkgnames_install: list[str], suffix: Chroot = Chroot.native()
|
||||||
) -> pmb.core.apkindex_block.ApkindexBlock | None:
|
) -> pmb.core.apkindex_block.ApkindexBlock | None:
|
||||||
"""
|
"""
|
||||||
:param pkgnames_install: packages to be installed
|
:param pkgnames_install: packages to be installed
|
||||||
|
|
|
@ -60,7 +60,7 @@ def _parse_kernel_suffix(info, device, kernel):
|
||||||
|
|
||||||
|
|
||||||
@Cache("device", "kernel")
|
@Cache("device", "kernel")
|
||||||
def deviceinfo(device=None, kernel=None) -> "Deviceinfo":
|
def deviceinfo(device: str | None = None, kernel: str | None = None) -> "Deviceinfo":
|
||||||
"""
|
"""
|
||||||
:param device: defaults to args.device
|
:param device: defaults to args.device
|
||||||
:param kernel: defaults to args.kernel
|
:param kernel: defaults to args.kernel
|
||||||
|
@ -170,7 +170,7 @@ class Deviceinfo:
|
||||||
keymaps: str | None = ""
|
keymaps: str | None = ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __validate(info: dict[str, str], path: Path):
|
def __validate(info: dict[str, str], path: Path) -> None:
|
||||||
# Resolve path for more readable error messages
|
# Resolve path for more readable error messages
|
||||||
path = path.resolve()
|
path = path.resolve()
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import pmb.parse
|
||||||
import pmb.helpers.pmaports
|
import pmb.helpers.pmaports
|
||||||
import pmb.parse.kconfigcheck
|
import pmb.parse.kconfigcheck
|
||||||
from pmb.helpers.exceptions import NonBugError
|
from pmb.helpers.exceptions import NonBugError
|
||||||
|
from pmb.types import PathString
|
||||||
|
|
||||||
|
|
||||||
def is_set(config, option):
|
def is_set(config, option):
|
||||||
|
@ -158,7 +159,14 @@ def check_config_options_set(
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def check_config(config_path, config_arch, pkgver, categories: list, details=False):
|
# TODO: This should probably use Arch and not str for config_arch
|
||||||
|
def check_config(
|
||||||
|
config_path: PathString,
|
||||||
|
config_arch: str,
|
||||||
|
pkgver: str,
|
||||||
|
categories: list[str],
|
||||||
|
details: bool = False,
|
||||||
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Check, whether one kernel config passes the rules of multiple components.
|
Check, whether one kernel config passes the rules of multiple components.
|
||||||
|
|
||||||
|
@ -295,7 +303,9 @@ def extract_version(config_path):
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
def check_file(config_path, components_list: list[str] = [], details=False):
|
def check_file(
|
||||||
|
config_path: PathString, components_list: list[str] = [], details: bool = False
|
||||||
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Check for necessary kernel config options in a kconfig file.
|
Check for necessary kernel config options in a kconfig file.
|
||||||
|
|
||||||
|
|
|
@ -206,7 +206,7 @@ def validate(version):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def compare(a_version: str, b_version: str, fuzzy=False):
|
def compare(a_version: str, b_version: str, fuzzy: bool = False) -> int:
|
||||||
"""
|
"""
|
||||||
Compare two versions A and B to find out which one is higher, or if
|
Compare two versions A and B to find out which one is higher, or if
|
||||||
both are equal.
|
both are equal.
|
||||||
|
|
|
@ -21,13 +21,13 @@ import pmb.chroot.initfs
|
||||||
import pmb.config
|
import pmb.config
|
||||||
import pmb.config.pmaports
|
import pmb.config.pmaports
|
||||||
import pmb.install.losetup
|
import pmb.install.losetup
|
||||||
from pmb.types import PathString, PmbArgs
|
from pmb.types import Env, PathString, PmbArgs
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
import pmb.parse.cpuinfo
|
import pmb.parse.cpuinfo
|
||||||
from pmb.core import Chroot, ChrootType
|
from pmb.core import Chroot, ChrootType
|
||||||
|
|
||||||
|
|
||||||
def system_image(device: str):
|
def system_image(device: str) -> Path:
|
||||||
"""
|
"""
|
||||||
Returns path to rootfs for specified device. In case that it doesn't
|
Returns path to rootfs for specified device. In case that it doesn't
|
||||||
exist, raise and exception explaining how to generate it.
|
exist, raise and exception explaining how to generate it.
|
||||||
|
@ -41,7 +41,7 @@ def system_image(device: str):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def create_second_storage(args: PmbArgs, device: str):
|
def create_second_storage(args: PmbArgs, device: str) -> Path:
|
||||||
"""
|
"""
|
||||||
Generate a second storage image if it does not exist.
|
Generate a second storage image if it does not exist.
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ def create_second_storage(args: PmbArgs, device: str):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|
||||||
def which_qemu(arch: Arch):
|
def which_qemu(arch: Arch) -> str:
|
||||||
"""
|
"""
|
||||||
Finds the qemu executable or raises an exception otherwise
|
Finds the qemu executable or raises an exception otherwise
|
||||||
"""
|
"""
|
||||||
|
@ -97,7 +97,13 @@ def create_gdk_loader_cache(args: PmbArgs) -> Path:
|
||||||
return chroot_native / custom_cache_path
|
return chroot_native / custom_cache_path
|
||||||
|
|
||||||
|
|
||||||
def command_qemu(args: PmbArgs, config: Config, arch: Arch, img_path, img_path_2nd=None):
|
def command_qemu(
|
||||||
|
args: PmbArgs,
|
||||||
|
config: Config,
|
||||||
|
arch: Arch,
|
||||||
|
img_path: Path,
|
||||||
|
img_path_2nd: Path | None = None,
|
||||||
|
) -> tuple[list[str | Path], Env]:
|
||||||
"""
|
"""
|
||||||
Generate the full qemu command with arguments to run postmarketOS
|
Generate the full qemu command with arguments to run postmarketOS
|
||||||
"""
|
"""
|
||||||
|
@ -139,6 +145,11 @@ def command_qemu(args: PmbArgs, config: Config, arch: Arch, img_path, img_path_2
|
||||||
if not arch.is_native() and ncpus > 8:
|
if not arch.is_native() and ncpus > 8:
|
||||||
ncpus = 8
|
ncpus = 8
|
||||||
|
|
||||||
|
env: Env
|
||||||
|
# It might be tempting to use PathString here, but I don't think it makes sense semantically as
|
||||||
|
# this is not just a list of paths.
|
||||||
|
command: list[str | Path]
|
||||||
|
|
||||||
if args.host_qemu:
|
if args.host_qemu:
|
||||||
qemu_bin = which_qemu(arch)
|
qemu_bin = which_qemu(arch)
|
||||||
env = {}
|
env = {}
|
||||||
|
@ -319,7 +330,7 @@ def sigterm_handler(number, frame):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def install_depends(args: PmbArgs, arch: Arch):
|
def install_depends(args: PmbArgs, arch: Arch) -> None:
|
||||||
"""
|
"""
|
||||||
Install any necessary qemu dependencies in native chroot
|
Install any necessary qemu dependencies in native chroot
|
||||||
"""
|
"""
|
||||||
|
@ -358,7 +369,7 @@ def install_depends(args: PmbArgs, arch: Arch):
|
||||||
pmb.chroot.apk.install(depends, chroot)
|
pmb.chroot.apk.install(depends, chroot)
|
||||||
|
|
||||||
|
|
||||||
def run(args: PmbArgs):
|
def run(args: PmbArgs) -> None:
|
||||||
"""
|
"""
|
||||||
Run a postmarketOS image in qemu
|
Run a postmarketOS image in qemu
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright 2023 Martijn Braam
|
# Copyright 2023 Martijn Braam
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from pmb.core.arch import Arch
|
from pmb.core.arch import Arch
|
||||||
from pmb.helpers import logging
|
from pmb.helpers import logging
|
||||||
|
@ -63,7 +64,7 @@ def ssh_find_arch(args: PmbArgs, user: str, host: str, port: str) -> Arch:
|
||||||
return alpine_architecture
|
return alpine_architecture
|
||||||
|
|
||||||
|
|
||||||
def ssh_install_apks(args: PmbArgs, user, host, port, paths: list) -> None:
|
def ssh_install_apks(args: PmbArgs, user: str, host: str, port: str, paths: list[Path]) -> None:
|
||||||
"""Copy binary packages via SCP and install them via SSH.
|
"""Copy binary packages via SCP and install them via SSH.
|
||||||
:param user: target device ssh username
|
:param user: target device ssh username
|
||||||
:param host: target device ssh hostname
|
:param host: target device ssh hostname
|
||||||
|
@ -95,7 +96,13 @@ def ssh_install_apks(args: PmbArgs, user, host, port, paths: list) -> None:
|
||||||
|
|
||||||
|
|
||||||
def sideload(
|
def sideload(
|
||||||
args: PmbArgs, user: str, host: str, port: str, arch: Arch | None, copy_key: bool, pkgnames
|
args: PmbArgs,
|
||||||
|
user: str,
|
||||||
|
host: str,
|
||||||
|
port: str,
|
||||||
|
arch: Arch | None,
|
||||||
|
copy_key: bool,
|
||||||
|
pkgnames: list[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Build packages if necessary and install them via SSH.
|
"""Build packages if necessary and install them via SSH.
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright 2024 Caleb Connolly
|
# Copyright 2024 Caleb Connolly
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import subprocess
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Literal, TypedDict
|
from typing import Any, Literal, TypedDict
|
||||||
|
@ -8,6 +9,10 @@ from typing import Any, Literal, TypedDict
|
||||||
from pmb.core.arch import Arch
|
from pmb.core.arch import Arch
|
||||||
|
|
||||||
CrossCompileType = Literal["native", "crossdirect"] | None
|
CrossCompileType = Literal["native", "crossdirect"] | None
|
||||||
|
RunOutputTypeDefault = Literal["log", "stdout", "interactive", "tui", "null"]
|
||||||
|
RunOutputTypePopen = Literal["background", "pipe"]
|
||||||
|
RunOutputType = RunOutputTypeDefault | RunOutputTypePopen
|
||||||
|
RunReturnType = str | int | subprocess.Popen
|
||||||
PathString = Path | str
|
PathString = Path | str
|
||||||
Env = dict[str, PathString]
|
Env = dict[str, PathString]
|
||||||
Apkbuild = dict[str, Any]
|
Apkbuild = dict[str, Any]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue