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.
cute-signatures
William Pitcock 2017-11-02 02:55:17 +00:00
parent ee3740fcc6
commit f18c708183
9 changed files with 51 additions and 11 deletions

View File

@ -117,6 +117,7 @@ struct apk_package {
struct apk_dependency_array *depends, *install_if, *provides; struct apk_dependency_array *depends, *install_if, *provides;
size_t installed_size, size; size_t installed_size, size;
time_t build_time; time_t build_time;
unsigned short provider_priority;
unsigned repos : APK_MAX_REPOS; unsigned repos : APK_MAX_REPOS;
unsigned marked : 1; unsigned marked : 1;
unsigned uninstallable : 1; unsigned uninstallable : 1;

View File

@ -54,6 +54,7 @@ struct apk_solver_package_state {
unsigned seen : 1; unsigned seen : 1;
unsigned pkg_available : 1; unsigned pkg_available : 1;
unsigned pkg_selectable : 1; unsigned pkg_selectable : 1;
unsigned pkg_selected : 1;
unsigned tag_ok : 1; unsigned tag_ok : 1;
unsigned tag_preferred : 1; unsigned tag_preferred : 1;
unsigned dependencies_used : 1; unsigned dependencies_used : 1;

View File

@ -812,6 +812,9 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg,
case 'c': case 'c':
pkg->commit = apk_blob_cstr(value); pkg->commit = apk_blob_cstr(value);
break; 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 'F': case 'M': case 'R': case 'Z': case 'r': case 'q':
case 'a': case 's': case 'f': case 'a': case 's': case 'f':
/* installed db entries which are handled in database.c */ /* 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' }, { "maintainer", 'm' },
{ "builddate", 't' }, { "builddate", 't' },
{ "commit", 'c' }, { "commit", 'c' },
{ "provider_priority", 'k' },
}; };
struct read_info_ctx *ri = (struct read_info_ctx *) ctx; struct read_info_ctx *ri = (struct read_info_ctx *) ctx;
apk_blob_t l, r; 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("\nc:"));
apk_blob_push_blob(&bbuf, APK_BLOB_STR(info->commit)); 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")); apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
if (APK_BLOB_IS_NULL(bbuf)) { if (APK_BLOB_IS_NULL(bbuf)) {

View File

@ -299,6 +299,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp
if (is_provided) if (is_provided)
inherit_pinning_and_flags(ss, pkg0, ppkg); 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) if (r)
return 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 */ /* Prefer lowest available repository */
return ffs(pkgB->repos) - ffs(pkgA->repos); 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) { if (name->ss.requirers || name->ss.has_iif) {
foreach_array_item(p, name->providers) { foreach_array_item(p, name->providers) {
dbg_printf(" consider "PKG_VER_FMT" iif_triggered=%d, tag_ok=%d, selectable=%d\n", 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); 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 */ /* Ensure valid pinning and install-if trigger */
if (name->ss.requirers == 0 && if (name->ss.requirers == 0 &&
(!p->pkg->ss.iif_triggered || (!p->pkg->ss.iif_triggered ||
!p->pkg->ss.tag_ok)) !p->pkg->ss.tag_ok))
continue; 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) if (compare_providers(ss, p, &chosen) > 0)
chosen = *p; chosen = *p;
} }

View File

@ -0,0 +1,6 @@
C:Q1EyN5AdpAOBJWKMR89pp/C66o+OE=
P:mailreadplus
V:1
S:1
I:1

9
test/provides-swap.test Normal file
View File

@ -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

View File

@ -45,6 +45,7 @@ V:1
S:1 S:1
I:1 I:1
p:mail-reader p:mail-reader
k:1
C:Q1EyN5AdpAOBJWKMR89pp/C77FFFF= C:Q1EyN5AdpAOBJWKMR89pp/C77FFFF=
P:server-a P:server-a

View File

@ -2,7 +2,5 @@
--test-repo provides.repo --test-repo provides.repo
add mail-reader add mail-reader
@EXPECT @EXPECT
ERROR: unsatisfiable constraints: (1/1) Installing mailreadplus (1)
mail-reader (virtual): OK: 0 MiB in 0 packages
provided by: mymailreader-1 mailreadplus
required by: world[mail-reader]

6
test/provides8.test Normal file
View File

@ -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