solver: consider virtual provides to exclude non-provides transitively

this fixes package selection when a 'real' package exists, but would
need to be provided by another package with 'virtual provides'.

In current package database this can happen with postgresql which is
also provided by postgresql-bdr. Normally postgresql would be satisfied
by postgresql, but if any package depends on postgresql-bdr and there's
no versioned dependency on postgresql this will help apk figure out
that postgresql-bdr should be used.
cute-signatures
Timo Teräs 2017-10-27 15:18:15 +03:00
parent 2f3c842049
commit e03716ff3b
2 changed files with 20 additions and 12 deletions

View File

@ -41,6 +41,7 @@ struct apk_solver_name_state {
unsigned no_iif : 1;
unsigned has_options : 1;
unsigned reverse_deps_done : 1;
unsigned has_virtual_provides : 1;
};
struct apk_solver_package_state {

View File

@ -302,7 +302,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp
}
}
static void exclude_non_providers(struct apk_solver_state *ss, struct apk_name *name, struct apk_name *must_provide)
static void exclude_non_providers(struct apk_solver_state *ss, struct apk_name *name, struct apk_name *must_provide, int skip_virtuals)
{
struct apk_provider *p;
struct apk_dependency *d;
@ -310,23 +310,25 @@ static void exclude_non_providers(struct apk_solver_state *ss, struct apk_name *
if (name == must_provide)
return;
dbg_printf("%s must provide %s\n", name->name, must_provide->name);
dbg_printf("%s must provide %s (skip_virtuals=%d)\n", name->name, must_provide->name, skip_virtuals);
foreach_array_item(p, name->providers) {
if (p->pkg->name == must_provide || !p->pkg->ss.pkg_selectable)
if (p->pkg->name == must_provide || !p->pkg->ss.pkg_selectable ||
(skip_virtuals && p->version == &apk_null_blob))
goto next;
foreach_array_item(d, p->pkg->provides)
if (d->name == must_provide)
if (d->name == must_provide || (skip_virtuals && d->version == &apk_null_blob))
goto next;
disqualify_package(ss, p->pkg, "provides transitivity");
next: ;
}
}
static inline void merge_index(unsigned short *index, int num_options)
static inline int merge_index(unsigned short *index, int num_options)
{
if (*index == num_options)
*index = num_options + 1;
if (*index != num_options) return 0;
*index = num_options + 1;
return 1;
}
static inline int merge_index_complete(unsigned short *index, int num_options)
@ -414,10 +416,11 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
if (!dep->conflict)
merge_index(&dep->name->ss.merge_depends, num_options);
merge_index(&pkg->name->ss.merge_provides, num_options);
if (merge_index(&pkg->name->ss.merge_provides, num_options))
pkg->name->ss.has_virtual_provides |= (p->version == &apk_null_blob);
foreach_array_item(dep, pkg->provides)
if (dep->version != &apk_null_blob)
merge_index(&dep->name->ss.merge_provides, num_options);
if (merge_index(&dep->name->ss.merge_provides, num_options))
dep->name->ss.has_virtual_provides |= (dep->version == &apk_null_blob);
num_tag_not_ok += !pkg->ss.tag_ok;
num_options++;
@ -455,10 +458,14 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
/* provides transitivity */
if (merge_index_complete(&pkg->name->ss.merge_provides, num_options))
exclude_non_providers(ss, pkg->name, name);
exclude_non_providers(ss, pkg->name, name, pkg->name->ss.has_virtual_provides);
foreach_array_item(dep, pkg->provides)
if (merge_index_complete(&dep->name->ss.merge_provides, num_options))
exclude_non_providers(ss, dep->name, name);
exclude_non_providers(ss, dep->name, name, dep->name->ss.has_virtual_provides);
pkg->name->ss.has_virtual_provides = 0;
foreach_array_item(dep, pkg->provides)
dep->name->ss.has_virtual_provides = 0;
}
name->ss.reverse_deps_done = 1;