diff options
author | Timo Teräs <timo.teras@iki.fi> | 2017-10-27 15:18:15 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2017-10-27 15:20:03 +0300 |
commit | e03716ff3baa73061b45235754bd9eaa53346337 (patch) | |
tree | 24b2370cfd1113cec2c33237eddc1d341663b44b | |
parent | 2f3c8420493a731556909eb3ebd6d50478fb7b24 (diff) | |
download | apk-tools-e03716ff3baa73061b45235754bd9eaa53346337.tar.gz apk-tools-e03716ff3baa73061b45235754bd9eaa53346337.tar.bz2 apk-tools-e03716ff3baa73061b45235754bd9eaa53346337.tar.xz apk-tools-e03716ff3baa73061b45235754bd9eaa53346337.zip |
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.
-rw-r--r-- | src/apk_solver_data.h | 1 | ||||
-rw-r--r-- | src/solver.c | 31 |
2 files changed, 20 insertions, 12 deletions
diff --git a/src/apk_solver_data.h b/src/apk_solver_data.h index ca3f127..43b7a1b 100644 --- a/src/apk_solver_data.h +++ b/src/apk_solver_data.h @@ -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 { diff --git a/src/solver.c b/src/solver.c index 5c08887..1db8a69 100644 --- a/src/solver.c +++ b/src/solver.c @@ -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; |