pmb.parse.apkindex: Introduce proper typing (MR 2425)

And adjust other code.

Closes https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/issues/2455
This commit is contained in:
Stefan Hansson 2024-09-29 20:24:36 +02:00 committed by Newbyte
parent 566b43edd4
commit 71772b9b6b
No known key found for this signature in database
GPG key ID: 8A700086A9FE41FD
18 changed files with 279 additions and 179 deletions

View file

@ -9,10 +9,9 @@ See also:
- pmb/helpers/repo.py (work with binary package repos)
"""
import copy
from typing import Any, overload
from typing import overload
from pmb.core.arch import Arch
from pmb.core.context import get_context
from pmb.core.package_metadata import PackageMetadata
from pmb.helpers import logging
import pmb.build._package
@ -30,27 +29,33 @@ def remove_operators(package):
@overload
def get(pkgname: str, arch: Arch, replace_subpkgnames: bool = False) -> dict[str, Any]: ...
def get(pkgname: str, arch: Arch, replace_subpkgnames: bool = ...) -> PackageMetadata: ...
@overload
def get(
pkgname: str, arch: Arch, replace_subpkgnames: bool = False, must_exist: bool = True
) -> dict[str, Any] | None: ...
pkgname: str, arch: Arch, replace_subpkgnames: bool = ..., must_exist: bool = ...
) -> PackageMetadata | None: ...
@overload
def get(
pkgname: str,
arch: Arch,
replace_subpkgnames: bool = False,
must_exist: bool = True,
try_other_arches: bool = True,
) -> dict[str, Any] | None: ...
replace_subpkgnames: bool = ...,
must_exist: bool = ...,
try_other_arches: bool = ...,
) -> PackageMetadata | None: ...
@Cache("pkgname", "arch", "replace_subpkgnames", "try_other_arches")
def get(pkgname, arch, replace_subpkgnames=False, must_exist=True, try_other_arches=True):
def get(
pkgname: str,
arch: Arch,
replace_subpkgnames: bool = False,
must_exist: bool = True,
try_other_arches: bool = True,
) -> PackageMetadata | None:
"""Find a package in pmaports, and as fallback in the APKINDEXes of the binary packages.
:param pkgname: package name (e.g. "hello-world")
@ -71,50 +76,37 @@ def get(pkgname, arch, replace_subpkgnames=False, must_exist=True, try_other_arc
* None if the package was not found
"""
# Find in pmaports
ret: dict[str, Any] = {}
ret: PackageMetadata | None = None
pmaport = pmb.helpers.pmaports.get(pkgname, False)
if pmaport:
ret = {
"arch": pmaport["arch"],
"depends": pmb.build._package.get_depends(get_context(), pmaport),
"pkgname": pmaport["pkgname"],
"provides": pmaport["provides"],
"version": pmaport["pkgver"] + "-r" + pmaport["pkgrel"],
}
ret = PackageMetadata.from_pmaport(pmaport)
# Find in APKINDEX (given arch)
if not ret or not pmb.helpers.pmaports.check_arches(ret["arch"], arch):
if not ret or not pmb.helpers.pmaports.check_arches(ret.arch, arch):
pmb.helpers.repo.update(arch)
ret_repo = pmb.parse.apkindex.package(pkgname, arch, False)
# Save as result if there was no pmaport, or if the pmaport can not be
# built for the given arch, but there is a binary package for that arch
# (e.g. temp/mesa can't be built for x86_64, but Alpine has it)
if not ret or (ret_repo and ret_repo["arch"] == arch):
ret = ret_repo
if ret_repo and (not ret or ret_repo.arch == arch):
ret = PackageMetadata.from_apkindex_block(ret_repo)
# Find in APKINDEX (other arches)
if not ret and try_other_arches:
pmb.helpers.repo.update()
for arch_i in Arch.supported():
if arch_i != arch:
ret = pmb.parse.apkindex.package(pkgname, arch_i, False)
apkindex_block = pmb.parse.apkindex.package(pkgname, arch_i, False)
if apkindex_block is not None:
ret = PackageMetadata.from_apkindex_block(apkindex_block)
if ret:
break
# Copy ret (it might have references to caches of the APKINDEX or APKBUILDs
# and we don't want to modify those!)
if ret:
ret = copy.deepcopy(ret)
# Make sure ret["arch"] is a list (APKINDEX code puts a string there)
if ret and isinstance(ret["arch"], str):
ret["arch"] = [ret["arch"]]
# Replace subpkgnames if desired
if replace_subpkgnames:
if replace_subpkgnames and ret:
depends_new = []
for depend in ret["depends"]:
for depend in ret.depends:
depend_data = get(depend, arch, must_exist=False, try_other_arches=try_other_arches)
if not depend_data:
logging.warning(f"WARNING: {pkgname}: failed to resolve" f" dependency '{depend}'")
@ -122,10 +114,10 @@ def get(pkgname, arch, replace_subpkgnames=False, must_exist=True, try_other_arc
if depend not in depends_new:
depends_new += [depend]
continue
depend_pkgname = depend_data["pkgname"]
depend_pkgname = depend_data.pkgname
if depend_pkgname not in depends_new:
depends_new += [depend_pkgname]
ret["depends"] = depends_new
ret.depends = depends_new
# Save to cache and return
if ret:
@ -141,7 +133,7 @@ def get(pkgname, arch, replace_subpkgnames=False, must_exist=True, try_other_arc
@Cache("pkgname", "arch")
def depends_recurse(pkgname, arch):
def depends_recurse(pkgname: str, arch: Arch) -> list[str]:
"""Recursively resolve all of the package's dependencies.
:param pkgname: name of the package (e.g. "device-samsung-i9100")
@ -158,19 +150,19 @@ def depends_recurse(pkgname, arch):
package = get(pkgname_queue, arch)
# Add its depends to the queue
for depend in package["depends"]:
for depend in package.depends:
if depend not in ret:
queue += [depend]
# Add the pkgname (not possible subpkgname) to ret
if package["pkgname"] not in ret:
ret += [package["pkgname"]]
if package.pkgname not in ret:
ret += [package.pkgname]
ret.sort()
return ret
def check_arch(pkgname, arch, binary=True):
def check_arch(pkgname: str, arch: Arch, binary: bool = True) -> bool:
"""Check if a package be built for a certain architecture, or is there a binary package for it.
:param pkgname: name of the package
@ -181,7 +173,7 @@ def check_arch(pkgname, arch, binary=True):
:returns: True when the package can be built, or there is a binary package, False otherwise
"""
if binary:
arches = get(pkgname, arch)["arch"]
arches = get(pkgname, arch).arch
else:
arches = pmb.helpers.pmaports.get(pkgname, must_exist=True)["arch"]
return pmb.helpers.pmaports.check_arches(arches, arch)