diff options
Diffstat (limited to 'src/state.c')
-rw-r--r-- | src/state.c | 235 |
1 files changed, 153 insertions, 82 deletions
diff --git a/src/state.c b/src/state.c index 4a4641d..6de3629 100644 --- a/src/state.c +++ b/src/state.c @@ -138,14 +138,20 @@ static struct apk_name_choices *name_choices_new(struct apk_database *db, if (dep->name != name) continue; - 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--; + 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; @@ -232,6 +238,50 @@ void apk_state_unref(struct apk_state *state) 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_array(struct apk_state *state, + struct apk_dependency_array *da) +{ + struct apk_package *pkg; + int i; + + for (i = 0; i < da->num; i++) { + pkg = get_locked_or_installed_package(state, da->item[i].name); + if (pkg == NULL && da->item[i].result_mask != APK_DEPMASK_CONFLICT) + return 0; + if (!apk_dep_is_satisfied(&da->item[i], pkg)) + return 0; + } + + return da->num; +} + static int apk_state_add_change(struct apk_state *state, struct apk_package *oldpkg, struct apk_package *newpkg) @@ -334,20 +384,22 @@ int apk_state_prune_dependency(struct apk_state *state, return c->num; } -int apk_state_lock_dependency(struct apk_state *state, - struct apk_dependency *dep) +int apk_state_autolock_name(struct apk_state *state, struct apk_name *name, + int install_if) { - struct apk_name *name = dep->name; struct apk_name_choices *c; - struct apk_package *installed = NULL, *latest = NULL, *use; - int i, r; - - r = apk_state_prune_dependency(state, dep); - if (r <= 0) - return r; + 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 @@ -355,6 +407,10 @@ int apk_state_lock_dependency(struct apk_state *state, 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)) @@ -396,7 +452,13 @@ int apk_state_lock_dependency(struct apk_state *state, use = latest; } if (use == NULL) - return -1; + 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 @@ -411,6 +473,18 @@ int apk_state_lock_dependency(struct apk_state *state, #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) { @@ -420,12 +494,18 @@ static int apk_state_fix_package(struct apk_state *state, return 0; for (i = 0; i < pkg->depends->num; i++) { - r = apk_state_lock_dependency(state, - &pkg->depends->item[i]); - if (r != 0) - ret = -1; + if (pkg->depends->item[i].name->flags & APK_NAME_TOPLEVEL_OVERRIDE) { + 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; } @@ -467,48 +547,19 @@ static int for_each_broken_reverse_depency(struct apk_state *state, void *ctx) { struct apk_package *pkg0; - int i, j, r; + int i, r; for (i = 0; i < name->rdepends->num; i++) { struct apk_name *name0 = name->rdepends->item[i]; - if (ns_locked(state->name[name0->id])) { - pkg0 = ns_to_pkg(state->name[name0->id]); - if (pkg0 == NULL) - continue; - r = call_if_dependency_broke(state, pkg0, name, - cb, ctx); - if (r != 0) - return r; - } else if (!ns_empty(state->name[name0->id])) { - struct apk_name_choices *ns = - ns_to_choices(state->name[name0->id]); - - for (j = 0; j < ns->num; j++) { - if (ns->pkgs[j]->ipkg == NULL) - continue; - r = call_if_dependency_broke(state, - ns->pkgs[j], - name, cb, ctx); - if (r != 0) - return r; - break; - } - } else { - for (j = 0; j < name0->pkgs->num; j++) { - pkg0 = name0->pkgs->item[j]; - - if (pkg0->ipkg == NULL) - continue; + pkg0 = get_locked_or_installed_package(state, name0); + if (pkg0 == NULL) + continue; - r = call_if_dependency_broke(state, - name0->pkgs->item[j], - name, cb, ctx); - if (r != 0) - return r; - break; - } - } + r = call_if_dependency_broke(state, pkg0, name, + cb, ctx); + if (r != 0) + return r; } return 0; @@ -578,15 +629,19 @@ int apk_state_lock_name(struct apk_state *state, } /* If the chosen package is installed, all is done here */ - if (oldpkg == newpkg && - (newpkg == NULL || - !(newpkg->name->flags & APK_NAME_REINSTALL))) - return 0; + 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; + } - /* 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; } @@ -655,22 +710,19 @@ static void apk_count_change(struct apk_change *change, struct apk_stats *stats) stats->packages ++; } -static inline void apk_draw_progress(int percent, int last) +static void apk_draw_progress(int percent) { - char tmp[128]; - char reset[128]; + const int bar_width = (apk_screen_width - 7); int i; - snprintf(tmp, sizeof(tmp), "-[ ]- %3i%%", percent); - for (i = 0; (i < (percent/5)) && (i < (sizeof(tmp)-2)); i++) - tmp[2+i] = '#'; - memset(reset, '\b', strlen(tmp)); - fwrite(tmp, strlen(tmp), 1, stderr); - if (!last) - fwrite(reset, strlen(tmp), 1, stderr); - else if (apk_verbosity > 0) - fwrite("\n", 1, 1, stderr); + 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 { @@ -692,7 +744,7 @@ static void progress_cb(void *ctx, size_t progress) prog->total.bytes + prog->total.packages); if (prog->count != count) - apk_draw_progress(count, 0); + apk_draw_progress(count); prog->count = count; } @@ -799,6 +851,23 @@ static int apk_state_autoclean(struct apk_state *state, 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; } @@ -874,11 +943,11 @@ void apk_state_print_errors(struct apk_state *state) printf("\n"); } -int apk_state_commit(struct apk_state *state, - struct apk_database *db) +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 */ @@ -940,6 +1009,8 @@ int apk_state_commit(struct apk_state *state, 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)) { @@ -961,7 +1032,7 @@ int apk_state_commit(struct apk_state *state, apk_count_change(change, &prog.done); } if (apk_flags & APK_PROGRESS) - apk_draw_progress(100, 1); + apk_draw_progress(100); update_state: apk_db_run_triggers(db); |