summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2013-06-12 08:45:29 +0300
committerTimo Teräs <timo.teras@iki.fi>2013-06-13 18:22:00 +0300
commit426a12686e6e6dcce11616c774176c01ad0985f9 (patch)
tree0fcad980e90c3d679b883c7840af91d5ffb0962e
parentb8c44536ca911418fee1c9ab4eecbb913a1ca852 (diff)
downloadapk-tools-426a12686e6e6dcce11616c774176c01ad0985f9.tar.gz
apk-tools-426a12686e6e6dcce11616c774176c01ad0985f9.tar.bz2
apk-tools-426a12686e6e6dcce11616c774176c01ad0985f9.tar.xz
apk-tools-426a12686e6e6dcce11616c774176c01ad0985f9.zip
solver: rewrite as deductive solver -- per name flags
Handle properly per-name preference flags, and add test cases for testing those via fix applet.
-rw-r--r--src/apk_solver_data.h6
-rw-r--r--src/commit.c19
-rw-r--r--src/solver.c32
-rw-r--r--test/fix1.test9
-rw-r--r--test/fix2.test9
-rw-r--r--test/fix3.test11
-rw-r--r--test/fix4.test8
-rw-r--r--test/fix5.test8
-rw-r--r--test/fix6.test10
9 files changed, 95 insertions, 17 deletions
diff --git a/src/apk_solver_data.h b/src/apk_solver_data.h
index 913829f..47496ac 100644
--- a/src/apk_solver_data.h
+++ b/src/apk_solver_data.h
@@ -37,12 +37,14 @@ struct apk_solver_name_state {
};
struct apk_solver_package_state {
- unsigned short conflicts;
+ unsigned int conflicts;
+ unsigned short max_dep_chain;
+ unsigned solver_flags : 4;
+ unsigned solver_flags_inheritable : 4;
unsigned seen : 1;
unsigned available : 1;
unsigned in_changeset : 1;
unsigned iif_triggered : 1;
- unsigned max_dep_chain : 10;
};
#endif
diff --git a/src/commit.c b/src/commit.c
index 660aab9..2c1d4b5 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -104,15 +104,16 @@ struct apk_stats {
static void count_change(struct apk_change *change, struct apk_stats *stats)
{
- if (change->new_pkg != change->old_pkg) {
+ if (change->new_pkg != change->old_pkg || change->reinstall) {
if (change->new_pkg != NULL) {
stats->bytes += change->new_pkg->installed_size;
- stats->packages ++;
+ stats->packages++;
}
if (change->old_pkg != NULL)
- stats->packages ++;
+ stats->packages++;
stats->changes++;
- } else if (change->reinstall || change->new_repository_tag != change->old_repository_tag) {
+ } else if (change->new_repository_tag != change->old_repository_tag) {
+ stats->packages++;
stats->changes++;
}
}
@@ -157,12 +158,16 @@ static void update_progress(struct progress *prog, size_t percent, int force)
static void progress_cb(void *ctx, size_t pkg_percent)
{
struct progress *prog = (struct progress *) ctx;
- size_t partial = 0, percent;
+ size_t partial = 0, percent, total;
if (prog->pkg != NULL)
partial = muldiv(pkg_percent, prog->pkg->installed_size, APK_PROGRESS_SCALE);
- percent = muldiv(100, prog->done.bytes + prog->done.packages + partial,
- prog->total.bytes + prog->total.packages);
+ total = prog->total.bytes + prog->total.packages;
+ if (total > 0)
+ percent = muldiv(100, prog->done.bytes + prog->done.packages + partial,
+ prog->total.bytes + prog->total.packages);
+ else
+ percent = 0;
update_progress(prog, percent, pkg_percent == 0);
}
diff --git a/src/solver.c b/src/solver.c
index 1e301e7..bc370f6 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -34,9 +34,9 @@ struct apk_solver_state {
struct apk_changeset *changeset;
struct list_head dirty_head;
struct list_head unresolved_head;
- unsigned int solver_flags;
unsigned int errors;
unsigned int num_selections, num_solution_entries;
+ unsigned int solver_flags_inherit;
};
static struct apk_provider provider_none = {
@@ -48,6 +48,13 @@ void apk_solver_set_name_flags(struct apk_name *name,
unsigned short solver_flags,
unsigned short solver_flags_inheritable)
{
+ int i;
+
+ for (i = 0; i < name->providers->num; i++) {
+ struct apk_package *pkg = name->providers->item[i].pkg;
+ pkg->ss.solver_flags |= solver_flags;
+ pkg->ss.solver_flags_inheritable |= solver_flags_inheritable;
+ }
}
static void foreach_dependency(struct apk_solver_state *ss, struct apk_dependency_array *deps,
@@ -181,6 +188,7 @@ static void name_requirers_changed(struct apk_solver_state *ss, struct apk_name
static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency *dep)
{
+ unsigned int solver_flags_inherit = ss->solver_flags_inherit;
struct apk_name *name = dep->name;
int i;
@@ -205,6 +213,10 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
pkg0->ss.conflicts += !is_provided;
if (unlikely(pkg0->ss.available && pkg0->ss.conflicts))
disqualify_package(ss, pkg0, "conflicting dependency");
+ if (is_provided) {
+ pkg0->ss.solver_flags |= solver_flags_inherit;
+ pkg0->ss.solver_flags_inheritable |= solver_flags_inherit;
+ }
}
}
@@ -307,6 +319,7 @@ static int compare_providers(struct apk_solver_state *ss,
{
struct apk_database *db = ss->db;
struct apk_package *pkgA = pA->pkg, *pkgB = pB->pkg;
+ unsigned int solver_flags;
int r;
/* Prefer existing package */
@@ -319,7 +332,8 @@ static int compare_providers(struct apk_solver_state *ss,
return r;
/* Prefer available */
- if (ss->solver_flags & APK_SOLVERF_AVAILABLE) {
+ solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
+ if (solver_flags & APK_SOLVERF_AVAILABLE) {
r = !!(pkgA->repos & db->available_repos) -
!!(pkgB->repos & db->available_repos);
if (r)
@@ -328,7 +342,7 @@ static int compare_providers(struct apk_solver_state *ss,
/* Prefer installed */
/* FIXME: check-per-name flags here too */
- if (!(ss->solver_flags & APK_SOLVERF_UPGRADE)) {
+ if (!(solver_flags & APK_SOLVERF_UPGRADE)) {
r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
if (r)
return r;
@@ -431,7 +445,9 @@ static void select_package(struct apk_solver_state *ss, struct apk_name *name)
struct apk_dependency *p = &pkg->provides->item[i];
assign_name(ss, p->name, APK_PROVIDER_FROM_PROVIDES(pkg, p));
}
+ ss->solver_flags_inherit = pkg->ss.solver_flags_inheritable;
foreach_dependency(ss, pkg->depends, apply_constraint);
+ ss->solver_flags_inherit = 0;
ss->num_selections++;
} else {
dbg_printf("selecting: %s [unassigned]\n", name->name);
@@ -468,11 +484,10 @@ static void generate_change(struct apk_solver_state *ss, struct apk_name *name)
.old_repository_tag = opkg ? opkg->ipkg->repository_tag : 0,
.new_pkg = pkg,
.new_repository_tag = pkg->ipkg ? pkg->ipkg->repository_tag : 0,
+ .reinstall = !!(pkg->ss.solver_flags & APK_SOLVERF_REINSTALL),
#if 0
- /* FIXME: setup reinstall and repository_tag for solution */
- .reinstall = ps->inherited_reinstall ||
- ((name->ss.solver_flags_local | ss->solver_flags) & APK_SOLVERF_REINSTALL),
- .repository_tag = get_tag(db, pinning, repos),
+ /* FIXME: repository_tag from pinning */
+ .new_repository_tag = get_tag(db, pinning, repos),
#endif
};
if (change->new_pkg == NULL)
@@ -585,7 +600,6 @@ int apk_solver_solve(struct apk_database *db,
memset(ss, 0, sizeof(*ss));
ss->db = db;
ss->changeset = changeset;
- ss->solver_flags = solver_flags;
list_init(&ss->dirty_head);
list_init(&ss->unresolved_head);
@@ -594,6 +608,7 @@ int apk_solver_solve(struct apk_database *db,
/* FIXME: If filename specified, force to use it */
dbg_printf("applying world\n");
+ ss->solver_flags_inherit = solver_flags;
for (i = 0; i < world->num; i++) {
struct apk_dependency *dep = &world->item[i];
name = dep->name;
@@ -601,6 +616,7 @@ int apk_solver_solve(struct apk_database *db,
name->ss.preferred_pinning = BIT(dep->repository_tag);
apply_constraint(ss, dep);
}
+ ss->solver_flags_inherit = 0;
dbg_printf("applying world [finished]\n");
do {
diff --git a/test/fix1.test b/test/fix1.test
new file mode 100644
index 0000000..fcc0a98
--- /dev/null
+++ b/test/fix1.test
@@ -0,0 +1,9 @@
+@ARGS
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a
+--upgrade
+fix b
+@EXPECT
+(1/1) Upgrading b (1 -> 2)
+OK: 0 MiB in 2 packages
diff --git a/test/fix2.test b/test/fix2.test
new file mode 100644
index 0000000..25f2198
--- /dev/null
+++ b/test/fix2.test
@@ -0,0 +1,9 @@
+@ARGS
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a
+--upgrade
+fix a
+@EXPECT
+(1/1) Upgrading a (1 -> 2)
+OK: 0 MiB in 2 packages
diff --git a/test/fix3.test b/test/fix3.test
new file mode 100644
index 0000000..364f710
--- /dev/null
+++ b/test/fix3.test
@@ -0,0 +1,11 @@
+@ARGS
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a
+--upgrade
+--depends
+fix a
+@EXPECT
+(1/2) Upgrading b (1 -> 2)
+(2/2) Upgrading a (1 -> 2)
+OK: 0 MiB in 2 packages
diff --git a/test/fix4.test b/test/fix4.test
new file mode 100644
index 0000000..431266b
--- /dev/null
+++ b/test/fix4.test
@@ -0,0 +1,8 @@
+@ARGS
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a
+fix b
+@EXPECT
+(1/1) Re-installing b (1)
+OK: 0 MiB in 2 packages
diff --git a/test/fix5.test b/test/fix5.test
new file mode 100644
index 0000000..33029fc
--- /dev/null
+++ b/test/fix5.test
@@ -0,0 +1,8 @@
+@ARGS
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a
+fix a
+@EXPECT
+(1/1) Re-installing a (1)
+OK: 0 MiB in 2 packages
diff --git a/test/fix6.test b/test/fix6.test
new file mode 100644
index 0000000..c6dc6bd
--- /dev/null
+++ b/test/fix6.test
@@ -0,0 +1,10 @@
+@ARGS
+--test-repo basic.repo
+--test-instdb basic.installed
+--test-world a
+--depends
+fix a
+@EXPECT
+(1/2) Re-installing b (1)
+(2/2) Re-installing a (1)
+OK: 0 MiB in 2 packages