diff options
-rw-r--r-- | src/apk_solver.h | 14 | ||||
-rw-r--r-- | src/del.c | 6 | ||||
-rw-r--r-- | src/solver.c | 147 | ||||
-rw-r--r-- | src/test.c | 10 | ||||
-rw-r--r-- | src/upgrade.c | 4 |
5 files changed, 113 insertions, 68 deletions
diff --git a/src/apk_solver.h b/src/apk_solver.h index 7dd2914..4ecb9a7 100644 --- a/src/apk_solver.h +++ b/src/apk_solver.h @@ -12,10 +12,18 @@ #ifndef APK_SOLVER_H #define APK_SOLVER_H +struct apk_solution_entry { + struct apk_package *pkg; + unsigned short repository_tag : 15; + unsigned reinstall : 1; +}; +APK_ARRAY(apk_solution_array, struct apk_solution_entry); + struct apk_change { struct apk_package *oldpkg; struct apk_package *newpkg; - unsigned short repository_tag; + unsigned short repository_tag : 15; + unsigned reinstall : 1; }; APK_ARRAY(apk_change_array, struct apk_change); @@ -33,13 +41,13 @@ void apk_solver_set_name_flags(struct apk_name *name, int apk_solver_solve(struct apk_database *db, unsigned short solver_flags, struct apk_dependency_array *world, - struct apk_package_array **solution, + struct apk_solution_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_solution_array *solution, struct apk_dependency_array *world, int unsatisfiable); int apk_solver_commit(struct apk_database *db, @@ -125,7 +125,7 @@ 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 apk_solution_array *solution = NULL; struct not_deleted_ctx ndctx = {}; int i, r = 0; @@ -145,7 +145,7 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv) 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]; + struct apk_package *pkg = solution->item[i].pkg; pkg->name->state_ptr = pkg; pkg->state_int = 0; } @@ -165,7 +165,7 @@ static int del_main(void *pctx, struct apk_database *db, int argc, char **argv) } else { apk_solver_print_errors(db, solution, ctx->world, r); } - apk_package_array_free(&solution); + apk_solution_array_free(&solution); apk_dependency_array_free(&ctx->world); return r; diff --git a/src/solver.c b/src/solver.c index 9581aa8..d7a8f63 100644 --- a/src/solver.c +++ b/src/solver.c @@ -76,7 +76,7 @@ struct apk_solver_state { unsigned int solver_flags : 4; unsigned int refresh_name_states : 1; - struct apk_package_array *best_solution; + struct apk_solution_array *best_solution; struct apk_score best_score; }; @@ -337,6 +337,7 @@ static unsigned int get_pinning_mask_repos(struct apk_database *db, unsigned sho static int compare_package_preference(unsigned short solver_flags, unsigned int preferred_repos, + unsigned int allowed_repos, struct apk_package *pkgA, struct apk_package *pkgB, struct apk_database *db) @@ -357,6 +358,12 @@ static int compare_package_preference(unsigned short solver_flags, if ((b_repos & preferred_repos) && !(a_repos & preferred_repos)) return -1; + /* Difference in allowed repositories? */ + if ((a_repos & allowed_repos) && !(b_repos & allowed_repos)) + return 1; + if ((b_repos & allowed_repos) && !(a_repos & allowed_repos)) + return -1; + if (solver_flags & APK_SOLVERF_AVAILABLE) { if (pkgA->repos != 0 && pkgB->repos == 0) return 1; @@ -400,13 +407,18 @@ static int get_preference(struct apk_solver_state *ss, unsigned short name_flags = ns->solver_flags_local | ns->solver_flags_inherited | ss->solver_flags; - unsigned short preferred_pinning; - unsigned int preferred_repos; + unsigned short preferred_pinning, allowed_pinning; + unsigned int preferred_repos, allowed_repos; unsigned short preference = 0; - int i; + int i, r; preferred_pinning = ns->preferred_pinning ?: APK_DEFAULT_PINNING_MASK; preferred_repos = get_pinning_mask_repos(ss->db, preferred_pinning); + allowed_pinning = ns->allowed_pinning | ns->preferred_pinning | APK_DEFAULT_PINNING_MASK; + if (preferred_pinning != allowed_pinning) + allowed_repos = get_pinning_mask_repos(ss->db, allowed_pinning); + else + allowed_repos = preferred_repos; for (i = 0; i < name->pkgs->num; i++) { struct apk_package *pkg0 = name->pkgs->item[i]; @@ -415,15 +427,17 @@ static int get_preference(struct apk_solver_state *ss, if (pkg0 == pkg || ps0 == NULL) continue; - if (compare_package_preference(name_flags, preferred_repos, - pkg, pkg0, ss->db) < 0) { - if (installable_only) { - if (ss->topology_position > pkg0->topology_hard && - !(ps0->flags & APK_PKGSTF_DECIDED)) - preference++; - } else - preference++; - } + if (installable_only && + (ss->topology_position <= pkg0->topology_hard || + (ps0->flags & APK_PKGSTF_DECIDED))) + continue; + + r = compare_package_preference(name_flags, + preferred_repos, + allowed_repos, + pkg, pkg0, ss->db); + if (r < 0) + preference += -r; } return preference; @@ -487,7 +501,9 @@ static int update_name_state(struct apk_solver_state *ss, struct apk_name *name) if ((preferred_pkg == NULL) || (ps0->conflicts < preferred_ps->conflicts) || (ps0->conflicts == preferred_ps->conflicts && - compare_package_preference(name_flags, preferred_repos, + compare_package_preference(name_flags, + preferred_repos, + allowed_repos, pkg0, preferred_pkg, ss->db) > 0)) { preferred_pkg = pkg0; preferred_ps = ps0; @@ -896,22 +912,50 @@ static int expand_branch(struct apk_solver_state *ss) return 0; } +static int get_tag(struct apk_database *db, unsigned short pinning_mask, unsigned int repos) +{ + int i; + + for (i = 0; i < db->num_repo_tags; i++) { + if (!(BIT(i) & pinning_mask)) + continue; + if (db->repo_tags[i].allowed_repos & repos) + return i; + } + return APK_DEFAULT_REPOSITORY_TAG; +} + static void record_solution(struct apk_solver_state *ss) { + struct apk_database *db = ss->db; struct apk_package *pkg; struct apk_package_state *ps; + struct apk_name_state *ns; int i; - apk_package_array_resize(&ss->best_solution, ss->assigned_names); + apk_solution_array_resize(&ss->best_solution, ss->assigned_names); i = 0; pkg = ss->latest_decision; while (pkg != NULL) { ps = pkg_to_ps(pkg); + ns = name_to_ns(pkg->name); if (ps->flags & APK_PKGSTF_INSTALL) { + unsigned short pinning; + unsigned int repos; + if (i >= ss->assigned_names) abort(); - ss->best_solution->item[i++] = pkg; + + pinning = ns->allowed_pinning | ns->preferred_pinning | APK_DEFAULT_PINNING_MASK; + repos = pkg->repos | (pkg->ipkg ? db->repo_tags[pkg->ipkg->repository_tag].allowed_repos : 0); + + ss->best_solution->item[i++] = (struct apk_solution_entry){ + .pkg = pkg, + .reinstall = !!((ns->solver_flags_local | ns->solver_flags_inherited | + ss->solver_flags) & APK_SOLVERF_REINSTALL), + .repository_tag = get_tag(db, pinning, repos), + }; } dbg_printf("record_solution: " PKG_VER_FMT ": %sINSTALL\n", @@ -920,16 +964,16 @@ static void record_solution(struct apk_solver_state *ss) pkg = ps->backtrack; } - apk_package_array_resize(&ss->best_solution, i); + apk_solution_array_resize(&ss->best_solution, i); ss->best_score = ss->score; } -static int compare_package_name(const void *p1, const void *p2) +static int compare_solution_entry(const void *p1, const void *p2) { - const struct apk_package **c1 = (const struct apk_package **) p1; - const struct apk_package **c2 = (const struct apk_package **) p2; + const struct apk_solution_entry *c1 = (const struct apk_solution_entry *) p1; + const struct apk_solution_entry *c2 = (const struct apk_solution_entry *) p2; - return strcmp((*c1)->name->name, (*c2)->name->name); + return strcmp(c1->pkg->name->name, c2->pkg->name->name); } static int compare_change(const void *p1, const void *p2) @@ -955,21 +999,8 @@ static int compare_change(const void *p1, const void *p2) c2->newpkg->topology_hard; } -static int get_tag(struct apk_database *db, unsigned short pinning_mask, unsigned int repos) -{ - int i; - - for (i = 0; i < db->num_repo_tags; i++) { - if (!(BIT(i) & pinning_mask)) - continue; - if (db->repo_tags[i].allowed_repos & repos) - return i; - } - return APK_DEFAULT_REPOSITORY_TAG; -} - static int generate_changeset(struct apk_database *db, - struct apk_package_array *solution, + struct apk_solution_array *solution, struct apk_changeset *changeset, unsigned short solver_flags) { @@ -981,13 +1012,13 @@ static int generate_changeset(struct apk_database *db, /* calculate change set size */ for (i = 0; i < solution->num; i++) { - pkg = solution->item[i]; + pkg = solution->item[i].pkg; ns = name_to_ns(pkg->name); ns->chosen = pkg; ns->in_changeset = 1; if ((pkg->ipkg == NULL) || - ((ns->solver_flags_local | ns->solver_flags_inherited | - solver_flags) & APK_SOLVERF_REINSTALL)) + solution->item[i].reinstall || + solution->item[i].repository_tag != pkg->ipkg->repository_tag) num_installs++; } list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { @@ -1008,13 +1039,13 @@ static int generate_changeset(struct apk_database *db, } } for (i = 0; i < solution->num; i++) { - pkg = solution->item[i]; + pkg = solution->item[i].pkg; name = pkg->name; ns = name_to_ns(name); if ((pkg->ipkg == NULL) || - ((ns->solver_flags_local | ns->solver_flags_inherited | - solver_flags) & APK_SOLVERF_REINSTALL)) { + solution->item[i].reinstall || + solution->item[i].repository_tag != pkg->ipkg->repository_tag){ for (j = 0; j < name->pkgs->num; j++) { pkg0 = name->pkgs->item[j]; if (pkg0->ipkg == NULL) @@ -1023,7 +1054,8 @@ static int generate_changeset(struct apk_database *db, break; } changeset->changes->item[ci].newpkg = pkg; - changeset->changes->item[ci].repository_tag = get_tag(db, ns->allowed_pinning, pkg->repos); + changeset->changes->item[ci].repository_tag = solution->item[i].repository_tag; + changeset->changes->item[ci].reinstall = solution->item[i].reinstall; ci++; } } @@ -1075,7 +1107,7 @@ static void apk_solver_free(struct apk_database *db) int apk_solver_solve(struct apk_database *db, unsigned short solver_flags, struct apk_dependency_array *world, - struct apk_package_array **solution, + struct apk_solution_array **solution, struct apk_changeset *changeset) { struct apk_solver_state *ss; @@ -1134,10 +1166,10 @@ int apk_solver_solve(struct apk_database *db, } if (solution != NULL) { qsort(ss->best_solution->item, ss->best_solution->num, - sizeof(struct apk_package *), compare_package_name); + sizeof(struct apk_solution_entry), compare_solution_entry); *solution = ss->best_solution; } else { - apk_package_array_free(&ss->best_solution); + apk_solution_array_free(&ss->best_solution); } r = ss->best_score.unsatisfiable; apk_solver_free(db); @@ -1179,6 +1211,10 @@ static void print_change(struct apk_database *db, apk_message("%s Purging %s (" BLOB_FMT ")", status, nameptr, BLOB_PRINTF(*oldpkg->version)); + } else if (newpkg == oldpkg && !change->reinstall) { + apk_message("%s Updating pinning %s (" BLOB_FMT ")", + status, nameptr, + BLOB_PRINTF(*oldpkg->version)); } else { r = apk_pkg_version_compare(newpkg, oldpkg); switch (r) { @@ -1415,10 +1451,11 @@ int apk_solver_commit_changeset(struct apk_database *db, 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 (change->oldpkg != change->newpkg || change->reinstall) + r = apk_db_install_pkg(db, + change->oldpkg, change->newpkg, + (apk_flags & APK_PROGRESS) ? progress_cb : NULL, + &prog); if (r != 0) break; if (change->newpkg) @@ -1482,7 +1519,7 @@ static void print_dep_errors(struct apk_database *db, char *label, struct apk_de } void apk_solver_print_errors(struct apk_database *db, - struct apk_package_array *solution, + struct apk_solution_array *solution, struct apk_dependency_array *world, int unsatisfiable) { @@ -1491,15 +1528,15 @@ void apk_solver_print_errors(struct apk_database *db, apk_error("%d unsatisfiable dependencies:", unsatisfiable); for (i = 0; i < solution->num; i++) { - struct apk_package *pkg = solution->item[i]; + struct apk_package *pkg = solution->item[i].pkg; pkg->name->state_ptr = pkg; } print_dep_errors(db, "world", world); for (i = 0; i < solution->num; i++) { - struct apk_package *pkg = solution->item[i]; + struct apk_package *pkg = solution->item[i].pkg; char pkgtext[256]; - snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(solution->item[i])); + snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(pkg)); print_dep_errors(db, pkgtext, pkg->depends); } } @@ -1509,7 +1546,7 @@ int apk_solver_commit(struct apk_database *db, struct apk_dependency_array *world) { struct apk_changeset changeset = {}; - struct apk_package_array *solution = NULL; + struct apk_solution_array *solution = NULL; int r; if (apk_db_check_world(db, world) != 0) { @@ -1529,7 +1566,7 @@ int apk_solver_commit(struct apk_database *db, /* Failure -- print errors */ apk_solver_print_errors(db, solution, world, r); } - apk_package_array_free(&solution); + apk_solution_array_free(&solution); return r; } @@ -119,7 +119,7 @@ static void print_dep_errors(struct apk_database *db, char *label, struct apk_de } static void print_errors_in_solution(struct apk_database *db, int unsatisfiable, - struct apk_package_array *solution) + struct apk_solution_array *solution) { int i; @@ -127,15 +127,15 @@ static void print_errors_in_solution(struct apk_database *db, int unsatisfiable, unsatisfiable, solution->num); for (i = 0; i < solution->num; i++) { - struct apk_package *pkg = solution->item[i]; + struct apk_package *pkg = solution->item[i].pkg; pkg->name->state_ptr = pkg; } print_dep_errors(db, "world", db->world); for (i = 0; i < solution->num; i++) { - struct apk_package *pkg = solution->item[i]; + struct apk_package *pkg = solution->item[i].pkg; char pkgtext[256]; - snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(solution->item[i])); + snprintf(pkgtext, sizeof(pkgtext), PKG_VER_FMT, PKG_VER_PRINTF(pkg)); print_dep_errors(db, pkgtext, pkg->depends); } @@ -145,7 +145,7 @@ static int test_main(void *pctx, struct apk_database *db, int argc, char **argv) { struct test_ctx *ctx = (struct test_ctx *) pctx; struct apk_bstream *bs; - struct apk_package_array *solution = NULL; + struct apk_solution_array *solution = NULL; struct apk_changeset changeset = {}; apk_blob_t b; int i, r; diff --git a/src/upgrade.c b/src/upgrade.c index 497fc54..1185079 100644 --- a/src/upgrade.c +++ b/src/upgrade.c @@ -45,7 +45,7 @@ int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags) { struct apk_name *name; struct apk_changeset changeset = {}; - struct apk_package_array *solution = NULL; + struct apk_solution_array *solution = NULL; int r; name = apk_db_get_name(db, APK_BLOB_STR("apk-tools")); @@ -83,7 +83,7 @@ int apk_do_self_upgrade(struct apk_database *db, unsigned short solver_flags) exit(1); ret: - apk_package_array_free(&solution); + apk_solution_array_free(&solution); apk_change_array_free(&changeset.changes); db->performing_self_update = 0; |