summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2013-06-12 17:00:43 +0300
committerTimo Teräs <timo.teras@iki.fi>2013-06-13 18:22:00 +0300
commit25ff68a87e3264b6dfdc846823d4912b4dd870b2 (patch)
treecd0d63eba30d233f52d5bed6e8a89cb64bf7de82 /src/solver.c
parent59678309ea7350a159a3f5ee61c2fb5218dee6d5 (diff)
downloadapk-tools-25ff68a87e3264b6dfdc846823d4912b4dd870b2.tar.gz
apk-tools-25ff68a87e3264b6dfdc846823d4912b4dd870b2.tar.bz2
apk-tools-25ff68a87e3264b6dfdc846823d4912b4dd870b2.tar.xz
apk-tools-25ff68a87e3264b6dfdc846823d4912b4dd870b2.zip
solver: prune broken world dependencies with --force
mostly useful for reboot, when all packages are not available.
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c76
1 files changed, 54 insertions, 22 deletions
diff --git a/src/solver.c b/src/solver.c
index 4823ece..71a4d41 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -78,12 +78,12 @@ static unsigned int get_pkg_repos(struct apk_database *db, struct apk_package *p
return pkg->repos | (pkg->ipkg ? db->repo_tags[pkg->ipkg->repository_tag].allowed_repos : 0);
}
-static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependency_array *deps,
- void (*func)(struct apk_solver_state *ss, struct apk_dependency *dep))
+static void foreach_dependency(struct apk_solver_state *ss, struct apk_package *ppkg, struct apk_dependency_array *deps,
+ void (*func)(struct apk_solver_state *ss, struct apk_package *ppkg, struct apk_dependency *dep))
{
int i;
for (i = 0; i < deps->num; i++)
- func(ss, &deps->item[i]);
+ func(ss, ppkg, &deps->item[i]);
}
static void foreach_name(struct apk_solver_state *ss, struct apk_name_array *names,
@@ -126,6 +126,14 @@ static void foreach_rinstall_if_pkg(
}
}
+static void mark_error(struct apk_solver_state *ss, struct apk_package *pkg)
+{
+ if (pkg == NULL || pkg->ss.error)
+ return;
+ pkg->ss.error = 1;
+ ss->errors++;
+}
+
static void queue_dirty(struct apk_solver_state *ss, struct apk_name *name)
{
if (list_hashed(&name->ss.dirty_list) || name->ss.locked ||
@@ -199,7 +207,8 @@ static int dependency_satisfiable(struct apk_solver_state *ss, struct apk_depend
}
static void discover_name(struct apk_solver_state *ss, struct apk_name *name);
-static void discover_names(struct apk_solver_state *ss, struct apk_dependency *dep)
+
+static void discover_names(struct apk_solver_state *ss, struct apk_package *ppkg, struct apk_dependency *dep)
{
discover_name(ss, dep->name);
}
@@ -227,7 +236,7 @@ static void discover_name(struct apk_solver_state *ss, struct apk_name *name)
pkg->ss.tag_ok = !!(repos & ss->default_repos);
pkg->ss.tag_preferred = !!(repos & ss->default_repos);
- foreach_dependency(ss, pkg->depends, discover_names);
+ foreach_dependency(ss, pkg, pkg->depends, discover_names);
for (j = 0; j < pkg->depends->num; j++)
pkg->ss.max_dep_chain = max(pkg->ss.max_dep_chain,
pkg->depends->item[j].name->ss.max_dep_chain+1);
@@ -264,7 +273,7 @@ static void inherit_pinning(struct apk_solver_state *ss, struct apk_package *pkg
}
}
-static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
+static void apply_constraint(struct apk_solver_state *ss, struct apk_package *ppkg, struct apk_dependency *dep)
{
struct apk_name *name = dep->name;
unsigned int solver_flags_inherit = ss->solver_flags_inherit;
@@ -503,8 +512,9 @@ static void assign_name(struct apk_solver_state *ss, struct apk_name *name, stru
if (p.version == &apk_null_blob &&
name->ss.chosen.version == &apk_null_blob)
return;
- /* Othewise providing locked item is an error */
- ss->errors++;
+ /* Conflict: providing same name */
+ mark_error(ss, p.pkg);
+ mark_error(ss, name->ss.chosen.pkg);
return;
}
@@ -560,11 +570,13 @@ static void select_package(struct apk_solver_state *ss, struct apk_name *name)
if (chosen.version == &apk_null_blob) {
/* Pure virtual package */
assign_name(ss, name, provider_none);
- ss->errors++;
+ ss->errors += (name->ss.requirers > 0);
return;
}
- if (!pkg->ss.available || !pkg->ss.tag_ok)
- ss->errors++;
+ if (!pkg->ss.available || !pkg->ss.tag_ok) {
+ /* Selecting broken or unallowed package */
+ mark_error(ss, pkg);
+ }
dbg_printf("selecting: " PKG_VER_FMT ", available: %d\n", PKG_VER_PRINTF(pkg), pkg->ss.available);
assign_name(ss, pkg->name, APK_PROVIDER_FROM_PACKAGE(pkg));
for (i = 0; i < pkg->provides->num; i++) {
@@ -573,19 +585,18 @@ static void select_package(struct apk_solver_state *ss, struct apk_name *name)
}
ss->solver_flags_inherit = pkg->ss.solver_flags_inheritable;
ss->pinning_inherit = pkg->ss.pinning_allowed;
- foreach_dependency(ss, pkg->depends, apply_constraint);
+ foreach_dependency(ss, pkg, pkg->depends, apply_constraint);
ss->solver_flags_inherit = 0;
ss->pinning_inherit = 0;
ss->num_selections++;
} else {
dbg_printf("selecting: %s [unassigned]\n", name->name);
assign_name(ss, name, provider_none);
- if (name->ss.requirers)
- ss->errors++;
+ ss->errors += (name->ss.requirers > 0);
}
}
-static void generate_change_dep(struct apk_solver_state *ss, struct apk_dependency *dep);
+static void generate_change_dep(struct apk_solver_state *ss, struct apk_package *ppkg, struct apk_dependency *dep);
static void generate_change_iif(struct apk_solver_state *ss, struct apk_name *name);
static void generate_change(struct apk_solver_state *ss, struct apk_name *name)
@@ -602,7 +613,7 @@ static void generate_change(struct apk_solver_state *ss, struct apk_name *name)
pkg->ss.in_changeset = 1;
pkg->name->ss.in_changeset = 1;
- foreach_dependency(ss, pkg->depends, generate_change_dep);
+ foreach_dependency(ss, pkg, pkg->depends, generate_change_dep);
change = &changeset->changes->item[ss->num_solution_entries++];
dbg_printf("Selecting: "PKG_VER_FMT"%s\n", PKG_VER_PRINTF(pkg), pkg->ss.available ? "" : " [NOT AVAILABLE]");
@@ -646,14 +657,18 @@ static void generate_change_iif(struct apk_solver_state *ss, struct apk_name *na
generate_change(ss, name);
}
-static void generate_change_dep(struct apk_solver_state *ss, struct apk_dependency *dep)
+static void generate_change_dep(struct apk_solver_state *ss, struct apk_package *ppkg, struct apk_dependency *dep)
{
struct apk_name *name = dep->name;
+ struct apk_package *pkg = name->ss.chosen.pkg;
if (!apk_dep_is_provided(dep, &name->ss.chosen))
- ss->errors++;
+ mark_error(ss, ppkg);
generate_change(ss, name);
+
+ if (pkg && pkg->ss.error)
+ mark_error(ss, ppkg);
}
static void generate_changeset(struct apk_solver_state *ss, struct apk_dependency_array *world)
@@ -668,7 +683,7 @@ static void generate_changeset(struct apk_solver_state *ss, struct apk_dependenc
}
apk_change_array_resize(&ss->changeset->changes, ss->num_selections);
- foreach_dependency(ss, world, generate_change_dep);
+ foreach_dependency(ss, NULL, world, generate_change_dep);
/* FIXME: could order better the removals of unneeded packages */
list_for_each_entry(ipkg, &ss->db->installed.packages, installed_pkgs_list) {
@@ -721,6 +736,7 @@ int apk_solver_solve(struct apk_database *db,
struct apk_solver_state ss_data, *ss = &ss_data;
int i;
+restart:
memset(ss, 0, sizeof(*ss));
ss->db = db;
ss->changeset = changeset;
@@ -728,17 +744,19 @@ int apk_solver_solve(struct apk_database *db,
list_init(&ss->dirty_head);
list_init(&ss->unresolved_head);
- foreach_dependency(ss, world, discover_names);
+ foreach_dependency(ss, NULL, world, discover_names);
dbg_printf("applying world\n");
ss->prefer_pinning = 1;
ss->solver_flags_inherit = solver_flags;
for (i = 0; i < world->num; i++) {
struct apk_dependency *dep = &world->item[i];
+ if (dep->broken)
+ continue;
name = dep->name;
name->ss.in_world_dependency = 1;
ss->pinning_inherit = BIT(dep->repository_tag);
- apply_constraint(ss, dep);
+ apply_constraint(ss, NULL, dep);
}
ss->solver_flags_inherit = 0;
ss->pinning_inherit = 0;
@@ -776,9 +794,23 @@ int apk_solver_solve(struct apk_database *db,
generate_changeset(ss, world);
+ if (ss->errors && (apk_flags & APK_FORCE)) {
+ for (i = 0; i < world->num; i++) {
+ struct apk_dependency *dep = &world->item[i];
+ struct apk_name *name = dep->name;
+ struct apk_package *pkg = name->ss.chosen.pkg;
+ if (pkg == NULL || pkg->ss.error) {
+ dep->broken = 1;
+ dbg_printf("disabling broken world dep: %s", name->name);
+ }
+ }
+ apk_hash_foreach(&db->available.names, free_state, NULL);
+ apk_hash_foreach(&db->available.packages, free_package, NULL);
+ goto restart;
+ }
+
apk_hash_foreach(&db->available.names, free_state, NULL);
apk_hash_foreach(&db->available.packages, free_package, NULL);
-
dbg_printf("solver done, errors=%d\n", ss->errors);
return ss->errors;