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",
|
"o": "origin",
|
||||||
"P": "pkgname",
|
"P": "pkgname",
|
||||||
"p": "provides",
|
"p": "provides",
|
||||||
|
"k": "provider_priority",
|
||||||
"t": "timestamp",
|
"t": "timestamp",
|
||||||
"V": "version",
|
"V": "version",
|
||||||
}
|
}
|
||||||
|
@ -321,6 +322,32 @@ def providers(args, package, arch=None, must_exist=True, indexes=None):
|
||||||
return ret
|
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):
|
def provider_shortest(providers, pkgname):
|
||||||
"""
|
"""
|
||||||
Get the provider with the shortest pkgname and log a message. In most cases
|
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")
|
" the '" + suffix + "' chroot already")
|
||||||
return provider
|
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)
|
return pmb.parse.apkindex.provider_shortest(providers, pkgname)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,43 @@ def test_providers_highest_version(args, monkeypatch):
|
||||||
assert providers["test"]["version"] == "3"
|
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):
|
def test_package(args, monkeypatch):
|
||||||
# Override pmb.parse.apkindex.providers()
|
# Override pmb.parse.apkindex.providers()
|
||||||
providers = collections.OrderedDict()
|
providers = collections.OrderedDict()
|
||||||
|
|
|
@ -72,7 +72,14 @@ def test_package_provider(args, monkeypatch):
|
||||||
pkgnames_install = []
|
pkgnames_install = []
|
||||||
assert func(args, pkgname, pkgnames_install) == package
|
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 = {}
|
installed = {}
|
||||||
assert func(args, pkgname, pkgnames_install) == package
|
assert func(args, pkgname, pkgnames_install) == package
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue