solver: add logic: transitive provides exclusion
If name N is required, and all providers of A also provide B, it means that only instances of B can be selected that provide N. This is strong help with cases when so:libfoo.so.1 is updated to so:libfoo.so.2 and not everything is recompiled.cute-signatures
parent
956bd5f032
commit
a984fd3679
|
@ -22,7 +22,8 @@ struct apk_solver_name_state {
|
||||||
struct apk_provider chosen;
|
struct apk_provider chosen;
|
||||||
|
|
||||||
unsigned short requirers;
|
unsigned short requirers;
|
||||||
unsigned short merge_index;
|
unsigned short merge_depends;
|
||||||
|
unsigned short merge_provides;
|
||||||
unsigned short max_dep_chain;
|
unsigned short max_dep_chain;
|
||||||
unsigned seen : 1;
|
unsigned seen : 1;
|
||||||
unsigned in_world_dependency : 1;
|
unsigned in_world_dependency : 1;
|
||||||
|
|
79
src/solver.c
79
src/solver.c
|
@ -294,11 +294,45 @@ 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)
|
||||||
|
{
|
||||||
|
struct apk_provider *p;
|
||||||
|
struct apk_dependency *d;
|
||||||
|
|
||||||
|
dbg_printf("%s must provide %s\n", name->name, must_provide->name);
|
||||||
|
|
||||||
|
foreach_array_item(p, name->providers) {
|
||||||
|
if (p->pkg->name == must_provide)
|
||||||
|
goto next;
|
||||||
|
foreach_array_item(d, p->pkg->provides)
|
||||||
|
if (d->name == must_provide)
|
||||||
|
goto next;
|
||||||
|
disqualify_package(ss, p->pkg, "provides transitivity");
|
||||||
|
next: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void merge_index(unsigned short *index, int num_options)
|
||||||
|
{
|
||||||
|
if (*index == num_options)
|
||||||
|
*index = num_options + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int merge_index_complete(unsigned short *index, int num_options)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = (*index == num_options);
|
||||||
|
*index = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
|
static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
|
||||||
{
|
{
|
||||||
struct apk_name *name0, **pname0;
|
struct apk_name *name0, **pname0;
|
||||||
struct apk_dependency *dep;
|
struct apk_dependency *dep;
|
||||||
struct apk_package *first_candidate = NULL;
|
struct apk_package *first_candidate = NULL, *pkg;
|
||||||
struct apk_provider *p;
|
struct apk_provider *p;
|
||||||
int reevaluate_deps, reevaluate_iif;
|
int reevaluate_deps, reevaluate_iif;
|
||||||
int num_options = 0, num_tag_not_ok = 0, has_iif = 0;
|
int num_options = 0, num_tag_not_ok = 0, has_iif = 0;
|
||||||
|
@ -313,9 +347,8 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
|
||||||
/* propagate down by merging common dependencies and
|
/* propagate down by merging common dependencies and
|
||||||
* applying new constraints */
|
* applying new constraints */
|
||||||
foreach_array_item(p, name->providers) {
|
foreach_array_item(p, name->providers) {
|
||||||
struct apk_package *pkg = p->pkg;
|
|
||||||
|
|
||||||
/* check if this pkg's dependencies have become unsatisfiable */
|
/* check if this pkg's dependencies have become unsatisfiable */
|
||||||
|
pkg = p->pkg;
|
||||||
pkg->ss.dependencies_merged = 0;
|
pkg->ss.dependencies_merged = 0;
|
||||||
if (reevaluate_deps) {
|
if (reevaluate_deps) {
|
||||||
if (!pkg->ss.available)
|
if (!pkg->ss.available)
|
||||||
|
@ -348,14 +381,16 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
|
||||||
pkg->ss.dependencies_merged = 1;
|
pkg->ss.dependencies_merged = 1;
|
||||||
if (first_candidate == NULL)
|
if (first_candidate == NULL)
|
||||||
first_candidate = pkg;
|
first_candidate = pkg;
|
||||||
foreach_array_item(dep, pkg->depends) {
|
|
||||||
/* FIXME: can merge also conflicts */
|
/* FIXME: can merge also conflicts */
|
||||||
if (dep->conflict)
|
foreach_array_item(dep, pkg->depends)
|
||||||
continue;
|
if (!dep->conflict)
|
||||||
name0 = dep->name;
|
merge_index(&dep->name->ss.merge_depends, num_options);
|
||||||
if (name0->ss.merge_index == num_options)
|
|
||||||
name0->ss.merge_index = num_options + 1;
|
merge_index(&pkg->name->ss.merge_provides, num_options);
|
||||||
}
|
foreach_array_item(dep, pkg->provides)
|
||||||
|
if (dep->version != &apk_null_blob)
|
||||||
|
merge_index(&dep->name->ss.merge_provides, num_options);
|
||||||
|
|
||||||
num_tag_not_ok += !pkg->ss.tag_ok;
|
num_tag_not_ok += !pkg->ss.tag_ok;
|
||||||
num_options++;
|
num_options++;
|
||||||
|
@ -365,33 +400,39 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
|
||||||
queue_unresolved(ss, name);
|
queue_unresolved(ss, name);
|
||||||
|
|
||||||
if (first_candidate != NULL) {
|
if (first_candidate != NULL) {
|
||||||
|
pkg = first_candidate;
|
||||||
foreach_array_item(p, name->providers)
|
foreach_array_item(p, name->providers)
|
||||||
p->pkg->ss.dependencies_used = p->pkg->ss.dependencies_merged;
|
p->pkg->ss.dependencies_used = p->pkg->ss.dependencies_merged;
|
||||||
|
|
||||||
/* propagate down common dependencies */
|
/* propagate down common dependencies */
|
||||||
if (num_options == 1) {
|
if (num_options == 1) {
|
||||||
/* FIXME: keeps increasing counts, use bit fields instead? */
|
/* FIXME: keeps increasing counts, use bit fields instead? */
|
||||||
foreach_array_item(dep, first_candidate->depends)
|
foreach_array_item(dep, pkg->depends)
|
||||||
apply_constraint(ss, first_candidate, dep);
|
if (merge_index_complete(&dep->name->ss.merge_depends, num_options))
|
||||||
|
apply_constraint(ss, pkg, dep);
|
||||||
} else {
|
} else {
|
||||||
/* FIXME: could merge versioning bits too */
|
/* FIXME: could merge versioning bits too */
|
||||||
foreach_array_item(dep, first_candidate->depends) {
|
foreach_array_item(dep, pkg->depends) {
|
||||||
if (dep->conflict)
|
|
||||||
continue;
|
|
||||||
name0 = dep->name;
|
name0 = dep->name;
|
||||||
if (name0->ss.merge_index == num_options) {
|
if (merge_index_complete(&name0->ss.merge_depends, num_options) &&
|
||||||
|
name0->ss.requirers == 0) {
|
||||||
/* common dependency name with all */
|
/* common dependency name with all */
|
||||||
if (name0->ss.requirers == 0) {
|
|
||||||
dbg_printf("%s common dependency: %s\n",
|
dbg_printf("%s common dependency: %s\n",
|
||||||
name->name, name0->name);
|
name->name, name0->name);
|
||||||
name0->ss.requirers++;
|
name0->ss.requirers++;
|
||||||
name_requirers_changed(ss, name0);
|
name_requirers_changed(ss, name0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
name0->ss.merge_index = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* provides transitivity */
|
||||||
|
if (merge_index_complete(&pkg->name->ss.merge_provides, num_options))
|
||||||
|
exclude_non_providers(ss, pkg->name, name);
|
||||||
|
foreach_array_item(dep, pkg->provides)
|
||||||
|
if (merge_index_complete(&dep->name->ss.merge_provides, num_options))
|
||||||
|
exclude_non_providers(ss, dep->name, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
name->ss.reverse_deps_done = 1;
|
name->ss.reverse_deps_done = 1;
|
||||||
foreach_array_item(pname0, name->rdepends) {
|
foreach_array_item(pname0, name->rdepends) {
|
||||||
name0 = *pname0;
|
name0 = *pname0;
|
||||||
|
|
Loading…
Reference in New Issue