diff options
-rw-r--r-- | src/apk_solver.h | 8 | ||||
-rw-r--r-- | src/del.c | 147 | ||||
-rw-r--r-- | src/solver.c | 25 |
3 files changed, 158 insertions, 22 deletions
diff --git a/src/apk_solver.h b/src/apk_solver.h index 5ab3147..03a2de5 100644 --- a/src/apk_solver.h +++ b/src/apk_solver.h @@ -31,7 +31,13 @@ int apk_solver_solve(struct apk_database *db, struct apk_dependency_array *world, struct apk_package_array **solution, struct apk_changeset *changeset); - +int apk_solver_commit_changeset(struct apk_database *db, + struct apk_changeset *changeset, + struct apk_dependency_array *world); +void apk_solver_print_errors(struct apk_database *db, + struct apk_package_array *solution, + struct apk_dependency_array *world, + int unsatisfiable); int apk_solver_commit(struct apk_database *db, unsigned short solver_flags, struct apk_dependency_array *world); @@ -15,31 +15,159 @@ #include "apk_print.h" #include "apk_solver.h" -static int del_parse(void *ctx, struct apk_db_options *db, +struct del_ctx { + int recursive_delete : 1; + struct apk_dependency_array *world; +}; + +static int del_parse(void *pctx, struct apk_db_options *db, int optch, int optindex, const char *optarg) { + struct del_ctx *ctx = (struct del_ctx *) pctx; + switch (optch) { case 'r': - /* FIXME: Reimplement recursive delete. */ + ctx->recursive_delete = 1; + break; default: return -1; } return 0; } -static int del_main(void *ctx, struct apk_database *db, int argc, char **argv) +static void foreach_installed_reverse_dependency( + struct apk_package *pkg, + void (*cb)(struct apk_package *rdepend, void *ctx), void *ctx) { struct apk_name *name; - struct apk_dependency_array *world = NULL; + int i, j, k; + + if (pkg == NULL) + return; + + name = pkg->name; + for (i = 0; i < pkg->name->rdepends->num; i++) { + struct apk_name *name0 = pkg->name->rdepends->item[i]; + + for (j = 0; j < name0->pkgs->num; j++) { + struct apk_package *pkg0 = name0->pkgs->item[j]; + + if (pkg0->ipkg == NULL) + continue; + + for (k = 0; k < pkg0->depends->num; k++) { + struct apk_dependency *dep = &pkg0->depends->item[k]; + if (dep->name == name && + (dep->result_mask == APK_DEPMASK_CONFLICT || + apk_dep_is_satisfied(dep, pkg))) + break; + } + if (k >= pkg0->depends->num) + continue; + + cb(pkg0, ctx); + } + } +} + +struct not_deleted_ctx { + struct apk_indent indent; + struct apk_package *pkg; + int header; +}; + +static void print_not_deleted_message(struct apk_package *pkg, + void *pctx) +{ + struct not_deleted_ctx *ctx = (struct not_deleted_ctx *) pctx; + + if (pkg == NULL) + return; + + if (pkg->state_ptr == ctx->pkg) + return; + pkg->state_ptr = ctx->pkg; + + if (!ctx->header) { + apk_message("World updated, but the following packages are not removed due to:"); + ctx->header = 1; + } + if (!ctx->indent.indent) { + ctx->indent.x = printf(" %s:", ctx->pkg->name->name); + ctx->indent.indent = ctx->indent.x + 1; + } + + apk_print_indented(&ctx->indent, APK_BLOB_STR(pkg->name->name)); + foreach_installed_reverse_dependency(pkg, print_not_deleted_message, pctx); +} + +static struct apk_package *name_to_pkg(struct apk_name *name) +{ + int i; + + for (i = 0; i < name->pkgs->num; i++) { + if (name->pkgs->item[i]->ipkg != NULL) + return name->pkgs->item[i]; + } + + return NULL; +} + +static void delete_from_world(struct apk_package *pkg, void *pctx) +{ + struct del_ctx *ctx = (struct del_ctx *) pctx; + + apk_deps_del(&ctx->world, pkg->name); + foreach_installed_reverse_dependency(pkg, delete_from_world, pctx); +} + +static int del_main(void *pctx, struct apk_database *db, int argc, char **argv) +{ + struct del_ctx *ctx = (struct del_ctx *) pctx; + struct apk_name **name; + struct apk_changeset changeset = {}; + struct apk_package_array *solution = NULL; + struct not_deleted_ctx ndctx = {}; int i, r = 0; - apk_dependency_array_copy(&world, db->world); + apk_dependency_array_copy(&ctx->world, db->world); + + name = alloca(argc * sizeof(struct apk_name*)); for (i = 0; i < argc; i++) { - name = apk_db_get_name(db, APK_BLOB_STR(argv[i])); - apk_deps_del(&world, name); + name[i] = apk_db_get_name(db, APK_BLOB_STR(argv[i])); + apk_deps_del(&ctx->world, name[i]); + if (ctx->recursive_delete) + foreach_installed_reverse_dependency( + name_to_pkg(name[i]), + delete_from_world, ctx); + } + + r = apk_solver_solve(db, 0, ctx->world, &solution, &changeset); + if (r == 0 || (apk_flags & APK_FORCE)) { + /* check for non-deleted package names */ + for (i = 0; i < solution->num; i++) { + struct apk_package *pkg = solution->item[i]; + pkg->name->state_ptr = pkg; + pkg->state_int = 0; + } + for (i = 0; i < argc; i++) { + ndctx.pkg = name[i]->state_ptr; + ndctx.indent.indent = 0; + foreach_installed_reverse_dependency( + name[i]->state_ptr, + print_not_deleted_message, &ndctx); + if (ndctx.indent.indent) + printf("\n"); + } + if (ndctx.header) + printf("\n"); + apk_solver_commit_changeset(db, &changeset, ctx->world); + r = 0; + } else { + apk_solver_print_errors(db, solution, ctx->world, r); } - r = apk_solver_commit(db, 0, world); - apk_dependency_array_free(&world); + apk_package_array_free(&solution); + apk_dependency_array_free(&ctx->world); return r; } @@ -54,6 +182,7 @@ static struct apk_applet apk_del = { .help = "Remove PACKAGEs from the main dependencies and uninstall them.", .arguments = "PACKAGE...", .open_flags = APK_OPENF_WRITE, + .context_size = sizeof(struct del_ctx), .num_options = ARRAY_SIZE(del_options), .options = del_options, .parse = del_parse, diff --git a/src/solver.c b/src/solver.c index 72eb3e1..75575c2 100644 --- a/src/solver.c +++ b/src/solver.c @@ -974,14 +974,17 @@ static int cmp_upgrade(struct apk_change *change) return 0; } -static int commit_changeset(struct apk_database *db, - struct apk_changeset *changeset, - struct apk_dependency_array *world) +int apk_solver_commit_changeset(struct apk_database *db, + struct apk_changeset *changeset, + struct apk_dependency_array *world) { struct progress prog; struct apk_change *change; int i, r = 0, size_diff = 0; + if (changeset->changes == NULL) + goto all_done; + /* Count what needs to be done */ memset(&prog, 0, sizeof(prog)); for (i = 0; i < changeset->changes->num; i++) { @@ -1044,6 +1047,7 @@ static int commit_changeset(struct apk_database *db, apk_db_run_triggers(db); +all_done: apk_dependency_array_copy(&db->world, world); apk_db_write_config(db); @@ -1085,10 +1089,10 @@ static void print_dep_errors(char *label, struct apk_dependency_array *deps) printf("\n"); } -static void print_errors(struct apk_database *db, - struct apk_package_array *solution, - struct apk_dependency_array *world, - int unsatisfiable) +void apk_solver_print_errors(struct apk_database *db, + struct apk_package_array *solution, + struct apk_dependency_array *world, + int unsatisfiable) { int i; @@ -1120,16 +1124,13 @@ int apk_solver_commit(struct apk_database *db, if (r < 0) return r; - if (changeset.changes == NULL) - apk_change_array_init(&changeset.changes); - if (r == 0 || (apk_flags & APK_FORCE)) { /* Success -- or forced installation of bad graph */ - commit_changeset(db, &changeset, world); + apk_solver_commit_changeset(db, &changeset, world); r = 0; } else { /* Failure -- print errors */ - print_errors(db, solution, world, r); + apk_solver_print_errors(db, solution, world, r); } apk_package_array_free(&solution); |