summaryrefslogtreecommitdiff
path: root/src/state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.c')
-rw-r--r--src/state.c241
1 files changed, 142 insertions, 99 deletions
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;
}