Commit a5146f1b authored by Timo Teräs's avatar Timo Teräs

solver: generate proper error messages

 * the solver no longer does look-ahead locking of names
   (could be possibly optimized later); instead names are now
   always ordered strictly to properly detect the package names
   which are unsolveable
 * basic error tests added, so we can see the most likely problem
   in dependencies easily
parent 1a04425f
......@@ -24,7 +24,7 @@ struct apk_changeset {
void apk_solver_sort(struct apk_database *db);
int apk_solver_solve(struct apk_database *db, struct apk_dependency_array *world,
struct apk_package_array **solution);
struct apk_package_array **solution, int allow_errors);
int apk_solver_generate_changeset(struct apk_database *db,
struct apk_package_array *solution,
struct apk_changeset *changeset);
......
This diff is collapsed.
......@@ -90,13 +90,67 @@ static inline void print_change(struct apk_package *oldpkg,
}
}
static void print_dep_errors(char *label, struct apk_dependency_array *deps,
struct apk_package **name_pkgs)
{
int i, print_label = 1;
char buf[256];
apk_blob_t p = APK_BLOB_BUF(buf);
for (i = 0; i < deps->num; i++) {
struct apk_dependency *dep = &deps->item[i];
struct apk_package *pkg = name_pkgs[dep->name->id];
if (pkg != NULL && apk_dep_is_satisfied(dep, pkg))
continue;
if (print_label) {
print_label = 0;
printf("%s: ", label);
} else {
printf(" ");
}
apk_blob_push_dep(&p, dep);
p = apk_blob_pushed(APK_BLOB_BUF(buf), p);
fwrite(p.ptr, p.len, 1, stdout);
}
if (!print_label)
printf("\n");
}
static void print_errors_in_solution(struct apk_database *db, int unsatisfiable,
struct apk_package_array *solution)
{
struct apk_package **name_pkg;
int i;
printf("%d unsatisfiable dependencies (solution with %d names)\n",
unsatisfiable, solution->num);
name_pkg = alloca(sizeof(struct apk_package*) * db->available.names.num_items);
memset(name_pkg, 0, sizeof(struct apk_package*) * db->available.names.num_items);
for (i = 0; i < solution->num; i++) {
struct apk_package *pkg = solution->item[i];
name_pkg[pkg->name->id] = pkg;
}
print_dep_errors("world", db->world, name_pkg);
for (i = 0; i < solution->num; i++) {
struct apk_package *pkg = solution->item[i];
char pkgtext[256];
snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(solution->item[i]));
print_dep_errors(pkgtext, pkg->depends, name_pkg);
}
}
static int test_main(void *pctx, struct apk_database *db, int argc, char **argv)
{
struct test_ctx *ctx = (struct test_ctx *) pctx;
struct apk_bstream *bs;
struct apk_package_array *solution = NULL;
struct apk_changeset changeset;
int i;
int i, r;
if (argc != 1)
return -EINVAL;
......@@ -126,16 +180,18 @@ static int test_main(void *pctx, struct apk_database *db, int argc, char **argv)
/* run solver */
apk_solver_sort(db);
if (apk_solver_solve(db, db->world, &solution) != 0)
return 1;
memset(&changeset, 0, sizeof(changeset));
if (apk_solver_generate_changeset(db, solution, &changeset) == 0) {
/* dump changeset */
for (i = 0; i < changeset.changes->num; i++) {
struct apk_change *c = &changeset.changes->item[i];
print_change(c->oldpkg, c->newpkg);
r = apk_solver_solve(db, db->world, &solution, TRUE);
if (r == 0) {
memset(&changeset, 0, sizeof(changeset));
if (apk_solver_generate_changeset(db, solution, &changeset) == 0) {
/* dump changeset */
for (i = 0; i < changeset.changes->num; i++) {
struct apk_change *c = &changeset.changes->item[i];
print_change(c->oldpkg, c->newpkg);
}
}
} else { /* r >= 1*/
print_errors_in_solution(db, r, solution);
}
return 0;
......
--raw-repository basic.repo a
--raw-repository basic.repo
a
--raw-repository basic.repo --installed basic.installed a
--raw-repository basic.repo --installed basic.installed
a
--raw-repository basic.repo --installed basic.installed -u a
--raw-repository basic.repo --installed basic.installed -u
a
--raw-repository basic.repo --installed basic.installed b
--raw-repository basic.repo --installed basic.installed
b
--raw-repository basic.repo --installed basic.installed2 -a a
--raw-repository basic.repo --installed basic.installed2 -a
a
--raw-repository basic.repo --installed basic.installed2 a
--raw-repository basic.repo --installed basic.installed2
a
--no-network --raw-repository basic.repo --installed basic.installed -u a
--no-network --raw-repository basic.repo --installed basic.installed -u
a
--raw-repository complicated1.repo a
--raw-repository complicated1.repo
a
--raw-repository complicated1.repo b
--raw-repository complicated1.repo
b
--raw-repository complicated1.repo c
--raw-repository complicated1.repo
c
--raw-repository complicated1.repo --installed complicated1.installed a
--raw-repository complicated1.repo --installed complicated1.installed
a
3 unsatisfiable dependencies (solution with 3 names)
world: d>1.5
b-1: d<2.0
c-1: d>1.0
--raw-repository complicated1.repo
a d>1.5
4 unsatisfiable dependencies (solution with 3 names)
world: d<1.5
a-3: d>1.5
b-1: d<2.0
c-1: d>1.0
--raw-repository complicated1.repo
a d<1.5
1 unsatisfiable dependencies (solution with 3 names)
world: !b
a-3: b
--raw-repository complicated1.repo
a !b
1 unsatisfiable dependencies (solution with 4 names)
world: nonexistant
--raw-repository complicated1.repo
a nonexistant
3 unsatisfiable dependencies (solution with 3 names)
a-3: d>1.5
b-1: d<2.0
c-1: d>1.0
--raw-repository complicated1.repo
a>2
......@@ -5,8 +5,12 @@ APK_TEST=../src/apk_test
fail=0
for test in *.test; do
bn=$(basename $test .test)
$APK_TEST $(cat $test) &> $bn.got
if ! cmp $bn.expect $bn.got 2> /dev/null; then
(
read options
read world
$APK_TEST $options "$world" &> $bn.got
) < $bn.test
if ! cmp $bn.expect $bn.got &> /dev/null; then
fail=$((fail+1))
echo "FAIL: $test"
diff -ru $bn.expect $bn.got
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment