summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2012-02-16 10:50:52 +0200
committerTimo Teräs <timo.teras@iki.fi>2012-02-16 10:57:52 +0200
commit0800d7e050b738e7faa848291d6021175b853e29 (patch)
tree70d5709e8b87ad49fd3661d4eaf727d025b039d6 /src/solver.c
parent7399f1950f5418dc7942579d5e9ed9807c764cce (diff)
downloadapk-tools-0800d7e050b738e7faa848291d6021175b853e29.tar.gz
apk-tools-0800d7e050b738e7faa848291d6021175b853e29.tar.bz2
apk-tools-0800d7e050b738e7faa848291d6021175b853e29.tar.xz
apk-tools-0800d7e050b738e7faa848291d6021175b853e29.zip
solver: record repository tag, and flags in solution
name state could get overwritten later, so we can't use that when generating the changeset.
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c147
1 files changed, 92 insertions, 55 deletions
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;
}