treewide: migrate to pkgrepo API (MR 2252)

Make use of the new pmb.core.pkgrepo API to handle multiple aports and
extra-repos.

Signed-off-by: Caleb Connolly <caleb@postmarketos.org>
This commit is contained in:
Caleb Connolly 2024-06-08 05:59:45 +02:00 committed by Oliver Smith
parent 8a61d67053
commit 560cea46ea
No known key found for this signature in database
GPG key ID: 5AE7F5513E0885CB
19 changed files with 153 additions and 91 deletions

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import os import os
from pmb.core import get_context from pmb.core import get_context
from pmb.core.pkgrepo import pkgrepo_default_path
from pmb.helpers import logging from pmb.helpers import logging
import pmb.aportgen.busybox_static import pmb.aportgen.busybox_static
import pmb.aportgen.core import pmb.aportgen.core
@ -61,7 +62,7 @@ def generate(pkgname, fork_alpine):
else: else:
prefix, folder, options = properties(pkgname) prefix, folder, options = properties(pkgname)
config = get_context().config config = get_context().config
path_target = config.aports / folder / pkgname path_target = pkgrepo_default_path() / folder / pkgname
# Confirm overwrite # Confirm overwrite
if options["confirm_overwrite"] and os.path.exists(path_target): if options["confirm_overwrite"] and os.path.exists(path_target):

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import pmb.aportgen.core import pmb.aportgen.core
from pmb.core import get_context from pmb.core import get_context
from pmb.core.pkgrepo import pkgrepo_default_path
import pmb.helpers.git import pmb.helpers.git
import pmb.helpers.run import pmb.helpers.run
@ -15,10 +16,10 @@ def generate(pkgname):
upstream = pmb.aportgen.core.get_upstream_aport("gcc", arch) upstream = pmb.aportgen.core.get_upstream_aport("gcc", arch)
based_on = "main/gcc (from Alpine)" based_on = "main/gcc (from Alpine)"
elif prefix == "gcc4": elif prefix == "gcc4":
upstream = f"{context.config.aports}/main/gcc4" upstream = pkgrepo_default_path() / "main/gcc4"
based_on = "main/gcc4 (from postmarketOS)" based_on = "main/gcc4 (from postmarketOS)"
elif prefix == "gcc6": elif prefix == "gcc6":
upstream = f"{context.config.aports}/main/gcc6" upstream = pkgrepo_default_path() / "main/gcc6"
based_on = "main/gcc6 (from postmarketOS)" based_on = "main/gcc6 (from postmarketOS)"
else: else:
raise ValueError(f"Invalid prefix '{prefix}', expected gcc, gcc4 or" raise ValueError(f"Invalid prefix '{prefix}', expected gcc, gcc4 or"

View file

@ -61,11 +61,12 @@ def get_apkbuild(pkgname, arch):
pmb.helpers.repo.update(arch) pmb.helpers.repo.update(arch)
# Get pmaport, skip upstream only packages # Get pmaport, skip upstream only packages
pmaport = pmb.helpers.pmaports.get(pkgname, False) pmaport, apkbuild = pmb.helpers.pmaports.get_with_path(pkgname, False)
if pmaport: if pmaport:
return pmaport pmaport = pkgrepo_relative_path(pmaport)[0]
return pmaport, apkbuild
if pmb.parse.apkindex.providers(pkgname, arch, False): if pmb.parse.apkindex.providers(pkgname, arch, False):
return None return None, None
raise RuntimeError("Package '" + pkgname + "': Could not find aport, and" raise RuntimeError("Package '" + pkgname + "': Could not find aport, and"
" could not find this package in any APKINDEX!") " could not find this package in any APKINDEX!")
@ -158,7 +159,7 @@ def build_depends(context: Context, apkbuild, arch, strict):
" pmbootstrap won't build any depends since" " pmbootstrap won't build any depends since"
" it was started with --no-depends.") " it was started with --no-depends.")
# Check if binary package is outdated # Check if binary package is outdated
apkbuild_dep = get_apkbuild(depend, arch) _, apkbuild_dep = get_apkbuild(depend, arch)
if apkbuild_dep and \ if apkbuild_dep and \
pmb.build.is_necessary(arch, apkbuild_dep): pmb.build.is_necessary(arch, apkbuild_dep):
raise RuntimeError(f"Binary package for dependency '{depend}'" raise RuntimeError(f"Binary package for dependency '{depend}'"
@ -339,15 +340,21 @@ def override_source(apkbuild, pkgver, src, chroot: Chroot=Chroot.native()):
pmb.chroot.user(["mv", append_path + "_", apkbuild_path], chroot) pmb.chroot.user(["mv", append_path + "_", apkbuild_path], chroot)
def mount_pmaports(destination, chroot: Chroot=Chroot.native()): def mount_pmaports(chroot: Chroot=Chroot.native()) -> Dict[str, Path]:
""" """
Mount pmaports.git in chroot. Mount pmaports.git in chroot.
:param destination: mount point inside the chroot :param chroot: chroot to target
:returns: Dictionary mapping pkgrepo name to dest path
""" """
outside_destination = chroot / destination dest_paths = {}
pmb.helpers.mount.bind(get_context().config.aports, outside_destination, umount=True) for repo in pkgrepo_paths(skip_extras=True):
destination = Path("/mnt") / repo.name
outside_destination = chroot / destination
pmb.helpers.mount.bind(repo, outside_destination, umount=True)
dest_paths[repo.name] = destination
return dest_paths
def link_to_git_dir(suffix): def link_to_git_dir(suffix):
""" 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
@ -368,13 +375,12 @@ def link_to_git_dir(suffix):
# initialization of the chroot, because the pmaports dir may not exist yet # initialization of the chroot, because the pmaports dir may not exist yet
# at that point. Use umount=True, so we don't have an old path mounted # at that point. Use umount=True, so we don't have an old path mounted
# (some tests change the pmaports dir). # (some tests change the pmaports dir).
destination = "/mnt/pmaports" dest_paths = mount_pmaports(chroot)
mount_pmaports(destination, suffix)
# Create .git symlink # Create .git symlink
pmb.chroot.user(["mkdir", "-p", "/home/pmos/build"], suffix) pmb.chroot.user(["mkdir", "-p", "/home/pmos/build"], chroot)
pmb.chroot.user(["ln", "-sf", destination + "/.git", pmb.chroot.user(["ln", "-sf", dest_paths["pmaports"] / ".git",
"/home/pmos/build/.git"], suffix) "/home/pmos/build/.git"], chroot)
def run_abuild(context: Context, apkbuild, arch, strict=False, force=False, cross=None, def run_abuild(context: Context, apkbuild, arch, strict=False, force=False, cross=None,

View file

@ -1,6 +1,7 @@
# 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 pmb.core.pkgrepo import pkgrepo_default_path
from pmb.helpers import logging from pmb.helpers import logging
from pathlib import Path from pathlib import Path
import pmb.chroot import pmb.chroot
@ -12,7 +13,7 @@ import pmb.build
from pmb.core import Chroot, get_context from pmb.core import Chroot, get_context
def newapkbuild(args: PmbArgs, folder, args_passed, force=False): def newapkbuild(folder, args_passed, force=False):
# Initialize build environment and build folder # Initialize build environment and build folder
pmb.build.init() pmb.build.init()
build = Path("/home/pmos/build") build = Path("/home/pmos/build")
@ -30,7 +31,7 @@ def newapkbuild(args: PmbArgs, folder, args_passed, force=False):
# Paths for copying # Paths for copying
source_apkbuild = glob_result[0] source_apkbuild = glob_result[0]
pkgname = pmb.parse.apkbuild(source_apkbuild, False)["pkgname"] pkgname = pmb.parse.apkbuild(source_apkbuild, False)["pkgname"]
target = get_context().config.aports / folder / pkgname target = pkgrepo_default_path() / folder / pkgname
# Move /home/pmos/build/$pkgname/* to /home/pmos/build/* # Move /home/pmos/build/$pkgname/* to /home/pmos/build/*
for path in build_outside.glob("/*/*"): for path in build_outside.glob("/*/*"):

View file

@ -2,6 +2,6 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from pmb.chroot.init import init, init_keys, UsrMerge from pmb.chroot.init import init, init_keys, UsrMerge
from pmb.chroot.mount import mount, mount_native_into_foreign, remove_mnt_pmbootstrap from pmb.chroot.mount import mount, mount_native_into_foreign, remove_mnt_pmbootstrap
from pmb.chroot.run import root, user, exists as user_exists from pmb.chroot.run import root, rootm, user, exists as user_exists
from pmb.chroot.shutdown import shutdown from pmb.chroot.shutdown import shutdown
from pmb.chroot.zap import zap from pmb.chroot.zap import zap

View file

@ -2,6 +2,7 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import os import os
import glob import glob
from pmb.core.pkgrepo import pkgrepo_iglob
from pmb.helpers import logging from pmb.helpers import logging
import pmb.config import pmb.config
@ -25,7 +26,7 @@ def list_chroot(suffix: Chroot, remove_prefix=True):
def list_aports(): def list_aports():
ret = [] ret = []
prefix = pmb.config.initfs_hook_prefix prefix = pmb.config.initfs_hook_prefix
for path in glob.glob(f"{get_context().config.aports}/*/{prefix}*"): for path in pkgrepo_iglob(f"*/{prefix}*"):
ret.append(os.path.basename(path)[len(prefix):]) ret.append(os.path.basename(path)[len(prefix):])
return ret return ret

View file

@ -194,7 +194,7 @@ chroot_mount_bind = {
"$WORK/config_apk_keys": "/etc/apk/keys", "$WORK/config_apk_keys": "/etc/apk/keys",
"$WORK/cache_sccache": "/mnt/pmbootstrap/sccache", "$WORK/cache_sccache": "/mnt/pmbootstrap/sccache",
"$WORK/images_netboot": "/mnt/pmbootstrap/netboot", "$WORK/images_netboot": "/mnt/pmbootstrap/netboot",
"$WORK/packages/$CHANNEL": "/mnt/pmbootstrap/packages", "$WORK/packages/": "/mnt/pmbootstrap/packages",
} }
# Building chroots (all chroots, except for the rootfs_ chroot) get symlinks in # Building chroots (all chroots, except for the rootfs_ chroot) get symlinks in
@ -214,7 +214,7 @@ chroot_home_symlinks = {
"/mnt/pmbootstrap/ccache": "/home/pmos/.ccache", "/mnt/pmbootstrap/ccache": "/home/pmos/.ccache",
"/mnt/pmbootstrap/go/gocache": "/home/pmos/.cache/go-build", "/mnt/pmbootstrap/go/gocache": "/home/pmos/.cache/go-build",
"/mnt/pmbootstrap/go/gomodcache": "/home/pmos/go/pkg/mod", "/mnt/pmbootstrap/go/gomodcache": "/home/pmos/go/pkg/mod",
"/mnt/pmbootstrap/packages": "/home/pmos/packages/pmos", #"/mnt/pmbootstrap/packages": "/home/pmos/packages/pmos",
"/mnt/pmbootstrap/rust/git/db": "/home/pmos/.cargo/git/db", "/mnt/pmbootstrap/rust/git/db": "/home/pmos/.cargo/git/db",
"/mnt/pmbootstrap/rust/registry/cache": "/home/pmos/.cargo/registry/cache", "/mnt/pmbootstrap/rust/registry/cache": "/home/pmos/.cargo/registry/cache",
"/mnt/pmbootstrap/rust/registry/index": "/home/pmos/.cargo/registry/index", "/mnt/pmbootstrap/rust/registry/index": "/home/pmos/.cargo/registry/index",

View file

@ -2,8 +2,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import configparser import configparser
from pathlib import Path from pathlib import Path
from pmb.core import get_context from typing import List, Optional
from pmb.core.pkgrepo import pkgrepo_default_path from pmb.core.pkgrepo import pkgrepo_default_path, pkgrepo_paths, pkgrepo_relative_path
from pmb.helpers import logging from pmb.helpers import logging
import os import os
import sys import sys
@ -81,14 +81,28 @@ def read_config_repos():
return ret return ret
def read_config(): def read_config(aports: Optional[Path] = None):
"""Read and verify pmaports.cfg.""" """Read and verify pmaports.cfg."""
if not aports:
aports = pkgrepo_default_path()
name = aports.name
if support_systemd and aports.name == "systemd":
name = f"systemd-{aports.name}"
# Try cache first # Try cache first
cache_key = "pmb.config.pmaports.read_config" cache_key = "pmb.config.pmaports.read_config"
if pmb.helpers.other.cache[cache_key]: if support_systemd and aports.name in pmb.helpers.other.cache[cache_key]:
return pmb.helpers.other.cache[cache_key] return pmb.helpers.other.cache[cache_key][name]
systemd = aports.name == "systemd"
# extra-repos don't have a pmaports.cfg
# so jump up the main aports dir
if "extra-repos" in aports.parts:
aports = pkgrepo_relative_path(aports)[0]
# Try cache first
cache_key = "pmb.config.pmaports.read_config"
if aports.name in pmb.helpers.other.cache[cache_key]:
return pmb.helpers.other.cache[cache_key][aports.name]
aports = pkgrepo_default_path()
# Migration message # Migration message
if not os.path.exists(aports): if not os.path.exists(aports):
logging.error(f"ERROR: pmaports dir not found: {aports}") logging.error(f"ERROR: pmaports dir not found: {aports}")
@ -113,8 +127,26 @@ def read_config():
# Translate legacy channel names # Translate legacy channel names
ret["channel"] = pmb.helpers.pmaports.get_channel_new(ret["channel"]) ret["channel"] = pmb.helpers.pmaports.get_channel_new(ret["channel"])
if "systemd" in name:
ret["channel"] = "systemd-" + ret["channel"]
# Cache and return # Cache and return
pmb.helpers.other.cache[cache_key] = ret pmb.helpers.other.cache[cache_key][name] = ret
return ret
def all_channels() -> List[str]:
"""Get a list of all channels for all pkgrepos."""
ret = []
for repo in pkgrepo_paths():
if repo.name == "systemd":
channel = "systemd"
else:
channel = read_config(repo)["channel"]
if channel not in ret:
ret.append(channel)
return ret return ret

View file

@ -8,6 +8,7 @@ from pathlib import Path
import sys import sys
import pmb.config import pmb.config
from pmb.core.context import Context from pmb.core.context import Context
from pmb.core.pkgrepo import pkgrepo_default_path
from pmb.types import PmbArgs from pmb.types import PmbArgs
import pmb.helpers.git import pmb.helpers.git
import pmb.helpers.args import pmb.helpers.args
@ -97,7 +98,7 @@ def init(args: PmbArgs) -> PmbArgs:
if args.action not in ["init", "checksum", "config", "bootimg_analyze", "log", if args.action not in ["init", "checksum", "config", "bootimg_analyze", "log",
"pull", "shutdown", "zap"]: "pull", "shutdown", "zap"]:
pmb.config.pmaports.read_config() pmb.config.pmaports.read_config()
pmb.helpers.git.parse_channels_cfg(config.aports) pmb.helpers.git.parse_channels_cfg(pkgrepo_default_path())
deviceinfo = pmb.parse.deviceinfo() deviceinfo = pmb.parse.deviceinfo()
context.device_arch = deviceinfo.arch context.device_arch = deviceinfo.arch

View file

@ -4,6 +4,7 @@ import os
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from pmb.core import get_context from pmb.core import get_context
from pmb.core.pkgrepo import pkgrepo_glob_one, pkgrepo_iglob
def find_path(codename: str, file='') -> Optional[Path]: def find_path(codename: str, file='') -> Optional[Path]:
@ -13,18 +14,14 @@ def find_path(codename: str, file='') -> Optional[Path]:
:param file: file to look for (e.g. APKBUILD or deviceinfo), may be empty :param file: file to look for (e.g. APKBUILD or deviceinfo), may be empty
:returns: path to APKBUILD :returns: path to APKBUILD
""" """
g = list((get_context().config.aports / "device").glob(f"*/device-{codename}/{file}")) g = pkgrepo_glob_one(f"device/*/device-{codename}/{file}")
if not g: if not g:
return None return None
if len(g) != 1: return g
raise RuntimeError(codename + " found multiple times in the device"
" subdirectory of pmaports")
return g[0]
def list_codenames(aports: Path, vendor=None, archived=True): def list_codenames(vendor=None, archived=True):
"""Get all devices, for which aports are available. """Get all devices, for which aports are available.
:param vendor: vendor name to choose devices from, or None for all vendors :param vendor: vendor name to choose devices from, or None for all vendors
@ -32,7 +29,7 @@ def list_codenames(aports: Path, vendor=None, archived=True):
:returns: ["first-device", "second-device", ...] :returns: ["first-device", "second-device", ...]
""" """
ret = [] ret = []
for path in aports.glob("device/*/device-*"): for path in pkgrepo_iglob("device/*/device-*"):
if not archived and 'archived' in path.parts: if not archived and 'archived' in path.parts:
continue continue
device = os.path.basename(path).split("-", 1)[1] device = os.path.basename(path).split("-", 1)[1]
@ -41,13 +38,13 @@ def list_codenames(aports: Path, vendor=None, archived=True):
return ret return ret
def list_vendors(aports: Path): def list_vendors():
"""Get all device vendors, for which aports are available. """Get all device vendors, for which aports are available.
:returns: {"vendor1", "vendor2", ...} :returns: {"vendor1", "vendor2", ...}
""" """
ret = set() ret = set()
for path in (aports / "device").glob("*/device-*"): for path in pkgrepo_iglob("device/*/device-*"):
vendor = path.name.split("-", 2)[1] vendor = path.name.split("-", 2)[1]
ret.add(vendor) ret.add(vendor)
return ret return ret

View file

@ -404,7 +404,7 @@ def newapkbuild(args: PmbArgs):
# Passthrough: PKGNAME[-PKGVER] | SRCURL # Passthrough: PKGNAME[-PKGVER] | SRCURL
pass_through.append(args.pkgname_pkgver_srcurl) pass_through.append(args.pkgname_pkgver_srcurl)
pmb.build.newapkbuild(args, args.folder, pass_through, args.force) pmb.build.newapkbuild(args.folder, pass_through, args.force)
def kconfig(args: PmbArgs): def kconfig(args: PmbArgs):
@ -474,7 +474,7 @@ def deviceinfo_parse(args: PmbArgs):
# Default to all devices # Default to all devices
devices = args.devices devices = args.devices
if not devices: if not devices:
devices = pmb.helpers.devices.list_codenames(get_context().config.aports) devices = pmb.helpers.devices.list_codenames()
# Iterate over all devices # Iterate over all devices
kernel = args.deviceinfo_parse_kernel kernel = args.deviceinfo_parse_kernel

View file

@ -5,6 +5,7 @@ from pathlib import Path
from typing import Dict from typing import Dict
from pmb.core import get_context from pmb.core import get_context
from pmb.core.context import Context from pmb.core.context import Context
from pmb.core.pkgrepo import pkgrepo_path
from pmb.helpers import logging from pmb.helpers import logging
import os import os
from pathlib import Path from pathlib import Path
@ -23,9 +24,9 @@ def get_path(name_repo: str):
:returns: full path to repository :returns: full path to repository
""" """
if name_repo == "pmaports": if name_repo == "aports_upstream":
return get_context().config.aports return get_context().config.work / "cache_git" / name_repo
return get_context().config.work / "cache_git" / name_repo return pkgrepo_path(name_repo)
def clone(name_repo): def clone(name_repo):

View file

@ -1,7 +1,9 @@
# Copyright 2023 Danct12 <danct12@disroot.org> # Copyright 2023 Danct12 <danct12@disroot.org>
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from pathlib import Path from pathlib import Path
from typing import Dict, List
from pmb.core.chroot import Chroot from pmb.core.chroot import Chroot
from pmb.core.pkgrepo import pkgrepo_iter_package_dirs, pkgrepo_names, pkgrepo_relative_path
from pmb.helpers import logging from pmb.helpers import logging
import os import os
@ -13,7 +15,7 @@ import pmb.helpers.run
import pmb.helpers.pmaports import pmb.helpers.pmaports
def check(args: PmbArgs, pkgnames): def check(args: PmbArgs, pkgnames: List[str]):
"""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
@ -23,18 +25,27 @@ def check(args: PmbArgs, pkgnames):
# Mount pmaports.git inside the chroot so that we don't have to copy the # Mount pmaports.git inside the chroot so that we don't have to copy the
# package folders # package folders
pmaports = Path("/mnt/pmaports") dest_paths = pmb.build.mount_pmaports(chroot)
pmb.build.mount_pmaports(pmaports, chroot)
# Locate all APKBUILDs and make the paths be relative to the pmaports # Locate all APKBUILDs and make the paths be relative to the pmaports
# root # root
apkbuilds = [] apkbuilds: Dict[str, List[str]] = dict(map(lambda x: (x, []), pkgrepo_names()))
for pkgname in pkgnames: found_pkgnames = set()
aport = pmb.helpers.pmaports.find(pkgname) # If a package exists in multiple aports we will lint all of them
if not (aport / "APKBUILD").exists(): # since.. well, what else do we do?
raise ValueError(f"Path does not contain an APKBUILD file: {aport}") for pkgdir in pkgrepo_iter_package_dirs():
relpath = os.path.relpath(aport, args.aports) if pkgdir.name not in pkgnames:
apkbuilds.append(f"{relpath}/APKBUILD") continue
repo, relpath = pkgrepo_relative_path(pkgdir)
apkbuilds[repo.name].append(os.fspath(relpath / "APKBUILD"))
found_pkgnames.add(pkgdir.name)
# Check we found all the packages in pkgnames
if len(found_pkgnames) != len(pkgnames):
missing = set(pkgnames) - found_pkgnames
logging.error(f"Could not find the following packages: {missing}")
return
# Run apkbuild-lint in chroot from the pmaports mount point. This will # Run apkbuild-lint in chroot from the pmaports mount point. This will
# print a nice source identifier à la "./cross/grub-x86/APKBUILD" for # print a nice source identifier à la "./cross/grub-x86/APKBUILD" for
@ -42,8 +53,11 @@ def check(args: PmbArgs, pkgnames):
pkgstr = ", ".join(pkgnames) pkgstr = ", ".join(pkgnames)
logging.info(f"(native) linting {pkgstr} with apkbuild-lint") logging.info(f"(native) linting {pkgstr} with apkbuild-lint")
options = pmb.config.apkbuild_custom_valid_options options = pmb.config.apkbuild_custom_valid_options
return pmb.chroot.root(["apkbuild-lint"] + apkbuilds,
check=False, output="stdout", # For each pkgrepo run the linter on the relevant packages
output_return=True, for repo, apkbuild_paths in apkbuilds.items():
working_dir=pmaports, pmb.chroot.root(["apkbuild-lint"] + apkbuild_paths,
env={"CUSTOM_VALID_OPTIONS": " ".join(options)}) check=False, output="stdout",
output_return=True,
working_dir=dest_paths[repo],
env={"CUSTOM_VALID_OPTIONS": " ".join(options)})

View file

@ -36,8 +36,6 @@ def bind(source: Path, destination: Path, create_folders=True, umount=False):
umount_all(destination) umount_all(destination)
else: else:
return return
print(f"Mounting {source} -> {destination}")
# Check/create folders # Check/create folders
for path in [source, destination]: for path in [source, destination]:

View file

@ -297,7 +297,8 @@ cache: Dict[str, Any] = {
"pmb.helpers.package.get": {}, "pmb.helpers.package.get": {},
"pmb.helpers.repo.update": {"404": [], "offline_msg_shown": False}, "pmb.helpers.repo.update": {"404": [], "offline_msg_shown": False},
"pmb.helpers.git.parse_channels_cfg": {}, "pmb.helpers.git.parse_channels_cfg": {},
"pmb.config.pmaports.read_config": None, "pmb.config.pmaports.read_config": {},
"pmb.config.pmaports.read_config_repos": None, "pmb.config.pmaports.read_config_repos": None,
"pmb.chroot.init": {}, "pmb.chroot.init": {},
"pkgrepo_paths": [],
} }

View file

@ -8,14 +8,14 @@ See also:
""" """
import glob import glob
from pmb.core import get_context from pmb.core import get_context
from pmb.core.pkgrepo import pkgrepo_iter_package_dirs
from pmb.helpers import logging from pmb.helpers import logging
from pathlib import Path from pathlib import Path
from typing import Optional, Sequence, Dict from typing import Any, Optional, Sequence, Dict, Tuple
from pmb.types import PmbArgs
import pmb.parse import pmb.parse
def _find_apkbuilds() -> Dict[str, Path]: def _find_apkbuilds(skip_extra_repos=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")
@ -23,19 +23,20 @@ def _find_apkbuilds() -> Dict[str, Path]:
return apkbuilds return apkbuilds
apkbuilds = {} apkbuilds = {}
for apkbuild in glob.iglob(f"{get_context().config.aports}/**/*/APKBUILD", recursive=True): for package in pkgrepo_iter_package_dirs(skip_extra_repos=skip_extra_repos):
package = Path(apkbuild).parent.name pkgname = package.name
if package in apkbuilds: if pkgname in apkbuilds:
raise RuntimeError(f"Package {package} found in multiple aports " raise RuntimeError(f"Package {pkgname} found in multiple aports "
"subfolders. Please put it only in one folder.") "subfolders. Please put it only in one folder.")
apkbuilds[package] = Path(apkbuild) apkbuilds[pkgname] = package / "APKBUILD"
# Sort dictionary so we don't need to do it over and over again in # Sort dictionary so we don't need to do it over and over again in
# get_list() # get_list()
apkbuilds = dict(sorted(apkbuilds.items())) apkbuilds = dict(sorted(apkbuilds.items()))
# Save result in cache # Save result in cache
pmb.helpers.other.cache["pmb.helpers.pmaports.apkbuilds"] = apkbuilds if not skip_extra_repos:
pmb.helpers.other.cache["pmb.helpers.pmaports.apkbuilds"] = apkbuilds
return apkbuilds return apkbuilds
@ -137,7 +138,7 @@ def _find_package_in_apkbuild(package: str, path: Path) -> bool:
return False return False
def find(package, must_exist=True, subpackages=True): def find(package, must_exist=True, subpackages=True, skip_extra_repos=False):
"""Find the directory in pmaports that provides a package or subpackage. """Find the directory in pmaports that provides a package or subpackage.
If you want the parsed APKBUILD instead, use pmb.helpers.pmaports.get(). If you want the parsed APKBUILD instead, use pmb.helpers.pmaports.get().
@ -161,7 +162,7 @@ def find(package, must_exist=True, subpackages=True):
raise RuntimeError("Invalid pkgname: " + package) raise RuntimeError("Invalid pkgname: " + package)
# Try to find an APKBUILD with the exact pkgname we are looking for # Try to find an APKBUILD with the exact pkgname we are looking for
path = _find_apkbuilds().get(package) path = _find_apkbuilds(skip_extra_repos).get(package)
if path: if path:
ret = path.parent ret = path.parent
elif subpackages: elif subpackages:
@ -188,12 +189,12 @@ def find(package, must_exist=True, subpackages=True):
ret = guess ret = guess
# Crash when necessary # Crash when necessary
if ret is None: if ret is None and must_exist:
raise RuntimeError("Could not find aport for package: " + raise RuntimeError("Could not find aport for package: " +
package) package)
# Save result in cache (only if subpackage search was enabled) # Save result in cache (only if subpackage search was enabled)
if subpackages: if subpackages and not skip_extra_repos:
pmb.helpers.other.cache["find_aport"][package] = ret pmb.helpers.other.cache["find_aport"][package] = ret
return ret return ret
@ -206,7 +207,7 @@ def find_optional(package: str) -> Optional[Path]:
return None return None
def get(pkgname, must_exist=True, subpackages=True): def get_with_path(pkgname, must_exist=True, subpackages=True, skip_extra_repos=False) -> Tuple[Optional[Path], Optional[Dict[str, Any]]]:
"""Find and parse an APKBUILD file. """Find and parse an APKBUILD file.
Run 'pmbootstrap apkbuild_parse hello-world' for a full output example. Run 'pmbootstrap apkbuild_parse hello-world' for a full output example.
@ -216,6 +217,8 @@ def get(pkgname, must_exist=True, subpackages=True):
:param must_exist: raise an exception when it can't be found :param must_exist: raise an exception when it can't be found
:param subpackages: also search for subpackages with the specified :param subpackages: also search for subpackages with the specified
names (slow! might need to parse all APKBUILDs to find it) names (slow! might need to parse all APKBUILDs to find it)
:param skip_extra_repos: skip extra repositories (e.g. systemd) when
searching for the package
:returns: relevant variables from the APKBUILD as dictionary, e.g.: :returns: relevant variables from the APKBUILD as dictionary, e.g.:
{ "pkgname": "hello-world", { "pkgname": "hello-world",
@ -226,10 +229,14 @@ def get(pkgname, must_exist=True, subpackages=True):
... } ... }
""" """
pkgname = pmb.helpers.package.remove_operators(pkgname) pkgname = pmb.helpers.package.remove_operators(pkgname)
pmaport = find(pkgname, must_exist, subpackages) pmaport = find(pkgname, must_exist, subpackages, skip_extra_repos)
if pmaport: if pmaport:
return pmb.parse.apkbuild(pmaport / "APKBUILD") return pmaport, pmb.parse.apkbuild(pmaport / "APKBUILD")
return None return None, None
def get(pkgname, must_exist=True, subpackages=True, skip_extra_repos=False) -> Optional[Dict[str, Any]]:
return get_with_path(pkgname, must_exist, subpackages, skip_extra_repos)[1]
def find_providers( provide): def find_providers( provide):

View file

@ -10,6 +10,7 @@ See also:
import os import os
import hashlib import hashlib
from pmb.core import get_context from pmb.core import get_context
from pmb.core.pkgrepo import pkgrepo_paths
from pmb.helpers import logging from pmb.helpers import logging
from pathlib import Path from pathlib import Path
from typing import List from typing import List
@ -70,7 +71,8 @@ def urls(user_repository=True, postmarketos_mirror=True, alpine=True):
if user_repository: if user_repository:
channel = pmb.config.pmaports.read_config()["channel"] channel = pmb.config.pmaports.read_config()["channel"]
# FIXME: We shouldn't hardcod this here # FIXME: We shouldn't hardcod this here
ret.append("/mnt/pmbootstrap/packages") for channel in pmb.config.pmaports.all_channels():
ret.append(f"/mnt/pmbootstrap/packages/{channel}")
# Upstream postmarketOS binary repository # Upstream postmarketOS binary repository
if postmarketos_mirror: if postmarketos_mirror:
@ -112,8 +114,8 @@ def apkindex_files(arch=None, user_repository=True, pmos=True,
ret = [] ret = []
# Local user repository (for packages compiled with pmbootstrap) # Local user repository (for packages compiled with pmbootstrap)
if user_repository: if user_repository:
channel = pmb.config.pmaports.read_config()["channel"] for channel in pmb.config.pmaports.all_channels():
ret = [get_context().config.work / "packages" / channel / arch / "APKINDEX.tar.gz"] ret.append(get_context().config.work / "packages" / channel / arch / "APKINDEX.tar.gz")
# Resolve the APKINDEX.$HASH.tar.gz files # Resolve the APKINDEX.$HASH.tar.gz files
for url in urls(False, pmos, alpine): for url in urls(False, pmos, alpine):

View file

@ -3,7 +3,7 @@
import os import os
import glob import glob
from pmb.core import get_context from pmb.core import get_context
from pmb.types import PmbArgs from pmb.core.pkgrepo import pkgrepo_iglob
import pmb.helpers.pmaports import pmb.helpers.pmaports
import pmb.helpers.package import pmb.helpers.package
import pmb.parse import pmb.parse
@ -18,8 +18,7 @@ def list_ui(arch):
ret = [("none", "Bare minimum OS image for testing and manual" ret = [("none", "Bare minimum OS image for testing and manual"
" customization. The \"console\" UI should be selected if" " customization. The \"console\" UI should be selected if"
" a graphical UI is not desired.")] " a graphical UI is not desired.")]
context = get_context() # noqa: F821 for path in sorted(pkgrepo_iglob("main/postmarketos-ui-*")):
for path in sorted(context.config.aports.glob("main/postmarketos-ui-*")):
apkbuild = pmb.parse.apkbuild(path) apkbuild = pmb.parse.apkbuild(path)
ui = os.path.basename(path).split("-", 2)[2] ui = os.path.basename(path).split("-", 2)[2]
if pmb.helpers.package.check_arch(apkbuild["pkgname"], arch): if pmb.helpers.package.check_arch(apkbuild["pkgname"], arch):
@ -27,10 +26,10 @@ def list_ui(arch):
return ret return ret
def check_option(ui, option): def check_option(ui, option, skip_extra_repos=False):
""" """
Check if an option, such as pmb:systemd, is inside an UI's APKBUILD. Check if an option, such as pmb:systemd, is inside an UI's APKBUILD.
""" """
pkgname = f"postmarketos-ui-{ui}" pkgname = f"postmarketos-ui-{ui}"
apkbuild = pmb.helpers.pmaports.get(pkgname, subpackages=False) apkbuild = pmb.helpers.pmaports.get(pkgname, subpackages=False, skip_extra_repos=skip_extra_repos)
return option in apkbuild["options"] return option in apkbuild["options"]

View file

@ -156,8 +156,8 @@ class PmbArgs(Namespace):
class Config(): class Config():
aports: Path = Path(os.path.expanduser("~") + aports: List[Path] = [Path(os.path.expanduser("~") +
"/.local/var/pmbootstrap/cache_git/pmaports") "/.local/var/pmbootstrap/cache_git/pmaports")]
boot_size: int = 256 boot_size: int = 256
build_default_device_arch: bool = False build_default_device_arch: bool = False
build_pkgs_on_install: bool = True build_pkgs_on_install: bool = True