From f18c708183ac735d1787ff5b450d36f6596a10b9 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Thu, 2 Nov 2017 02:55:17 +0000 Subject: [PATCH] solver: implement support for choosing default virtuals By introducing a new package metadata field, `provider_priority` (index letter `k`), we can specify default packages to satisfy a virtual. If a user wishes to select an alternative provider for the virtual, a changeset swapping the default provider for the selected provider will be generated by the dependency resolver. --- src/apk_package.h | 1 + src/apk_solver_data.h | 1 + src/package.c | 8 ++++++++ src/solver.c | 24 +++++++++++++++++------- test/provides-swap.installed | 6 ++++++ test/provides-swap.test | 9 +++++++++ test/provides.repo | 1 + test/provides2.test | 6 ++---- test/provides8.test | 6 ++++++ 9 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 test/provides-swap.installed create mode 100644 test/provides-swap.test create mode 100644 test/provides8.test diff --git a/src/apk_package.h b/src/apk_package.h index c561fc1..87635a9 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -117,6 +117,7 @@ struct apk_package { struct apk_dependency_array *depends, *install_if, *provides; size_t installed_size, size; time_t build_time; + unsigned short provider_priority; unsigned repos : APK_MAX_REPOS; unsigned marked : 1; unsigned uninstallable : 1; diff --git a/src/apk_solver_data.h b/src/apk_solver_data.h index 43b7a1b..73c2753 100644 --- a/src/apk_solver_data.h +++ b/src/apk_solver_data.h @@ -54,6 +54,7 @@ struct apk_solver_package_state { unsigned seen : 1; unsigned pkg_available : 1; unsigned pkg_selectable : 1; + unsigned pkg_selected : 1; unsigned tag_ok : 1; unsigned tag_preferred : 1; unsigned dependencies_used : 1; diff --git a/src/package.c b/src/package.c index be7f269..d851ff0 100644 --- a/src/package.c +++ b/src/package.c @@ -812,6 +812,9 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg, case 'c': pkg->commit = apk_blob_cstr(value); break; + case 'k': + pkg->provider_priority = apk_blob_pull_uint(&value, 10); + break; case 'F': case 'M': case 'R': case 'Z': case 'r': case 'q': case 'a': case 's': case 'f': /* installed db entries which are handled in database.c */ @@ -850,6 +853,7 @@ static int read_info_line(void *ctx, apk_blob_t line) { "maintainer", 'm' }, { "builddate", 't' }, { "commit", 'c' }, + { "provider_priority", 'k' }, }; struct read_info_ctx *ri = (struct read_info_ctx *) ctx; apk_blob_t l, r; @@ -1125,6 +1129,10 @@ int apk_pkg_write_index_entry(struct apk_package *info, apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nc:")); apk_blob_push_blob(&bbuf, APK_BLOB_STR(info->commit)); } + if (info->provider_priority) { + apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nk:")); + apk_blob_push_uint(&bbuf, info->provider_priority, 10); + } apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); if (APK_BLOB_IS_NULL(bbuf)) { diff --git a/src/solver.c b/src/solver.c index 1db8a69..11ccfc9 100644 --- a/src/solver.c +++ b/src/solver.c @@ -299,6 +299,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp if (is_provided) inherit_pinning_and_flags(ss, pkg0, ppkg); + + /* if a world-dependency is non-virtual, then the provider is going to be selected */ + if (ppkg == NULL && dep->name == pkg0->name && pkg0->ss.pkg_selectable) + pkg0->ss.pkg_selected = 1; } } @@ -587,6 +591,16 @@ static int compare_providers(struct apk_solver_state *ss, if (r) return r; + /* Prefer already selected package. */ + r = pkgA->ss.pkg_selected - pkgB->ss.pkg_selected; + if (r) + return r; + + /* Prefer highest declared provider priority. */ + r = pkgA->provider_priority - pkgB->provider_priority; + if (r) + return r; + /* Prefer lowest available repository */ return ffs(pkgB->repos) - ffs(pkgA->repos); } @@ -639,18 +653,14 @@ static void select_package(struct apk_solver_state *ss, struct apk_name *name) if (name->ss.requirers || name->ss.has_iif) { foreach_array_item(p, name->providers) { - dbg_printf(" consider "PKG_VER_FMT" iif_triggered=%d, tag_ok=%d, selectable=%d\n", - PKG_VER_PRINTF(p->pkg), p->pkg->ss.iif_triggered, p->pkg->ss.tag_ok, p->pkg->ss.pkg_selectable); + dbg_printf(" consider "PKG_VER_FMT" iif_triggered=%d, tag_ok=%d, selectable=%d, selected=%d, provider_priority=%d\n", + PKG_VER_PRINTF(p->pkg), p->pkg->ss.iif_triggered, p->pkg->ss.tag_ok, p->pkg->ss.pkg_selectable, + p->pkg->ss.pkg_selected, p->pkg->provider_priority); /* Ensure valid pinning and install-if trigger */ if (name->ss.requirers == 0 && (!p->pkg->ss.iif_triggered || !p->pkg->ss.tag_ok)) continue; - /* Virtual packages cannot be autoselected */ - if (p->version == &apk_null_blob && - p->pkg->name->auto_select_virtual == 0 && - p->pkg->name->ss.requirers == 0) - continue; if (compare_providers(ss, p, &chosen) > 0) chosen = *p; } diff --git a/test/provides-swap.installed b/test/provides-swap.installed new file mode 100644 index 0000000..480def8 --- /dev/null +++ b/test/provides-swap.installed @@ -0,0 +1,6 @@ +C:Q1EyN5AdpAOBJWKMR89pp/C66o+OE= +P:mailreadplus +V:1 +S:1 +I:1 + diff --git a/test/provides-swap.test b/test/provides-swap.test new file mode 100644 index 0000000..d38c227 --- /dev/null +++ b/test/provides-swap.test @@ -0,0 +1,9 @@ +@ARGS +--test-repo provides.repo +--test-instdb provides-swap.installed +--test-world mail-reader +add mymailreader +@EXPECT +(1/2) Purging mailreadplus (1) +(2/2) Installing mymailreader (1) +OK: 0 MiB in 1 packages diff --git a/test/provides.repo b/test/provides.repo index 6418f18..8bc0c62 100644 --- a/test/provides.repo +++ b/test/provides.repo @@ -45,6 +45,7 @@ V:1 S:1 I:1 p:mail-reader +k:1 C:Q1EyN5AdpAOBJWKMR89pp/C77FFFF= P:server-a diff --git a/test/provides2.test b/test/provides2.test index 37fc9d8..a0fca43 100644 --- a/test/provides2.test +++ b/test/provides2.test @@ -2,7 +2,5 @@ --test-repo provides.repo add mail-reader @EXPECT -ERROR: unsatisfiable constraints: - mail-reader (virtual): - provided by: mymailreader-1 mailreadplus - required by: world[mail-reader] +(1/1) Installing mailreadplus (1) +OK: 0 MiB in 0 packages diff --git a/test/provides8.test b/test/provides8.test new file mode 100644 index 0000000..9cc13f5 --- /dev/null +++ b/test/provides8.test @@ -0,0 +1,6 @@ +@ARGS +--test-repo provides.repo +add mail-reader mailreadplus +@EXPECT +(1/1) Installing mailreadplus (1) +OK: 0 MiB in 0 packages