pmb.install: support pmb_recommends for any package

This refactors the get_recommends function that was originally used for
UI packages to support pmb_recommends for any package (and subpackage).

Extending pmb_recommends will, for example, help us create better
generic device packages [1] and can be used to improve packaging for UIs
with shared pmb_recommends[2].

1. https://gitlab.com/postmarketOS/pmaports/-/merge_requests/4673
2. https://gitlab.com/postmarketOS/pmaports/-/merge_requests/3700

Reviewed-by: Oliver Smith <ollieparanoid@postmarketos.org>
Link: https://lists.sr.ht/~postmarketos/pmbootstrap-devel/%3C20240102074605.23248-2-clayton@craftyguy.net%3E
This commit is contained in:
Clayton Craft 2024-01-01 23:46:05 -08:00 committed by Oliver Smith
parent 0c0f05caab
commit 19f8a3b8c8
No known key found for this signature in database
GPG key ID: 5AE7F5513E0885CB
6 changed files with 77 additions and 58 deletions

View file

@ -696,9 +696,9 @@ apkbuild_package_attributes = {
"install": {"array": True}, "install": {"array": True},
"triggers": {"array": True}, "triggers": {"array": True},
# UI meta-packages can specify apps in "_pmb_recommends" to be explicitly # Packages can specify soft dependencies in "_pmb_recommends" to be
# installed by default, and not implicitly as dependency of the UI meta- # explicitly installed by default, and not implicitly as a hard dependency
# package ("depends"). This makes these apps uninstallable, without # of the package ("depends"). This makes these apps uninstallable, without
# removing the meta-package. (#1933). To disable this feature, use: # removing the meta-package. (#1933). To disable this feature, use:
# "pmbootstrap install --no-recommends". # "pmbootstrap install --no-recommends".
"_pmb_recommends": {"array": True}, "_pmb_recommends": {"array": True},

View file

@ -1068,6 +1068,50 @@ def get_selected_providers(args, packages):
return providers return providers
def get_recommends(args, packages):
"""
Look through the specified packages and collect additional packages
specified under _pmb_recommends in them. This is recursive, so it will
dive into packages that are listed under recommends to collect any
packages they might also have listed under their own _pmb_recommends.
If unable to find a given package in aports, it is skipped and no error
is raised. This is because the given package might be in a different
aports than the one searched by this function. This function makes no
attempt to validate that a given package is in *any* available aports
repos at installation time.
If running with pmbootstrap install --no-recommends, this function
returns an empty list.
:returns: list of pkgnames, e.g. ["chatty", "gnome-contacts"] """
ret = []
if not args.install_recommends:
return ret
for package in packages:
# Note that this ignores packages that don't exist. This means they
# aren't in pmaports. This is fine, with the assumption that
# installation will fail later in some other method if they truly don't
# exist in any repo.
apkbuild = pmb.helpers.pmaports.get(args, package, must_exist=False)
if not apkbuild:
continue
if package in apkbuild["subpackages"]:
# Just focus on the subpackage
apkbuild = apkbuild["subpackages"][package]
recommends = apkbuild["_pmb_recommends"]
if recommends:
logging.debug(f"{package}: install _pmb_recommends:"
f" {', '.join(recommends)}")
ret += recommends
# Call recursively in case recommends have pmb_recommends of their
# own.
ret += get_recommends(args, recommends)
return ret
def create_device_rootfs(args, step, steps): def create_device_rootfs(args, step, steps):
# 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
@ -1096,8 +1140,6 @@ def create_device_rootfs(args, step, steps):
if args.ui.lower() != "none": if args.ui.lower() != "none":
if args.ui_extras: if args.ui_extras:
install_packages += ["postmarketos-ui-" + args.ui + "-extras"] install_packages += ["postmarketos-ui-" + args.ui + "-extras"]
if args.install_recommends:
install_packages += pmb.install.ui.get_recommends(args)
if args.extra_packages.lower() != "none": if args.extra_packages.lower() != "none":
install_packages += args.extra_packages.split(",") install_packages += args.extra_packages.split(",")
if args.add: if args.add:
@ -1126,6 +1168,9 @@ def create_device_rootfs(args, step, steps):
pmb.helpers.repo.update(args, args.deviceinfo["arch"]) pmb.helpers.repo.update(args, args.deviceinfo["arch"])
# Install uninstallable "dependencies" by default
install_packages += get_recommends(args, install_packages)
# Explicitly call build on the install packages, to re-build them or any # Explicitly call build on the install packages, to re-build them or any
# dependency, in case the version increased # dependency, in case the version increased
if args.build_pkgs_on_install: if args.build_pkgs_on_install:

View file

@ -5,36 +5,6 @@ import logging
import pmb.helpers.pmaports import pmb.helpers.pmaports
def get_recommends(args):
""" Get all packages listed in _pmb_recommends of the UI and UI-extras
package, unless running with pmbootstrap install --no-recommends.
:returns: list of pkgnames, e.g. ["chatty", "gnome-contacts"] """
ret = []
if not args.install_recommends or args.ui == "none":
return ret
# UI package
meta = f"postmarketos-ui-{args.ui}"
apkbuild = pmb.helpers.pmaports.get(args, meta)
recommends = apkbuild["_pmb_recommends"]
if recommends:
logging.debug(f"{meta}: install _pmb_recommends:"
f" {', '.join(recommends)}")
ret += recommends
# UI-extras subpackage
meta_extras = f"{meta}-extras"
if args.ui_extras and meta_extras in apkbuild["subpackages"]:
recommends = apkbuild["subpackages"][meta_extras]["_pmb_recommends"]
if recommends:
logging.debug(f"{meta_extras}: install _pmb_recommends:"
f" {', '.join(recommends)}")
ret += recommends
return ret
def get_groups(args): def get_groups(args):
""" Get all groups to which the user additionally must be added. """ Get all groups to which the user additionally must be added.
The list of groups are listed in _pmb_groups of the UI and The list of groups are listed in _pmb_groups of the UI and

View file

@ -50,37 +50,33 @@ def test_get_nonfree_packages(args):
def test_get_recommends(args): def test_get_recommends(args):
args.aports = pmb_test.const.testdata + "/pmb_recommends" args.aports = pmb_test.const.testdata + "/pmb_recommends"
func = pmb.install.ui.get_recommends func = pmb.install._install.get_recommends
# UI: none # UI: none
args.install_recommends = True args.install_recommends = True
args.ui = "none" assert func(args, ["postmarketos-ui-none"]) == []
assert func(args) == []
# UI: test, --no-recommends # UI: test, --no-recommends
args.install_recommends = False args.install_recommends = False
args.ui = "test" assert func(args, ["postmarketos-ui-test"]) == []
assert func(args) == []
# UI: test, without -extras # UI: test
args.install_recommends = True
assert func(args, ["postmarketos-ui-test"]) == ["plasma-camera",
"plasma-angelfish"]
# UI: test + test-extras
args.install_recommends = True
assert func(args, ["postmarketos-ui-test",
"postmarketos-ui-test-extras"]) == ["plasma-camera",
"plasma-angelfish",
"buho", "kaidan",
"test-app", "foot",
"htop"]
# Non-UI package
args.install_recommends = True args.install_recommends = True
args.ui = "test"
args.ui_extras = False args.ui_extras = False
assert func(args) == ["plasma-camera", "plasma-angelfish"] assert func(args, ["test-app"]) == ["foot", "htop"]
# UI: test, with -extras
args.install_recommends = True
args.ui = "test"
args.ui_extras = True
assert func(args) == ["plasma-camera", "plasma-angelfish", "buho",
"kaidan"]
# UI: invalid
args.install_recommends = True
args.ui = "invalid"
with pytest.raises(RuntimeError) as e:
func(args)
assert str(e.value).startswith("Could not find aport for package")
def test_get_groups(args): def test_get_groups(args):

View file

@ -9,5 +9,5 @@ arch="all"
_pmb_recommends="plasma-camera plasma-angelfish" _pmb_recommends="plasma-camera plasma-angelfish"
extras() { extras() {
_pmb_recommends="buho kaidan" _pmb_recommends="buho kaidan test-app"
} }

View file

@ -0,0 +1,8 @@
pkgname=test-app
pkgver=1
pkgrel=0
license="GPL-3.0-or-later"
depends=""
arch="all"
_pmb_recommends="foot htop"