summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/apk_solver.h8
-rw-r--r--src/del.c147
-rw-r--r--src/solver.c25
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);
diff --git a/src/del.c b/src/del.c
index cbf0686..db5da9a 100644
--- a/src/del.c
+++ b/src/del.c
@@ -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);