summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2017-10-27 15:18:15 +0300
committerTimo Teräs <timo.teras@iki.fi>2017-10-27 15:20:03 +0300
commite03716ff3baa73061b45235754bd9eaa53346337 (patch)
tree24b2370cfd1113cec2c33237eddc1d341663b44b
parent2f3c8420493a731556909eb3ebd6d50478fb7b24 (diff)
downloadapk-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.h1
-rw-r--r--src/solver.c31
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;