summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2011-09-16 17:10:50 +0300
committerTimo Teräs <timo.teras@iki.fi>2011-09-16 17:10:50 +0300
commit51999c97dabf9fbbe352ca3ead02851a982fcade (patch)
treeec1033d2d1079b24691246c23137e65d517c5b9b /src/solver.c
parentbcd0d45a49c89fd809f0a028012196f5a9527c99 (diff)
downloadapk-tools-51999c97dabf9fbbe352ca3ead02851a982fcade.tar.gz
apk-tools-51999c97dabf9fbbe352ca3ead02851a982fcade.tar.bz2
apk-tools-51999c97dabf9fbbe352ca3ead02851a982fcade.tar.xz
apk-tools-51999c97dabf9fbbe352ca3ead02851a982fcade.zip
solver: inheritable solver flags
allow per-name solver flags to be inheritable, and use them in self-upgrade, add -u and the fix applet. this gives more familiar behaviour for the upgrades.
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c134
1 files changed, 108 insertions, 26 deletions
diff --git a/src/solver.c b/src/solver.c
index 53fded2..e6f0cc5 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -39,16 +39,19 @@ struct apk_package_state {
unsigned short cur_unsatisfiable;
};
-#define APK_NAMESTF_AVAILABILITY_CHECKED 1
-#define APK_NAMESTF_LOCKED 2
-#define APK_NAMESTF_NO_OPTIONS 4
struct apk_name_state {
struct list_head unsolved_list;
struct apk_package *chosen;
- unsigned short solver_flags;
- unsigned short flags;
unsigned short requirers;
unsigned short install_ifs;
+
+ unsigned int solver_flags_local : 4;
+ unsigned int solver_flags_local_mask : 4;
+ unsigned int solver_flags_inherited : 4;
+
+ unsigned int availability_checked : 1;
+ unsigned int locked : 1;
+ unsigned int no_options : 1;
};
struct apk_solver_state {
@@ -59,9 +62,10 @@ struct apk_solver_state {
struct apk_package *latest_decision;
unsigned int topology_position;
unsigned int assigned_names;
- unsigned short solver_flags;
unsigned short cur_unsatisfiable;
+ unsigned short solver_flags;
+
struct apk_package_array *best_solution;
unsigned short best_unsatisfiable;
};
@@ -206,7 +210,7 @@ static void prepare_name(struct apk_solver_state *ss, struct apk_name *name,
{
int i;
- if (ns->flags & APK_NAMESTF_AVAILABILITY_CHECKED)
+ if (ns->availability_checked)
return;
for (i = 0; i < name->pkgs->num; i++) {
@@ -216,14 +220,44 @@ static void prepare_name(struct apk_solver_state *ss, struct apk_name *name,
/* if package is needed for (re-)install */
if ((pkg->ipkg == NULL) ||
- ((ns->solver_flags | ss->solver_flags) & APK_SOLVERF_REINSTALL)) {
+ ((ns->solver_flags_local | ns->solver_flags_inherited |
+ ss->solver_flags) & APK_SOLVERF_REINSTALL)) {
/* and it's not available, we can't use it */
if (!pkg_available(ss->db, pkg))
ps->conflicts = 1024;
}
}
- ns->flags |= APK_NAMESTF_AVAILABILITY_CHECKED;
+ ns->availability_checked = 1;
+}
+
+static void foreach_locked_reverse_dependency(
+ struct apk_name *name,
+ void (*cb)(struct apk_package *rdepend, void *ctx), void *ctx)
+{
+ int i, j;
+
+ if (name == NULL)
+ return;
+
+ for (i = 0; i < name->rdepends->num; i++) {
+ struct apk_name *name0 = name->rdepends->item[i];
+ struct apk_name_state *ns0 = name_to_ns(name0);
+ struct apk_package *pkg0 = ns0->chosen;
+
+ if (!ns0->locked || ns0->chosen == NULL)
+ continue;
+
+ for (j = 0; j < pkg0->depends->num; j++) {
+ struct apk_dependency *dep = &pkg0->depends->item[j];
+ if (dep->name == name)
+ break;
+ }
+ if (j >= pkg0->depends->num)
+ continue;
+
+ cb(pkg0, ctx);
+ }
}
static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependency_array *deps,
@@ -254,7 +288,8 @@ static int get_pkg_expansion_flags(struct apk_solver_state *ss, struct apk_packa
options++;
- if ((ns->solver_flags | ss->solver_flags) & APK_SOLVERF_AVAILABLE) {
+ if ((ns->solver_flags_local | ns->solver_flags_inherited |
+ ss->solver_flags) & APK_SOLVERF_AVAILABLE) {
/* pkg available, pkg0 not */
if (pkg->repos != 0 && pkg0->repos == 0)
continue;
@@ -263,7 +298,8 @@ static int get_pkg_expansion_flags(struct apk_solver_state *ss, struct apk_packa
return APK_PKGSTF_NOINSTALL | APK_PKGSTF_BRANCH;
}
- if ((ns->solver_flags | ss->solver_flags) & APK_SOLVERF_UPGRADE) {
+ if ((ns->solver_flags_local | ns->solver_flags_inherited |
+ ss->solver_flags) & APK_SOLVERF_UPGRADE) {
/* upgrading, or neither of the package is installed, so
* we just fall back comparing to versions */
switch (apk_pkg_version_compare(pkg0, pkg)) {
@@ -296,8 +332,7 @@ static int install_if_missing(struct apk_solver_state *ss, struct apk_package *p
struct apk_dependency *dep = &pkg->install_if->item[i];
ns = name_to_ns(dep->name);
- if (!(ns->flags & APK_NAMESTF_LOCKED) ||
- !apk_dep_is_satisfied(dep, ns->chosen))
+ if (!ns->locked || !apk_dep_is_satisfied(dep, ns->chosen))
missing++;
}
@@ -338,16 +373,16 @@ static int update_name_state(struct apk_solver_state *ss,
}
if (options == 0 && skipped_options == 0) {
- if (!(ns->flags & APK_NAMESTF_NO_OPTIONS)) {
+ if (!ns->no_options) {
ss->cur_unsatisfiable += ns->requirers;
if (ns->install_ifs)
ss->cur_unsatisfiable++;
- ns->flags |= APK_NAMESTF_NO_OPTIONS;
+ ns->no_options = 1;
} else if (requirers_adjustment > 0) {
ss->cur_unsatisfiable += requirers_adjustment;
}
} else
- ns->flags &= ~APK_NAMESTF_NO_OPTIONS;
+ ns->no_options = 0;
if ((options == 0 && skipped_options == 0) ||
(ns->requirers == 0 && ns->install_ifs == 0)) {
@@ -409,7 +444,7 @@ static void apply_decision(struct apk_solver_state *ss,
ss->assigned_names++;
ss->cur_unsatisfiable += ps->conflicts;
ns->chosen = pkg;
- ns->flags |= APK_NAMESTF_LOCKED;
+ ns->locked = 1;
list_del(&ns->unsolved_list);
list_init(&ns->unsolved_list);
@@ -443,7 +478,7 @@ static void undo_decision(struct apk_solver_state *ss,
foreach_rinstall_if_pkg(ss, pkg, untrigger_install_if);
foreach_dependency(ss, pkg->depends, undo_constraint);
- ns->flags &= ~APK_NAMESTF_LOCKED;
+ ns->locked = 0;
ns->chosen = NULL;
}
@@ -514,6 +549,41 @@ static int next_branch(struct apk_solver_state *ss)
return 1;
}
+static void inherit_name_state(struct apk_name *to, struct apk_name *from)
+{
+ struct apk_name_state *tns = name_to_ns(to);
+ struct apk_name_state *fns = name_to_ns(from);
+
+ tns->solver_flags_inherited |=
+ fns->solver_flags_inherited |
+ (fns->solver_flags_local & fns->solver_flags_local_mask);
+}
+
+static void inherit_name_state_wrapper(struct apk_package *rdepend, void *ctx)
+{
+ struct apk_name *name = (struct apk_name *) ctx;
+ inherit_name_state(name, rdepend->name);
+}
+
+static int has_inherited_state(struct apk_name *name)
+{
+ struct apk_name_state *ns = name_to_ns(name);
+
+ if (name == NULL)
+ return 0;
+ if (ns->solver_flags_inherited || (ns->solver_flags_local & ns->solver_flags_local_mask))
+ return 1;
+ return 0;
+}
+
+static void recalculate_inherted_name_state(struct apk_name *name)
+{
+ struct apk_name_state *ns = name_to_ns(name);
+
+ ns->solver_flags_inherited = 0;
+ foreach_locked_reverse_dependency(name, inherit_name_state_wrapper, name);
+}
+
static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
{
struct apk_name *name = dep->name;
@@ -522,7 +592,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
prepare_name(ss, name, ns);
- if (ns->flags & APK_NAMESTF_LOCKED) {
+ if (ns->locked) {
dbg_printf(PKG_VER_FMT " selected already for %s\n",
PKG_VER_PRINTF(ns->chosen), dep->name->name);
if (!apk_dep_is_satisfied(dep, ns->chosen))
@@ -546,6 +616,9 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
}
}
+ if (ss->latest_decision != NULL)
+ inherit_name_state(name, ss->latest_decision->name);
+
update_name_state(ss, name, ns,
(dep->result_mask != APK_DEPMASK_CONFLICT) ? 1 : 0);
}
@@ -556,7 +629,7 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
struct apk_name_state *ns = name_to_ns(name);
int i;
- if (ns->flags & APK_NAMESTF_LOCKED) {
+ if (ns->locked) {
dbg_printf(PKG_VER_FMT " selected already for %s\n",
PKG_VER_PRINTF(ns->chosen), dep->name->name);
return;
@@ -577,6 +650,9 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
}
}
+ if (ss->latest_decision && has_inherited_state(ss->latest_decision->name))
+ recalculate_inherted_name_state(name);
+
update_name_state(ss, name, ns,
(dep->result_mask != APK_DEPMASK_CONFLICT) ? -1 : 0);
}
@@ -689,14 +765,16 @@ static int generate_changeset(struct apk_database *db,
/* calculate change set size */
for (i = 0; i < solution->num; i++) {
pkg = solution->item[i];
+ ns = name_to_ns(pkg->name);
if ((pkg->ipkg == NULL) ||
- ((solver_flags | name_to_ns(pkg->name)->solver_flags) & APK_SOLVERF_REINSTALL))
+ ((ns->solver_flags_local | ns->solver_flags_inherited |
+ solver_flags) & APK_SOLVERF_REINSTALL))
num_installs++;
}
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
name = ipkg->pkg->name;
ns = name_to_ns(name);
- if ((ns->chosen == NULL) || !(ns->flags & APK_NAMESTF_LOCKED))
+ if ((ns->chosen == NULL) || !ns->locked)
num_removed++;
}
@@ -705,7 +783,7 @@ static int generate_changeset(struct apk_database *db,
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
name = ipkg->pkg->name;
ns = name_to_ns(name);
- if ((ns->chosen == NULL) || !(ns->flags & APK_NAMESTF_LOCKED)) {
+ if ((ns->chosen == NULL) || !ns->locked) {
changeset->changes->item[ci].oldpkg = ipkg->pkg;
ci++;
}
@@ -713,9 +791,11 @@ static int generate_changeset(struct apk_database *db,
for (i = 0; i < solution->num; i++) {
pkg = solution->item[i];
name = pkg->name;
+ ns = name_to_ns(name);
if ((pkg->ipkg == NULL) ||
- ((solver_flags | name_to_ns(name)->solver_flags) & APK_SOLVERF_REINSTALL)) {
+ ((ns->solver_flags_local | ns->solver_flags_inherited |
+ solver_flags) & APK_SOLVERF_REINSTALL)) {
for (j = 0; j < name->pkgs->num; j++) {
pkg0 = name->pkgs->item[j];
if (pkg0->ipkg == NULL)
@@ -758,10 +838,12 @@ static int free_package(apk_hash_item item, void *ctx)
}
void apk_solver_set_name_flags(struct apk_name *name,
- unsigned short solver_flags)
+ unsigned short solver_flags,
+ unsigned short solver_flags_inheritable)
{
struct apk_name_state *ns = name_to_ns(name);
- ns->solver_flags = solver_flags;
+ ns->solver_flags_local = solver_flags;
+ ns->solver_flags_local_mask = solver_flags_inheritable;
}
static void apk_solver_free(struct apk_database *db)