summaryrefslogtreecommitdiff
path: root/src/state.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2011-09-09 16:31:11 +0300
committerTimo Teräs <timo.teras@iki.fi>2011-09-09 16:32:31 +0300
commita5a7021658212748e9f787ce23181d3e099aba73 (patch)
tree459384995fc52f096007c3ed4d8d88ca865f998c /src/state.c
parent0e24207c2e4fedb9c0656ed98bc37cd37df44d91 (diff)
downloadapk-tools-a5a7021658212748e9f787ce23181d3e099aba73.tar.gz
apk-tools-a5a7021658212748e9f787ce23181d3e099aba73.tar.bz2
apk-tools-a5a7021658212748e9f787ce23181d3e099aba73.tar.xz
apk-tools-a5a7021658212748e9f787ce23181d3e099aba73.zip
applets: start using solver code
still todo: - 'fix' is missing - 'del -R' does not work - 'upgrade' does not do self-upgrade first ... and a lot of testing.
Diffstat (limited to 'src/state.c')
-rw-r--r--src/state.c1059
1 files changed, 0 insertions, 1059 deletions
diff --git a/src/state.c b/src/state.c
deleted file mode 100644
index 3889162..0000000
--- a/src/state.c
+++ /dev/null
@@ -1,1059 +0,0 @@
-/* state.c - Alpine Package Keeper (APK)
- *
- * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
- * Copyright (C) 2008 Timo Teräs <timo.teras@iki.fi>
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation. See http://www.gnu.org/ for details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <malloc.h>
-
-#include "apk_state.h"
-#include "apk_database.h"
-#include "apk_print.h"
-
-struct apk_name_choices {
- unsigned short refs, num;
- struct apk_package *pkgs[];
-};
-
-#if 0
-struct apk_deferred_state {
- unsigned int preference;
- struct apk_state *state;
-};
-#endif
-
-int apk_state_prune_dependency(struct apk_state *state,
- struct apk_dependency *dep);
-
-#define APK_NS_LOCKED 0x00000001
-#define APK_NS_PENDING 0x00000002
-#define APK_NS_ERROR 0x00000004
-
-static void apk_state_record_conflict(struct apk_state *state,
- struct apk_package *pkg)
-{
- struct apk_name *name = pkg->name;
-
- state->name[name->id] = (void*) (((intptr_t) pkg) | APK_NS_ERROR | APK_NS_LOCKED);
- *apk_package_array_add(&state->conflicts) = pkg;
-}
-
-static int inline ns_locked(apk_name_state_t name)
-{
- if (((intptr_t) name) & APK_NS_LOCKED)
- return TRUE;
- return FALSE;
-}
-
-static int inline ns_pending(apk_name_state_t name)
-{
- if (((intptr_t) name) & APK_NS_PENDING)
- return TRUE;
- return FALSE;
-}
-
-static int inline ns_error(apk_name_state_t name)
-{
- if (((intptr_t) name) & APK_NS_ERROR)
- return TRUE;
- return FALSE;
-}
-
-static int ns_empty(apk_name_state_t name)
-{
- return name == NULL;
-}
-
-static apk_name_state_t ns_from_pkg(struct apk_package *pkg)
-{
- return (apk_name_state_t) (((intptr_t) pkg) | APK_NS_LOCKED | APK_NS_PENDING);
-}
-
-static apk_name_state_t ns_from_pkg_non_pending(struct apk_package *pkg)
-{
- return (apk_name_state_t) (((intptr_t) pkg) | APK_NS_LOCKED);
-}
-
-static struct apk_package *ns_to_pkg(apk_name_state_t name)
-{
- return (struct apk_package *)
- (((intptr_t) name) & ~(APK_NS_LOCKED | APK_NS_PENDING | APK_NS_ERROR));
-}
-
-static apk_name_state_t ns_from_choices(struct apk_name_choices *nc)
-{
- if (nc == NULL)
- return ns_from_pkg(NULL);
- return (apk_name_state_t) nc;
-}
-
-static struct apk_name_choices *ns_to_choices(apk_name_state_t name)
-{
- return (struct apk_name_choices *) name;
-}
-
-static struct apk_name_choices *name_choices_new(struct apk_database *db,
- struct apk_name *name)
-{
- struct apk_name_choices *nc;
- int i, j;
-
- if (name->pkgs->num == 0)
- return NULL;
-
- nc = malloc(sizeof(struct apk_name_choices) +
- name->pkgs->num * sizeof(struct apk_package *));
- if (nc == NULL)
- return NULL;
-
- nc->refs = 1;
- nc->num = name->pkgs->num;
- memcpy(nc->pkgs, name->pkgs->item,
- name->pkgs->num * sizeof(struct apk_package *));
-
- for (j = 0; j < nc->num; ) {
- if (nc->pkgs[j]->filename != APK_PKG_UNINSTALLABLE) {
- j++;
- } else {
- nc->pkgs[j] = nc->pkgs[nc->num - 1];
- nc->num--;
- }
- }
-
- if (name->flags & APK_NAME_TOPLEVEL_OVERRIDE)
- return nc;
-
- /* Check for global dependencies */
- for (i = 0; i < db->world->num; i++) {
- struct apk_dependency *dep = &db->world->item[i];
-
- if (dep->name != name)
- continue;
-
- if (apk_flags & APK_PREFER_AVAILABLE) {
- dep->version = apk_blob_atomize(APK_BLOB_NULL);
- dep->result_mask = APK_DEPMASK_REQUIRE;
- } else {
- for (j = 0; j < nc->num; ) {
- if (apk_dep_is_satisfied(dep, nc->pkgs[j])) {
- j++;
- } else {
- nc->pkgs[j] = nc->pkgs[nc->num - 1];
- nc->num--;
- }
- }
- }
- break;
- }
-
- return nc;
-}
-
-static void name_choices_unref(struct apk_name_choices *nc)
-{
- if (--nc->refs == 0)
- free(nc);
-}
-
-static struct apk_name_choices *name_choices_writable(struct apk_name_choices *nc)
-{
- struct apk_name_choices *n;
-
- if (nc->refs == 1)
- return nc;
-
- n = malloc(sizeof(struct apk_name_choices) +
- nc->num * sizeof(struct apk_package *));
- if (n == NULL)
- return NULL;
-
- n->refs = 1;
- n->num = nc->num;
- memcpy(n->pkgs, nc->pkgs, nc->num * sizeof(struct apk_package *));
- name_choices_unref(nc);
-
- return n;
-}
-
-static void ns_free(apk_name_state_t name)
-{
- if (!ns_empty(name) && !ns_locked(name))
- name_choices_unref(ns_to_choices(name));
-}
-
-static inline int apk_state_pkg_available(struct apk_state *state,
- struct apk_package *pkg)
-{
- if (pkg->ipkg != NULL)
- return TRUE;
- if (pkg->installed_size == 0)
- return TRUE;
- if (pkg->filename != NULL)
- return TRUE;
- if (apk_db_select_repo(state->db, pkg) != NULL)
- return TRUE;
- return FALSE;
-}
-
-struct apk_state *apk_state_new(struct apk_database *db)
-{
- struct apk_state *state;
- int num_bytes;
-
- num_bytes = sizeof(struct apk_state) + db->name_id * sizeof(char *);
- state = (struct apk_state*) calloc(1, num_bytes);
- state->refs = 1;
- state->num_names = db->name_id;
- state->db = db;
- state->print_ok = 1;
- list_init(&state->change_list_head);
-
- apk_name_array_init(&state->missing);
- apk_package_array_init(&state->conflicts);
-
- return state;
-}
-
-struct apk_state *apk_state_dup(struct apk_state *state)
-{
- state->refs++;
- return state;
-}
-
-void apk_state_unref(struct apk_state *state)
-{
- if (--state->refs > 0)
- return;
-
- apk_package_array_free(&state->conflicts);
- apk_name_array_free(&state->missing);
- free(state);
-}
-
-static struct apk_package *get_locked_or_installed_package(
- struct apk_state *state,
- struct apk_name *name)
-{
- int i;
-
- if (ns_locked(state->name[name->id]))
- return ns_to_pkg(state->name[name->id]);
-
- if (!ns_empty(state->name[name->id])) {
- struct apk_name_choices *ns =
- ns_to_choices(state->name[name->id]);
-
- for (i = 0; i < ns->num; i++) {
- if (ns->pkgs[i]->ipkg != NULL)
- return ns->pkgs[i];
- }
- return NULL;
- }
-
- for (i = 0; i < name->pkgs->num; i++) {
- if (name->pkgs->item[i]->ipkg != NULL)
- return name->pkgs->item[i];
- }
- return NULL;
-}
-
-static int check_dependency(struct apk_state *state,
- struct apk_dependency *dep)
-{
- struct apk_package *pkg;
-
- pkg = get_locked_or_installed_package(state, dep->name);
- if (pkg == NULL && dep->result_mask != APK_DEPMASK_CONFLICT)
- return 0;
- if (!apk_dep_is_satisfied(dep, pkg))
- return 0;
-
- return 1;
-}
-
-static int check_dependency_array(struct apk_state *state,
- struct apk_dependency_array *da)
-{
- int i;
-
- for (i = 0; i < da->num; i++) {
- if (!check_dependency(state, &da->item[i]))
- return 0;
- }
-
- return da->num;
-}
-
-static int apk_state_add_change(struct apk_state *state,
- struct apk_package *oldpkg,
- struct apk_package *newpkg)
-{
- struct apk_change *change;
-
- change = (struct apk_change *) malloc(sizeof(struct apk_change));
- if (change == NULL)
- return -1;
-
- list_init(&change->change_list);
- list_add_tail(&change->change_list, &state->change_list_head);
- state->num_changes++;
- change->oldpkg = oldpkg;
- change->newpkg = newpkg;
-
- return 0;
-}
-
-/* returns:
- * -1 error
- * 0 locked entry matches and is ok
- * +n this many candidates on apk_name_choices for the name
- */
-int apk_state_prune_dependency(struct apk_state *state,
- struct apk_dependency *dep)
-{
- struct apk_name *name = dep->name;
- struct apk_name_choices *c;
- int i;
-
- if (name->id >= state->num_names)
- return -1;
-
- if (ns_empty(state->name[name->id])) {
- if (dep->result_mask == APK_DEPMASK_CONFLICT) {
- state->name[name->id] = ns_from_pkg(NULL);
- return 1;
- }
-
- /* This name has not been visited yet.
- * Construct list of candidates. */
- state->name[name->id] = ns_from_choices(name_choices_new(state->db, name));
- }
-
- if (ns_locked(state->name[name->id])) {
- /* Locked: check that selected package provides
- * requested version. */
- struct apk_package *pkg = ns_to_pkg(state->name[name->id]);
-
- /* Locked to not-installed / remove? */
- if (ns_error(state->name[name->id])) {
- return -1;
- } else if (pkg == NULL) {
- if (dep->result_mask != APK_DEPMASK_CONFLICT) {
- if (ns_pending(state->name[name->id])) {
- state->name[name->id] = ns_from_pkg_non_pending(NULL);
- *apk_name_array_add(&state->missing) = name;
- }
- return -1;
- }
- } else {
- if (!apk_dep_is_satisfied(dep, pkg))
- return -1;
- }
-
- if (ns_pending(state->name[name->id]))
- return 1;
-
- return 0;
- }
-
- /* Multiple candidates: prune incompatible versions. */
- c = ns_to_choices(state->name[name->id]);
- i = 0;
- while (i < c->num) {
- if (apk_dep_is_satisfied(dep, c->pkgs[i])) {
- i++;
- continue;
- }
-
- c = name_choices_writable(c);
- c->pkgs[i] = c->pkgs[c->num - 1];
- c->num--;
- }
- if (c->num == 1 && apk_state_pkg_available(state, c->pkgs[0])) {
- struct apk_package *pkg = c->pkgs[0];
- name_choices_unref(c);
- state->name[name->id] = ns_from_pkg(pkg);
- return 1;
- }
- if (c->num <= 1) {
- name_choices_unref(c);
- state->name[name->id] = ns_from_pkg(NULL);
- *apk_name_array_add(&state->missing) = name;
- return -1;
- }
-
- state->name[name->id] = ns_from_choices(c);
- return c->num;
-}
-
-int apk_state_autolock_name(struct apk_state *state, struct apk_name *name,
- int install_if)
-{
- struct apk_name_choices *c;
- struct apk_package *installed = NULL, *latest = NULL, *use;
- int i;
-
- if (ns_pending(state->name[name->id]))
- return apk_state_lock_name(state, name, ns_to_pkg(state->name[name->id]));
- if (ns_locked(state->name[name->id]))
- return 0;
- if (ns_empty(state->name[name->id])) {
- /* This name has not been visited yet.
- * Construct list of candidates. */
- state->name[name->id] = ns_from_choices(name_choices_new(state->db, name));
- }
-
- c = ns_to_choices(state->name[name->id]);
-#if 1
- /* Get latest and installed packages */
- for (i = 0; i < c->num; i++) {
- struct apk_package *pkg = c->pkgs[i];
-
- if (install_if &&
- !check_dependency_array(state, pkg->install_if))
- continue;
-
- if (pkg->ipkg != NULL)
- installed = pkg;
- else if (!apk_state_pkg_available(state, pkg))
- continue;
-
- if (latest == NULL) {
- latest = pkg;
- continue;
- }
-
- if ((apk_flags & APK_PREFER_AVAILABLE) ||
- (name->flags & APK_NAME_REINSTALL)) {
- if (latest->repos != 0 && pkg->repos == 0)
- continue;
-
- if (latest->repos == 0 && pkg->repos != 0) {
- latest = pkg;
- continue;
- }
-
- /* Otherwise both are not available, or both are
- * available and we just compare the versions then */
- }
-
- if (apk_pkg_version_compare(pkg, latest) == APK_VERSION_GREATER)
- latest = pkg;
- }
-
- /* Choose the best looking candidate.
- * FIXME: We should instead try all alternatives. */
- if (apk_flags & APK_UPGRADE) {
- use = latest;
- } else {
- if (installed != NULL &&
- (installed->repos != 0 ||
- !(name->flags & APK_NAME_REINSTALL)))
- use = installed;
- else
- use = latest;
- }
- if (use == NULL)
- return -2;
-
- /* Install_if check did not result in package selection change:
- * do not lock the package yet as the preferency might change
- * later. */
- if (install_if && use->ipkg != NULL)
- return 0;
-
- return apk_state_lock_name(state, name, use);
-#else
- /* If any of the choices is installed, we are good. Otherwise,
- * the caller needs to install this dependency. */
- for (i = 0; i < c->num; i++)
- if (apk_pkg_get_state(c->pkgs[i]) == APK_PKG_INSTALLED)
- return 0;
-
- /* Queue for deferred solution. */
- return 0;
-#endif
-}
-
-int apk_state_lock_dependency(struct apk_state *state,
- struct apk_dependency *dep)
-{
- int r;
-
- r = apk_state_prune_dependency(state, dep);
- if (r <= 0)
- return r;
-
- return apk_state_autolock_name(state, dep->name, FALSE);
-}
-
-static int apk_state_fix_package(struct apk_state *state,
- struct apk_package *pkg)
-{
- int i, r, ret = 0;
-
- if (pkg == NULL)
- return 0;
-
- for (i = 0; i < pkg->depends->num; i++) {
- if ((pkg->depends->item[i].name->flags & APK_NAME_TOPLEVEL_OVERRIDE) &&
- check_dependency(state, &pkg->depends->item[i])) {
- r = apk_state_prune_dependency(state,
- &pkg->depends->item[i]);
- if (r < 0)
- ret = -1;
- } else {
- r = apk_state_lock_dependency(state,
- &pkg->depends->item[i]);
- if (r != 0)
- ret = -1;
- }
- }
- return ret;
-}
-
-static int call_if_dependency_broke(struct apk_state *state,
- struct apk_package *pkg,
- struct apk_name *dep_name,
- int (*cb)(struct apk_state *state,
- struct apk_package *pkg,
- struct apk_dependency *dep,
- void *ctx),
- void *ctx)
-{
- struct apk_package *dep_pkg;
- int k;
-
- dep_pkg = ns_to_pkg(state->name[dep_name->id]);
- for (k = 0; k < pkg->depends->num; k++) {
- struct apk_dependency *dep = &pkg->depends->item[k];
- if (dep->name != dep_name)
- continue;
- if (dep_pkg == NULL &&
- dep->result_mask == APK_DEPMASK_CONFLICT)
- continue;
- if (dep_pkg != NULL &&
- apk_dep_is_satisfied(dep, dep_pkg))
- continue;
- return cb(state, pkg, dep, ctx);
- }
-
- return 0;
-}
-
-static int for_each_broken_reverse_depency(struct apk_state *state,
- struct apk_name *name,
- int (*cb)(struct apk_state *state,
- struct apk_package *pkg,
- struct apk_dependency *dep,
- void *ctx),
- void *ctx)
-{
- struct apk_package *pkg0;
- int i, r;
-
- for (i = 0; i < name->rdepends->num; i++) {
- struct apk_name *name0 = name->rdepends->item[i];
-
- pkg0 = get_locked_or_installed_package(state, name0);
- if (pkg0 == NULL)
- continue;
-
- r = call_if_dependency_broke(state, pkg0, name,
- cb, ctx);
- if (r != 0)
- return r;
- }
-
- return 0;
-}
-
-static int delete_broken_package(struct apk_state *state,
- struct apk_package *pkg,
- struct apk_dependency *dep,
- void *ctx)
-{
- return apk_state_lock_name(state, pkg->name, NULL);
-}
-
-static int reinstall_broken_package(struct apk_state *state,
- struct apk_package *pkg,
- struct apk_dependency *dep,
- void *ctx)
-
-{
- struct apk_dependency dep0 = {
- .name = pkg->name,
- .version = apk_blob_atomize(APK_BLOB_NULL),
- .result_mask = APK_DEPMASK_REQUIRE,
- };
- return apk_state_lock_dependency(state, &dep0);
-}
-
-int apk_state_lock_name(struct apk_state *state,
- struct apk_name *name,
- struct apk_package *newpkg)
-{
- struct apk_package *oldpkg = NULL;
- int i, r;
-
- if (name->id >= state->num_names)
- return -1;
-
- ns_free(state->name[name->id]);
- state->name[name->id] = ns_from_pkg_non_pending(newpkg);
-
- for (i = 0; i < name->pkgs->num; i++) {
- struct apk_package *pkg = name->pkgs->item[i];
- if (name->pkgs->item[i]->name == name &&
- pkg->ipkg != NULL)
- oldpkg = pkg;
- }
-
- /* First we need to make sure the dependants of the old package
- * still have their dependencies ok. */
- if (oldpkg != NULL) {
- r = for_each_broken_reverse_depency(state, name,
- newpkg == NULL ?
- delete_broken_package :
- reinstall_broken_package,
- NULL);
- if (r != 0) {
- apk_state_record_conflict(state, newpkg);
- return r;
- }
- }
-
- /* Check that all other dependencies hold for the new package. */
- r = apk_state_fix_package(state, newpkg);
- if (r != 0) {
- apk_state_record_conflict(state, newpkg);
- return r;
- }
-
- /* If the chosen package is installed, all is done here */
- if ((oldpkg != newpkg) ||
- (newpkg != NULL && (newpkg->name->flags & APK_NAME_REINSTALL))) {
- /* Track change */
- r = apk_state_add_change(state, oldpkg, newpkg);
- if (r != 0)
- return r;
- }
-
- /* Check all reverse install_if's */
- if (newpkg != NULL) {
- for (i = 0; i < newpkg->name->rinstall_if->num; i++)
- apk_state_autolock_name(state, newpkg->name->rinstall_if->item[i], TRUE);
- }
-
- return 0;
-}
-
-static void apk_print_change(struct apk_database *db,
- struct apk_package *oldpkg,
- struct apk_package *newpkg,
- int num, int total)
-{
- const char *msg = NULL;
- int r;
- struct apk_name *name;
- char status[64];
-
- snprintf(status, sizeof(status), "(%i/%i)", num, total);
- status[sizeof(status) - 1] = '\0';
-
- if (oldpkg != NULL)
- name = oldpkg->name;
- else
- name = newpkg->name;
-
- if (oldpkg == NULL) {
- apk_message("%s Installing %s (" BLOB_FMT ")",
- status, name->name,
- BLOB_PRINTF(*newpkg->version));
- } else if (newpkg == NULL) {
- apk_message("%s Purging %s (" BLOB_FMT ")",
- status, name->name,
- BLOB_PRINTF(*oldpkg->version));
- } else {
- r = apk_pkg_version_compare(newpkg, oldpkg);
- switch (r) {
- case APK_VERSION_LESS:
- msg = "Downgrading";
- break;
- case APK_VERSION_EQUAL:
- if (newpkg == oldpkg)
- msg = "Re-installing";
- else
- msg = "Replacing";
- break;
- case APK_VERSION_GREATER:
- msg = "Upgrading";
- break;
- }
- apk_message("%s %s %s (" BLOB_FMT " -> " BLOB_FMT ")",
- status, msg, name->name,
- BLOB_PRINTF(*oldpkg->version),
- BLOB_PRINTF(*newpkg->version));
- }
-}
-
-struct apk_stats {
- unsigned int bytes;
- unsigned int packages;
-};
-
-static void apk_count_change(struct apk_change *change, struct apk_stats *stats)
-{
- if (change->newpkg != NULL) {
- stats->bytes += change->newpkg->installed_size;
- stats->packages ++;
- }
- if (change->oldpkg != NULL)
- stats->packages ++;
-}
-
-static void apk_draw_progress(int percent)
-{
- const int bar_width = apk_get_screen_width() - 7;
- int i;
-
- fprintf(stderr, "\e7%3i%% [", percent);
- for (i = 0; i < bar_width * percent / 100; i++)
- fputc('#', stderr);
- for (; i < bar_width; i++)
- fputc(' ', stderr);
- fputc(']', stderr);
- fflush(stderr);
- fputs("\e8\e[0K", stderr);
-}
-
-struct progress {
- struct apk_stats done;
- struct apk_stats total;
- struct apk_package *pkg;
- size_t count;
-};
-
-static void progress_cb(void *ctx, size_t progress)
-{
- struct progress *prog = (struct progress *) ctx;
- size_t partial = 0, count;
-
- if (prog->pkg != NULL)
- partial = muldiv(progress, prog->pkg->installed_size, APK_PROGRESS_SCALE);
-
- count = muldiv(100, prog->done.bytes + prog->done.packages + partial,
- prog->total.bytes + prog->total.packages);
-
- if (prog->count != count)
- apk_draw_progress(count);
- prog->count = count;
-}
-
-static int dump_packages(struct apk_state *state,
- int (*cmp)(struct apk_change *change),
- const char *msg)
-{
- struct apk_change *change;
- struct apk_name *name;
- struct apk_indent indent = { 0, 2 };
- char tmp[256];
- int match = 0, i;
-
- list_for_each_entry(change, &state->change_list_head, change_list) {
- if (!cmp(change))
- continue;
- if (match == 0)
- printf("%s:\n ", msg);
- if (change->newpkg != NULL)
- name = change->newpkg->name;
- else
- name = change->oldpkg->name;
-
- i = snprintf(tmp, sizeof(tmp), "%s%s", name->name,
- (name->flags & APK_NAME_TOPLEVEL) ? "*" : "");
- apk_print_indented(&indent, APK_BLOB_PTR_LEN(tmp, i));
- match++;
- }
- if (match)
- printf("\n");
- return match;
-}
-
-static int cmp_remove(struct apk_change *change)
-{
- return change->newpkg == NULL;
-}
-
-static int cmp_new(struct apk_change *change)
-{
- return change->oldpkg == NULL;
-}
-
-static int cmp_downgrade(struct apk_change *change)
-{
- if (change->newpkg == NULL || change->oldpkg == NULL)
- return 0;
- if (apk_pkg_version_compare(change->newpkg, change->oldpkg)
- & APK_VERSION_LESS)
- return 1;
- return 0;
-}
-
-static int cmp_upgrade(struct apk_change *change)
-{
- if (change->newpkg == NULL || change->oldpkg == NULL)
- return 0;
-
- /* Count swapping package as upgrade too - this can happen if
- * same package version is used after it was rebuilt against
- * newer libraries. Basically, different (and probably newer)
- * package, but equal version number. */
- if ((apk_pkg_version_compare(change->newpkg, change->oldpkg) &
- (APK_VERSION_GREATER | APK_VERSION_EQUAL)) &&
- (change->newpkg != change->oldpkg))
- return 1;
-
- return 0;
-}
-
-static int fail_if_something_broke(struct apk_state *state,
- struct apk_package *pkg,
- struct apk_dependency *dep,
- void *ctx)
-
-{
- return 1;
-}
-
-static int apk_state_autoclean(struct apk_state *state,
- struct apk_package *pkg)
-{
- apk_name_state_t oldns;
- int i, r;
-
- for (i = 0; i < pkg->depends->num; i++) {
- struct apk_name *n = pkg->depends->item[i].name;
-
- if (ns_locked(state->name[n->id]))
- continue;
- if (n->flags & APK_NAME_TOPLEVEL)
- continue;
-
- oldns = state->name[n->id];
- state->name[n->id] = ns_from_pkg(NULL);
- r = for_each_broken_reverse_depency(state, n,
- fail_if_something_broke,
- NULL);
- state->name[n->id] = oldns;
-
- if (r == 0) {
- r = apk_state_lock_name(state, n, NULL);
- if (r != 0)
- return r;
- }
- }
-
- for (i = 0; i < pkg->name->rinstall_if->num; i++) {
- struct apk_name *n = pkg->name->rinstall_if->item[i];
-
- if (ns_locked(state->name[n->id]))
- continue;
- if (n->flags & APK_NAME_TOPLEVEL)
- continue;
-
- r = apk_state_autolock_name(state, n, TRUE);
- if (r == -2) {
- r = apk_state_lock_name(state, n, NULL);
- if (r != 0)
- return r;
- }
- }
-
- return 0;
-}
-
-struct error_state {
- struct apk_indent indent;
- struct apk_package *prevpkg;
-};
-
-static int print_dep(struct apk_state *state,
- struct apk_package *pkg,
- struct apk_dependency *dep,
- void *ctx)
-{
- struct error_state *es = (struct error_state *) ctx;
- apk_blob_t blob;
- char buf[256];
- int len;
-
- if (pkg != es->prevpkg) {
- printf("\n");
- es->indent.x = 0;
- len = snprintf(buf, sizeof(buf), PKG_VER_FMT ":",
- PKG_VER_PRINTF(pkg));
- apk_print_indented(&es->indent, APK_BLOB_PTR_LEN(buf, len));
- es->prevpkg = pkg;
- }
-
- blob = APK_BLOB_BUF(buf);
- apk_blob_push_dep(&blob, dep);
- blob = apk_blob_pushed(APK_BLOB_BUF(buf), blob);
- apk_print_indented(&es->indent, blob);
-
- return 0;
-}
-
-void apk_state_print_errors(struct apk_state *state)
-{
- struct apk_package *pkg;
- struct error_state es;
- int i, j, r;
-
- for (i = 0; i < state->conflicts->num; i++) {
- if (i == 0)
- apk_error("Unable to satisfy all dependencies:");
-
- es.prevpkg = pkg = state->conflicts->item[i];
- es.indent.x =
- printf(" " PKG_VER_FMT ":", PKG_VER_PRINTF(pkg));
- es.indent.indent = es.indent.x + 1;
- for (j = 0; j < pkg->depends->num; j++) {
- r = apk_state_lock_dependency(state,
- &pkg->depends->item[j]);
- if (r != 0)
- print_dep(state, pkg, &pkg->depends->item[j], &es);
- }
-
- /* Print conflicting reverse deps */
- for_each_broken_reverse_depency(state, pkg->name,
- print_dep, &es);
- printf("\n");
- }
-
- for (i = 0; i < state->missing->num; i++) {
- struct apk_name *name = state->missing->item[i];
- if (i == 0) {
- apk_error("Missing packages:");
- es.indent.x = 0;
- es.indent.indent = 2;
- }
- apk_print_indented(&es.indent, APK_BLOB_STR(name->name));
- }
- if (i != 0)
- printf("\n");
-}
-
-int apk_state_commit(struct apk_state *state)
-{
- struct progress prog;
- struct apk_change *change;
- struct apk_database *db = state->db;
- int n = 0, r = 0, size_diff = 0, toplevel = FALSE, deleteonly = TRUE;
-
- /* Count what needs to be done */
- memset(&prog, 0, sizeof(prog));
- list_for_each_entry(change, &state->change_list_head, change_list) {
- if (change->newpkg == NULL) {
- if (change->oldpkg->name->flags & APK_NAME_TOPLEVEL)
- toplevel = TRUE;
- } else
- deleteonly = FALSE;
- if (change->oldpkg != NULL)
- apk_state_autoclean(state, change->oldpkg);
- apk_count_change(change, &prog.total);
- if (change->newpkg)
- size_diff += change->newpkg->installed_size;
- if (change->oldpkg)
- size_diff -= change->oldpkg->installed_size;
- }
- size_diff /= 1024;
-
- if (toplevel &&
- (apk_flags & (APK_INTERACTIVE | APK_RECURSIVE_DELETE)) == 0) {
- if (!deleteonly)
- return -1;
-
- dump_packages(state, cmp_remove,
- "The top-level dependencies have been updated "
- "but the following packages are not removed");
- goto update_state;
- }
-
- if (apk_verbosity > 1 || (apk_flags & APK_INTERACTIVE)) {
- r = dump_packages(state, cmp_remove,
- "The following packages will be REMOVED");
- r += dump_packages(state, cmp_downgrade,
- "The following packages will be DOWNGRADED");
- if (r || (apk_flags & APK_INTERACTIVE) || apk_verbosity > 2) {
- dump_packages(state, cmp_new,
- "The following NEW packages will be installed");
- dump_packages(state, cmp_upgrade,
- "The following packages will be upgraded");
- printf("After this operation, %d kB of %s\n", abs(size_diff),
- (size_diff < 0) ?
- "disk space will be freed." :
- "additional disk space will be used.");
- }
- if (apk_flags & APK_INTERACTIVE) {
- printf("Do you want to continue [Y/n]? ");
- fflush(stdout);
- r = fgetc(stdin);
- if (r != 'y' && r != 'Y' && r != '\n')
- return -1;
- }
- }
-
- /* Go through changes */
- r = 0;
- n = 0;
- list_for_each_entry(change, &state->change_list_head, change_list) {
- n++;
- apk_print_change(db, change->oldpkg, change->newpkg, n, state->num_changes);
- if (apk_flags & APK_PROGRESS)
- apk_draw_progress(prog.count);
- prog.pkg = change->newpkg;
-
- if (!(apk_flags & APK_SIMULATE)) {
- r = apk_db_install_pkg(db,
- change->oldpkg, change->newpkg,
- (apk_flags & APK_PROGRESS) ? progress_cb : NULL,
- &prog);
- if (r != 0)
- break;
-
- if (change->oldpkg != NULL &&
- change->newpkg == NULL &&
- change->oldpkg->name->flags & APK_NAME_TOPLEVEL) {
- change->oldpkg->name->flags &= ~APK_NAME_TOPLEVEL;
- apk_deps_del(&db->world, change->oldpkg->name);
- }
- }
-
- apk_count_change(change, &prog.done);
- }
- if (apk_flags & APK_PROGRESS)
- apk_draw_progress(100);
-
-update_state:
- apk_db_run_triggers(db);
- apk_db_write_config(db);
-
- if (r == 0 && state->print_ok)
- apk_message("OK: %d packages, %d dirs, %d files",
- db->installed.stats.packages,
- db->installed.stats.dirs,
- db->installed.stats.files);
-
- return r;
-}