summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2022-12-20 21:50:37 +0200
committerTimo Teräs <timo.teras@iki.fi>2022-12-20 22:41:14 +0200
commit0726606de2db6a0e75bc4ebe1a010122d0367f0f (patch)
tree4f28f6c973f317b5142f307f775192619fb8d614
parent8d0962ca0cb076b3a5dafacc10c6a411b1e2d444 (diff)
downloadapk-tools-0726606de2db6a0e75bc4ebe1a010122d0367f0f.tar.gz
apk-tools-0726606de2db6a0e75bc4ebe1a010122d0367f0f.tar.bz2
apk-tools-0726606de2db6a0e75bc4ebe1a010122d0367f0f.tar.xz
apk-tools-0726606de2db6a0e75bc4ebe1a010122d0367f0f.zip
solver, commit: handle install_if via provided names correctly
Correctly trigger install_ifs for provided names also. And fix the construction of error messages concerning such install_if packages. ref #10843
-rw-r--r--src/commit.c80
-rw-r--r--src/solver.c58
2 files changed, 95 insertions, 43 deletions
diff --git a/src/commit.c b/src/commit.c
index 4b4f588..7ca39d3 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -383,9 +383,10 @@ all_done:
}
enum {
- STATE_SEEN = 0x80000000,
- STATE_PRESENT = 0x40000000,
- STATE_MISSING = 0x20000000,
+ STATE_PRESENT = 0x80000000,
+ STATE_MISSING = 0x40000000,
+ STATE_VIRTUAL_ONLY = 0x20000000,
+ STATE_INSTALLIF = 0x10000000,
STATE_COUNT_MASK = 0x0000ffff,
};
@@ -608,34 +609,71 @@ static void analyze_deps(struct print_state *ps, struct apk_dependency_array *de
}
static void discover_deps(struct apk_dependency_array *deps);
+static void discover_name(struct apk_name *name, int pkg_state);
-static void discover_name(struct apk_name *name)
+static void discover_reverse_iif(struct apk_name *name)
{
+ struct apk_name **pname0, *name0;
+ struct apk_dependency *d;
struct apk_provider *p;
+
+ foreach_array_item(pname0, name->rinstall_if) {
+ name0 = *pname0;
+
+ foreach_array_item(p, name0->providers) {
+ int ok = 1;
+ if (!p->pkg->marked) continue;
+ if (p->pkg->install_if->num == 0) continue;
+ foreach_array_item(d, p->pkg->install_if) {
+ if (!!d->conflict == !!(d->name->state_int & STATE_PRESENT)) {
+ ok = 0;
+ break;
+ }
+ }
+ if (ok) {
+ discover_name(p->pkg->name, STATE_INSTALLIF);
+ foreach_array_item(d, p->pkg->provides)
+ discover_name(d->name, STATE_INSTALLIF);
+ }
+ }
+ }
+}
+
+static int is_name_concrete(struct apk_package *pkg, struct apk_name *name)
+{
struct apk_dependency *d;
- int concrete;
+ if (pkg->name == name) return 1;
+ foreach_array_item(d, pkg->provides) {
+ if (d->name != name) continue;
+ if (d->version == &apk_atom_null) continue;
+ return 1;
+ }
+ return 0;
+}
- if (name->state_int & STATE_SEEN) return;
- name->state_int |= STATE_SEEN;
+static void discover_name(struct apk_name *name, int pkg_state)
+{
+ struct apk_provider *p;
+ struct apk_dependency *d;
foreach_array_item(p, name->providers) {
+ int state = pkg_state;
if (!p->pkg->marked) continue;
+ if (state == STATE_PRESENT && !is_name_concrete(p->pkg, name))
+ state = STATE_VIRTUAL_ONLY;
+ if (p->pkg->state_int & state) continue;
+ p->pkg->state_int |= state;
- concrete = p->pkg->name == name;
- if (!concrete) {
- foreach_array_item(d, p->pkg->provides) {
- if (d->name != name) continue;
- if (d->version == &apk_atom_null) continue;
- concrete = 1;
- break;
- }
- }
- if (concrete) {
- p->pkg->name->state_int |= STATE_PRESENT;
+ p->pkg->name->state_int |= state;
+ foreach_array_item(d, p->pkg->provides)
+ d->name->state_int |= state;
+
+ discover_deps(p->pkg->depends);
+ if (state == STATE_PRESENT || state == STATE_INSTALLIF) {
+ discover_reverse_iif(p->pkg->name);
foreach_array_item(d, p->pkg->provides)
- d->name->state_int |= STATE_PRESENT;
+ discover_reverse_iif(d->name);
}
- discover_deps(p->pkg->depends);
}
}
@@ -645,7 +683,7 @@ static void discover_deps(struct apk_dependency_array *deps)
foreach_array_item(d, deps) {
if (d->conflict) continue;
- discover_name(d->name);
+ discover_name(d->name, STATE_PRESENT);
}
}
diff --git a/src/solver.c b/src/solver.c
index 06dfb6b..3a8f6e6 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -118,8 +118,7 @@ static void reevaluate_reverse_deps(struct apk_solver_state *ss, struct apk_name
foreach_array_item(pname0, name->rdepends) {
name0 = *pname0;
- if (!name0->ss.seen)
- continue;
+ if (!name0->ss.seen) continue;
name0->ss.reevaluate_deps = 1;
queue_dirty(ss, name0);
}
@@ -131,15 +130,21 @@ static void reevaluate_reverse_installif(struct apk_solver_state *ss, struct apk
foreach_array_item(pname0, name->rinstall_if) {
name0 = *pname0;
- if (!name0->ss.seen)
- continue;
- if (name0->ss.no_iif)
- continue;
+ if (!name0->ss.seen) continue;
+ if (name0->ss.no_iif) continue;
name0->ss.reevaluate_iif = 1;
queue_dirty(ss, name0);
}
}
+static void reevaluate_reverse_installif_pkg(struct apk_solver_state *ss, struct apk_package *pkg)
+{
+ struct apk_dependency *d;
+ reevaluate_reverse_installif(ss, pkg->name);
+ foreach_array_item(d, pkg->provides)
+ reevaluate_reverse_installif(ss, d->name);
+}
+
static void disqualify_package(struct apk_solver_state *ss, struct apk_package *pkg, const char *reason)
{
struct apk_dependency *p;
@@ -149,7 +154,7 @@ static void disqualify_package(struct apk_solver_state *ss, struct apk_package *
reevaluate_reverse_deps(ss, pkg->name);
foreach_array_item(p, pkg->provides)
reevaluate_reverse_deps(ss, p->name);
- reevaluate_reverse_installif(ss, pkg->name);
+ reevaluate_reverse_installif_pkg(ss, pkg);
}
static int dependency_satisfiable(struct apk_solver_state *ss, struct apk_dependency *dep)
@@ -683,7 +688,10 @@ static void assign_name(struct apk_solver_state *ss, struct apk_name *name, stru
}
}
reevaluate_reverse_deps(ss, name);
- reevaluate_reverse_installif(ss, name);
+ if (p.pkg)
+ reevaluate_reverse_installif_pkg(ss, p.pkg);
+ else
+ reevaluate_reverse_installif(ss, name);
}
static void select_package(struct apk_solver_state *ss, struct apk_name *name)
@@ -822,10 +830,8 @@ static void cset_check_install_by_iif(struct apk_solver_state *ss, struct apk_na
foreach_array_item(dep0, pkg->install_if) {
struct apk_name *name0 = dep0->name;
- if (!name0->ss.in_changeset)
- return;
- if (!apk_dep_is_provided(dep0, &name0->ss.chosen))
- return;
+ if (!name0->ss.in_changeset) return;
+ if (!apk_dep_is_provided(dep0, &name0->ss.chosen)) return;
}
cset_gen_name_change(ss, name);
}
@@ -847,6 +853,19 @@ static void cset_check_removal_by_iif(struct apk_solver_state *ss, struct apk_na
}
}
+static void cset_check_by_reverse_iif(struct apk_solver_state *ss, struct apk_package *pkg, void (*cb)(struct apk_solver_state *ss, struct apk_name *))
+{
+ struct apk_name **pname;
+ struct apk_dependency *d;
+
+ if (!pkg) return;
+ foreach_array_item(pname, pkg->name->rinstall_if)
+ cb(ss, *pname);
+ foreach_array_item(d, pkg->provides)
+ foreach_array_item(pname, d->name->rinstall_if)
+ cb(ss, *pname);
+}
+
static void cset_gen_name_remove_orphan(struct apk_solver_state *ss, struct apk_name *name)
{
struct apk_package *pkg = name->ss.chosen.pkg;
@@ -860,7 +879,6 @@ static void cset_gen_name_remove_orphan(struct apk_solver_state *ss, struct apk_
static void cset_gen_name_change(struct apk_solver_state *ss, struct apk_name *name)
{
- struct apk_name **pname;
struct apk_package *pkg, *opkg;
struct apk_dependency *d;
@@ -877,10 +895,7 @@ static void cset_gen_name_change(struct apk_solver_state *ss, struct apk_name *n
cset_gen_name_remove_orphan(ss, d->name);
opkg = pkg->name->ss.installed_pkg;
- if (opkg) {
- foreach_array_item(pname, opkg->name->rinstall_if)
- cset_check_removal_by_iif(ss, *pname);
- }
+ cset_check_by_reverse_iif(ss, opkg, cset_check_removal_by_iif);
foreach_array_item(d, pkg->depends)
cset_gen_dep(ss, pkg, d);
@@ -888,8 +903,7 @@ static void cset_gen_name_change(struct apk_solver_state *ss, struct apk_name *n
dbg_printf("Selecting: "PKG_VER_FMT"%s\n", PKG_VER_PRINTF(pkg), pkg->ss.pkg_selectable ? "" : " [NOT SELECTABLE]");
record_change(ss, opkg, pkg);
- foreach_array_item(pname, pkg->name->rinstall_if)
- cset_check_install_by_iif(ss, *pname);
+ cset_check_by_reverse_iif(ss, pkg, cset_check_install_by_iif);
cset_track_deps_added(pkg);
if (opkg)
@@ -903,7 +917,7 @@ static void cset_gen_name_remove0(struct apk_package *pkg0, struct apk_dependenc
static void cset_gen_name_remove(struct apk_solver_state *ss, struct apk_package *pkg)
{
- struct apk_name *name = pkg->name, **pname;
+ struct apk_name *name = pkg->name;
if (pkg->ss.in_changeset ||
(name->ss.chosen.pkg != NULL &&
@@ -913,8 +927,8 @@ static void cset_gen_name_remove(struct apk_solver_state *ss, struct apk_package
name->ss.in_changeset = 1;
pkg->ss.in_changeset = 1;
apk_pkg_foreach_reverse_dependency(pkg, APK_FOREACH_INSTALLED|APK_DEP_SATISFIES, cset_gen_name_remove0, ss);
- foreach_array_item(pname, pkg->name->rinstall_if)
- cset_check_removal_by_iif(ss, *pname);
+ cset_check_by_reverse_iif(ss, pkg, cset_check_removal_by_iif);
+
record_change(ss, pkg, NULL);
cset_track_deps_removed(ss, pkg);
}