pmb.parse: Respect provider_priority if multiple providers exist (MR 1945)
Alpine APKBUILDs have the concept of "provider priorities" that affect the choice of the provider to install when multiple packages provide a virtual package. One use case for this is to allow installation of different firmware versions. bq-paella can run unsigned firmware, therefore you have the choice between using the original firmware from the manufacturer, or a slightly newer version from Qualcomm for the Dragonboard 410c. We add provides="firmware-qcom-msm8916-wcnss" (the "virtual package") to both firmware-qcom-db410c-wcnss and firmware-bq-picmt-wcnss. At this point, attempting to install "firmware-qcom-msm8916-wcnss" would still fail with apk. (Because it does not know which provider to install.) To pick a default we can set e.g. provider_priority=100 for firmware-qcom-db410c-wcnss (the slightly newer version). In that case, firmware-qcom-db410c-wcnss should be installed by default. However, the user can choose to do "apk add firmware-bq-picmt-wcnss" to override the default choice in case of problems. In that case, the conflicting firmware-qcom-db410c-wcnss will be automatically removed. At the moment, pmbootstrap does not respect the "provider_priority" at all. In the above case, it would always install "firmware-bq-picmt-wcnss" during "pmbootstrap install" since that has the shortest name. Extend the pmbootstrap code to pick a provider with the highest priority (if any of the providers has a priority set).
This commit is contained in:
parent
6d013b4472
commit
3ebb994206
|
@ -42,6 +42,7 @@ def parse_next_block(args, path, lines, start):
|
|||
"o": "origin",
|
||||
"P": "pkgname",
|
||||
"p": "provides",
|
||||
"k": "provider_priority",
|
||||
"t": "timestamp",
|
||||
"V": "version",
|
||||
}
|
||||
|
@ -321,6 +322,32 @@ def providers(args, package, arch=None, must_exist=True, indexes=None):
|
|||
return ret
|
||||
|
||||
|
||||
def provider_highest_priority(providers, pkgname):
|
||||
"""
|
||||
Get the provider(s) with the highest provider_priority and log a message.
|
||||
|
||||
:param providers: returned dict from providers(), must not be empty
|
||||
:param pkgname: the package name we are interested in (for the log message)
|
||||
"""
|
||||
max_priority = 0
|
||||
priority_providers = collections.OrderedDict()
|
||||
for provider_name, provider in providers.items():
|
||||
priority = int(provider.get("provider_priority", -1))
|
||||
if priority > max_priority:
|
||||
priority_providers.clear()
|
||||
max_priority = priority
|
||||
if priority == max_priority:
|
||||
priority_providers[provider_name] = provider
|
||||
|
||||
if priority_providers:
|
||||
logging.debug(f"{pkgname}: picked provider(s) with higest priority {max_priority}: " +
|
||||
", ".join(priority_providers.keys()))
|
||||
return priority_providers
|
||||
|
||||
# None of the providers seems to have a provider_priority defined
|
||||
return providers
|
||||
|
||||
|
||||
def provider_shortest(providers, pkgname):
|
||||
"""
|
||||
Get the provider with the shortest pkgname and log a message. In most cases
|
||||
|
|
|
@ -73,7 +73,12 @@ def package_provider(args, pkgname, pkgnames_install, suffix="native"):
|
|||
" the '" + suffix + "' chroot already")
|
||||
return provider
|
||||
|
||||
# 5. Pick the provider
|
||||
# 5. Pick the provider(s) with the highest priority
|
||||
providers = pmb.parse.apkindex.provider_highest_priority(providers, pkgname)
|
||||
if len(providers) == 1:
|
||||
return list(providers.values())[0]
|
||||
|
||||
# 6. Pick the shortest provider. (Note: Normally apk would fail here!)
|
||||
return pmb.parse.apkindex.provider_shortest(providers, pkgname)
|
||||
|
||||
|
||||
|
|
|
@ -300,6 +300,43 @@ def test_providers_highest_version(args, monkeypatch):
|
|||
assert providers["test"]["version"] == "3"
|
||||
|
||||
|
||||
def test_provider_highest_priority(args, monkeypatch):
|
||||
# Verify that it picks the provider with highest priority
|
||||
func = pmb.parse.apkindex.provider_highest_priority
|
||||
|
||||
provider_none_a = {"pkgname": "a", "provides": ["test"]}
|
||||
provider_none_b = {"pkgname": "b", "provides": ["test"]}
|
||||
provider_low_c = {"pkgname": "c", "provides": ["test"],
|
||||
"provider_priority": 42}
|
||||
provider_low_d = {"pkgname": "d", "provides": ["test"],
|
||||
"provider_priority": 42}
|
||||
provider_high = {"pkgname": "e", "provides": ["test"],
|
||||
"provider_priority": 1337}
|
||||
|
||||
# No provider has a priority
|
||||
providers = {"a": provider_none_a}
|
||||
assert func(providers, "test") == providers
|
||||
providers = {"a": provider_none_a, "b": provider_none_b}
|
||||
assert func(providers, "test") == providers
|
||||
|
||||
# One provider has a priority, another one does not
|
||||
providers = {"a": provider_none_a, "e": provider_high}
|
||||
assert func(providers, "test") == {"e": provider_high}
|
||||
|
||||
# One provider has a priority, another one has a higher priority
|
||||
providers = {"c": provider_low_c, "e": provider_high}
|
||||
assert func(providers, "test") == {"e": provider_high}
|
||||
|
||||
# One provider has a priority, another one has the same priority
|
||||
providers = {"c": provider_low_c, "d": provider_low_d}
|
||||
assert func(providers, "test") == providers
|
||||
|
||||
# + some package without priority at all should be filtered out
|
||||
providers2 = providers.copy()
|
||||
providers2["a"] = provider_none_a
|
||||
assert func(providers2, "test") == providers
|
||||
|
||||
|
||||
def test_package(args, monkeypatch):
|
||||
# Override pmb.parse.apkindex.providers()
|
||||
providers = collections.OrderedDict()
|
||||
|
|
|
@ -72,7 +72,14 @@ def test_package_provider(args, monkeypatch):
|
|||
pkgnames_install = []
|
||||
assert func(args, pkgname, pkgnames_install) == package
|
||||
|
||||
# 5. Pick the first one
|
||||
# 5. Pick package with highest priority
|
||||
package_with_priority = {"pkgname": "test-priority", "provides": ["test"],
|
||||
"provider_priority": 100}
|
||||
providers = {"test-two": package_two, "test-priority": package_with_priority}
|
||||
assert func(args, pkgname, pkgnames_install) == package_with_priority
|
||||
|
||||
# 6. Pick the first one
|
||||
providers = {"test_": package, "test-two": package_two}
|
||||
installed = {}
|
||||
assert func(args, pkgname, pkgnames_install) == package
|
||||
|
||||
|
|
Loading…
Reference in New Issue