From ba6bb4272d9d1194bff20a55c2e40cf9f5bd2b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Correa=20G=C3=B3mez?= Date: Sun, 11 May 2025 15:59:23 +0200 Subject: [PATCH] pmb.parse.apkindex: account for provider_priority when locating packages This fixes an issue where the local apk index has two packages in it that provide the same thing, but this function was returning only the one with the shortest name... which could be very bad :) https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/6475#note_480167 In the process, add tests for pmb.parse.apkindex.package function. Some of the tests would fail without this patch, surfacing a bug where priorities are not considered, but should, and that we are now fixing. Co-authored-by: Clayton Craft Part-of: https://gitlab.postmarketos.org/postmarketOS/pmbootstrap/-/merge_requests/2594 --- pmb/parse/apkindex.py | 10 ++++ test/parse/test_apkindex.py | 113 +++++++++++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 1 deletion(-) diff --git a/pmb/parse/apkindex.py b/pmb/parse/apkindex.py index 52e8fe71..3aacd78f 100644 --- a/pmb/parse/apkindex.py +++ b/pmb/parse/apkindex.py @@ -483,6 +483,16 @@ def package( if package in package_providers: return package_providers[package] + if package_providers: + providers_priority = provider_highest_priority(package_providers, package) + num_providers = len(providers_priority) + # Only one provider with max priority: return it + if num_providers == 1: + return next(iter(providers_priority.values())) + # Multiple providers with max priority: let follow-on logic decide + elif num_providers > 1: + package_providers = providers_priority + # Any provider if package_providers: return pmb.parse.apkindex.provider_shortest(package_providers, package) diff --git a/test/parse/test_apkindex.py b/test/parse/test_apkindex.py index 732dae00..f7486cdf 100644 --- a/test/parse/test_apkindex.py +++ b/test/parse/test_apkindex.py @@ -7,7 +7,11 @@ import pytest import pmb.parse.apkindex -from pmb.parse.apkindex import parse as parse_apkindex, clear_cache as clear_apkindex_cache +from pmb.parse.apkindex import ( + parse as parse_apkindex, + clear_cache as clear_apkindex_cache, + package as package_apkindex, +) example_apkindex = """ C:Q1p+nGf5oBAmbU9FQvV4MhfEmWqVE= @@ -443,3 +447,110 @@ def test_apkindex_parse_cache_hit(valid_apkindex_file, monkeypatch) -> None: with pytest.raises(AssertionError): parse_apkindex(valid_apkindex_file) + + +def test_apkindex_package(valid_apkindex_file) -> None: + index_block = package_apkindex( + "postmarketos-base-ui-networkmanager", arch=Arch.aarch64, indexes=[valid_apkindex_file] + ) + assert index_block.pkgname == "postmarketos-base-ui-networkmanager" + + index_block = package_apkindex( + "postmarketos-base-ui-wifi", arch=Arch.aarch64, indexes=[valid_apkindex_file] + ) + assert index_block.pkgname == "postmarketos-base-ui-wifi-wpa_supplicant" + + +def test_apkindex_package_provider_priority(tmp_path) -> None: + tmpfile = tmp_path / "APKINDEX.5" + f = open(tmpfile, "w") + # A snippet of the above example but with a missing timestamp + # and origin fields + f.write( + """ +C:Q1yB3CVUFMOjnLOOEAUIUUpJJV8g0= +P:postmarketos-base-short +V:20-r0 +A:aarch64 +S:1587 +I:22 +T:openrc config for postmarketOS +U:https://postmarketos.org +L:GPL-3.0-or-later +o:postmarketos-base +m:Clayton Craft +t:1729538699 +c:901cb9520450a1e88ded95ac774e83f6b2cfbba3-dirty +D:!systemd alpine-conf busybox-mdev-openrc busybox-openrc openrc +p:postmarketos-base-init +k:10 + +C:Q1yB3CVUFMOjnLOOEAUIUUpJJV8g0= +P:postmarketos-base-loooooooooong +V:22-r0 +A:aarch64 +S:1587 +I:22 +T:systemd base config for postmarketOS +U:https://postmarketos.org +L:GPL-3.0-or-later +o:postmarketos-base-systemd +m:Clayton Craft +t:1729538699 +c:901cb9520450a1e88ded95ac774e83f6b2cfbba3-dirty +D:kbd kmod less login-utils systemd systemd-services systemd-timesyncd tzdata +p:postmarketos-base-init +k:100 +""" + ) + f.close() + + index_block = package_apkindex("postmarketos-base-init", arch=Arch.aarch64, indexes=[tmpfile]) + assert index_block.pkgname == "postmarketos-base-loooooooooong" + assert index_block.origin == "postmarketos-base-systemd" + assert index_block.provides == ["postmarketos-base-init"] + + +def test_apkindex_package_provider_shortest(tmp_path) -> None: + tmpfile = tmp_path / "APKINDEX.6" + f = open(tmpfile, "w") + # A snippet of the above example but with a missing timestamp + # and origin fields + f.write( + """ +C:Q1yB3CVUFMOjnLOOEAUIUUpJJV8g0= +P:mesa-egl +V:20-r0 +A:aarch64 +S:1587 +I:22 +T:mesa package +U:https://postmarketos.org +L:GPL-3.0-or-later +o:mesa +m:Clayton Craft +t:1729538699 +c:901cb9520450a1e88ded95ac774e83f6b2cfbba3-dirty +p:so:libGL.so.1=20-r0 + +C:Q1yB3CVUFMOjnLOOEAUIUUpJJV8g0= +P:mesa-purism-gc7000-egl +V:22-r0 +A:aarch64 +S:1587 +I:22 +T:mesa fork for Purism +U:https://postmarketos.org +L:GPL-3.0-or-later +o:mesa-purism-gc7000 +m:Clayton Craft +t:1729538699 +c:901cb9520450a1e88ded95ac774e83f6b2cfbba3-dirty +p:so:libGL.so.1=22-r0 +""" + ) + f.close() + + index_block = package_apkindex("so:libGL.so.1", arch=Arch.aarch64, indexes=[tmpfile]) + assert index_block.pkgname == "mesa-egl" + assert index_block.origin == "mesa"