From 052fbe3f86eaab1940f25824705d809cd9af59e5 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Wed, 7 Jan 2009 21:45:11 +0200 Subject: various: make fancy progress bar and update todo --- src/state.c | 241 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 142 insertions(+), 99 deletions(-) (limited to 'src/state.c') diff --git a/src/state.c b/src/state.c index 24ecda9..484d5ee 100644 --- a/src/state.c +++ b/src/state.c @@ -15,10 +15,6 @@ #include "apk_state.h" #include "apk_database.h" -static int apk_state_commit_deps(struct apk_state *state, - struct apk_database *db, - struct apk_dependency_array *deps); - struct apk_state *apk_state_new(struct apk_database *db) { struct apk_state *state; @@ -27,6 +23,7 @@ struct apk_state *apk_state_new(struct apk_database *db) num_bytes = sizeof(struct apk_state) + (db->pkg_id * 2 + 7) / 8; state = (struct apk_state*) calloc(1, num_bytes); state->refs = 1; + list_init(&state->change_list_head); return state; } @@ -45,6 +42,24 @@ void apk_state_unref(struct apk_state *state) free(state); } +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); + change->oldpkg = oldpkg; + change->newpkg = newpkg; + + return 0; +} + static void apk_state_set(struct apk_state *state, int pos, int val) { int byte = pos / 4, offs = pos % 4; @@ -63,20 +78,18 @@ static int apk_state_get(struct apk_state *state, int pos) return (state->bitarray[byte] >> (offs * 2)) & 0x3; } -static int apk_state_commit_pkg(struct apk_state *state, - struct apk_database *db, - struct apk_name *name, - struct apk_package *oldpkg, - struct apk_package *newpkg) +static void apk_print_change(struct apk_database *db, + struct apk_package *oldpkg, + struct apk_package *newpkg) { const char *msg = NULL; - int r, upgrade = 0; + int r; + struct apk_name *name; - if (newpkg != NULL) { - r = apk_state_commit_deps(state, db, newpkg->depends); - if (r != 0) - return r; - } + if (oldpkg != NULL) + name = oldpkg->name; + else + name = newpkg->name; if (oldpkg == NULL) { apk_message("Installing %s (%s)", @@ -90,79 +103,100 @@ static int apk_state_commit_pkg(struct apk_state *state, switch (r) { case APK_VERSION_LESS: msg = "Downgrading"; - upgrade = 1; break; case APK_VERSION_EQUAL: msg = "Re-installing"; break; case APK_VERSION_GREATER: msg = "Upgrading"; - upgrade = 1; break; } apk_message("%s %s (%s -> %s)", - msg, name->name, oldpkg->version, newpkg->version); + msg, name->name, oldpkg->version, + newpkg->version); } - - return apk_db_install_pkg(db, oldpkg, newpkg); } -static int apk_state_commit_name(struct apk_state *state, - struct apk_database *db, - struct apk_name *name) -{ - struct apk_package *oldpkg = NULL, *newpkg = NULL; - int i; +struct apk_stats { + unsigned int bytes; + unsigned int packages; +}; - for (i = 0; i < name->pkgs->num; i++) { - if (apk_pkg_get_state(name->pkgs->item[i]) == APK_STATE_INSTALL) - oldpkg = name->pkgs->item[i]; - if (apk_state_get(state, name->pkgs->item[i]->id) == APK_STATE_INSTALL) - newpkg = name->pkgs->item[i]; +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 ++; +} - if (oldpkg == NULL && newpkg == NULL) - return 0; +static inline void apk_draw_progress(int x, int last) +{ + char tmp[] = + "-[ ]- " + "\b\b\b\b\b\b\b\b\b\b\b\b\b" + "\b\b\b\b\b\b\b\b\b\b\b\b"; + int i; - /* No reinstallations for now */ - if (newpkg == oldpkg) - return 0; + for (i = 0; i < x; i++) + tmp[2+i] = '#'; - return apk_state_commit_pkg(state, db, name, oldpkg, newpkg); + fwrite(tmp, last ? 25 : sizeof(tmp)-1, 1, stderr); + fflush(stderr); } -static int apk_state_commit_deps(struct apk_state *state, - struct apk_database *db, - struct apk_dependency_array *deps) +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) { - int r, i; + struct progress *prog = (struct progress *) ctx; + size_t partial = 0, count; - if (deps == NULL) - return 0; + if (prog->pkg != NULL) + partial = muldiv(progress, prog->pkg->installed_size, APK_PROGRESS_SCALE); - for (i = 0; i < deps->num; i++) { - r = apk_state_commit_name(state, db, deps->item[i].name); - if (r != 0) - return r; - } + count = muldiv(20, prog->done.bytes + prog->done.packages + partial, + prog->total.bytes + prog->total.packages); - return 0; + if (prog->count != count) + apk_draw_progress(count, 0); + prog->count = count; } int apk_state_commit(struct apk_state *state, struct apk_database *db) { - struct apk_package *pkg, *n; + struct progress prog; + struct apk_change *change; int r; - /* Check all dependencies */ - r = apk_state_commit_deps(state, db, db->world); - if (r != 0) - return r; + /* Count what needs to be done */ + memset(&prog, 0, sizeof(prog)); + list_for_each_entry(change, &state->change_list_head, change_list) + apk_count_change(change, &prog.total); - /* And purge all installed packages that were not considered */ - list_for_each_entry_safe(pkg, n, &db->installed.packages, installed_pkgs_list) - apk_state_commit_name(state, db, pkg->name); + /* Go through changes */ + list_for_each_entry(change, &state->change_list_head, change_list) { + apk_print_change(db, change->oldpkg, change->newpkg); + prog.pkg = change->newpkg; + + r = apk_db_install_pkg(db, change->oldpkg, change->newpkg, + apk_progress ? progress_cb : NULL, + &prog); + if (r != 0) + return r; + + apk_count_change(change, &prog.done); + } + if (apk_progress) + apk_draw_progress(20, 1); return 0; } @@ -170,9 +204,8 @@ int apk_state_commit(struct apk_state *state, int apk_state_satisfy_name(struct apk_state *state, struct apk_name *name) { - struct apk_package *preferred = NULL; - int i; - int upgrading = 1; + struct apk_package *preferred = NULL, *installed = NULL; + int i, r, upgrading = 1; /* Is something already installed? Or figure out the preferred * package. */ @@ -181,35 +214,52 @@ int apk_state_satisfy_name(struct apk_state *state, APK_STATE_INSTALL) return 0; + if (apk_pkg_get_state(name->pkgs->item[i]) == APK_STATE_INSTALL) { + installed = name->pkgs->item[i]; + if (!upgrading) { + preferred = installed; + continue; + } + } + if (preferred == NULL) { preferred = name->pkgs->item[i]; continue; } - if (upgrading) { - if (apk_version_compare(APK_BLOB_STR(name->pkgs->item[i]->version), - APK_BLOB_STR(preferred->version)) == - APK_VERSION_GREATER) { - preferred = name->pkgs->item[i]; - continue; - } - } else { - if (apk_pkg_get_state(name->pkgs->item[i]) == - APK_STATE_INSTALL) { - preferred = name->pkgs->item[i]; - continue; - } + if (apk_version_compare(APK_BLOB_STR(name->pkgs->item[i]->version), + APK_BLOB_STR(preferred->version)) == + APK_VERSION_GREATER) { + preferred = name->pkgs->item[i]; + continue; } } - /* Mark conflicting names as no install */ + /* FIXME: current code considers only the prefferred package. */ + + /* Can we install? */ + switch (apk_state_get(state, preferred->id)) { + case APK_STATE_INSTALL: + return 0; + case APK_STATE_NO_INSTALL: + return -1; + } + + /* Update state bits and track changes */ for (i = 0; i < name->pkgs->num; i++) { if (name->pkgs->item[i] != preferred) apk_state_set(state, name->pkgs->item[i]->id, APK_STATE_NO_INSTALL); } + apk_state_set(state, preferred->id, APK_STATE_INSTALL); + + if (preferred != installed) { + r = apk_state_add_change(state, installed, preferred); + if (r != 0) + return r; + } - return apk_state_pkg_install(state, preferred); + return apk_state_satisfy_deps(state, preferred->depends); } int apk_state_satisfy_deps(struct apk_state *state, @@ -234,33 +284,26 @@ int apk_state_satisfy_deps(struct apk_state *state, return 0; } -void apk_state_pkg_set(struct apk_state *state, - struct apk_package *pkg) +int apk_state_purge_unneeded(struct apk_state *state, + struct apk_database *db) { - apk_state_set(state, pkg->id, APK_STATE_INSTALL); -} + struct apk_package *pkg; + int r; -int apk_state_pkg_install(struct apk_state *state, - struct apk_package *pkg) -{ - switch (apk_state_get(state, pkg->id)) { - case APK_STATE_INSTALL: - return 0; - case APK_STATE_NO_INSTALL: - return -1; + /* Purge unconsidered packages */ + list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) { + switch (apk_state_get(state, pkg->id)) { + case APK_STATE_INSTALL: + case APK_STATE_NO_INSTALL: + break; + default: + r = apk_state_add_change(state, pkg, NULL); + if (r != 0) + return r; + break; + } } - apk_state_set(state, pkg->id, APK_STATE_INSTALL); - - if (pkg->depends == NULL) - return 0; - - return apk_state_satisfy_deps(state, pkg->depends); -} - -int apk_state_pkg_is_installed(struct apk_state *state, - struct apk_package *pkg) -{ - return apk_state_get(state, pkg->id); + return 0; } -- cgit v1.2.3-60-g2f50