summaryrefslogtreecommitdiff
path: root/src/solver.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2013-06-18 16:24:48 +0300
committerTimo Teräs <timo.teras@iki.fi>2013-06-19 08:33:51 +0300
commitd315c9019cf6e43dd7ecfe17e8d3896469396997 (patch)
tree68a54cb549792813700c18f19177bd1c2c52fe56 /src/solver.c
parentf91b01fea8a0e2b32ccf9d3eea8468d5312633c4 (diff)
downloadapk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.tar.gz
apk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.tar.bz2
apk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.tar.xz
apk-tools-d315c9019cf6e43dd7ecfe17e8d3896469396997.zip
upgrade: new option: --latest (-l)
Select latest version of package (if it is not pinned), and print error if it cannot be installed due to other dependencies. Together with --available, it selects the latest package which is present at least in some repository. This also fixes few solver issues with ordering of package selection that got quite apparent with this flag. Namely, we cannot "lock" a package until it's reverse dependencies are locked or not all of the solver flags are propagated properly.
Diffstat (limited to 'src/solver.c')
-rw-r--r--src/solver.c143
1 files changed, 87 insertions, 56 deletions
diff --git a/src/solver.c b/src/solver.c
index b1a078c..914baf1 100644
--- a/src/solver.c
+++ b/src/solver.c
@@ -222,11 +222,12 @@ static void discover_name(struct apk_solver_state *ss, struct apk_name *name)
}
name->ss.max_dep_chain = max(name->ss.max_dep_chain, pkg->ss.max_dep_chain);
- dbg_printf("discover " PKG_VER_FMT ": tag_ok=%d, tag_pref=%d max_dep_chain=%d\n",
+ dbg_printf("discover " PKG_VER_FMT ": tag_ok=%d, tag_pref=%d max_dep_chain=%d available=%d\n",
PKG_VER_PRINTF(pkg),
pkg->ss.tag_ok,
pkg->ss.tag_preferred,
- pkg->ss.max_dep_chain);
+ pkg->ss.max_dep_chain,
+ pkg->ss.available);
}
foreach_array_item(pname0, name->rinstall_if)
discover_name(ss, *pname0);
@@ -266,7 +267,8 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp
BLOB_PRINTF(*dep->version));
name->ss.requirers += !dep->conflict;
- name_requirers_changed(ss, name);
+ if (name->ss.requirers == 1 && !dep->conflict)
+ name_requirers_changed(ss, name);
foreach_array_item(p0, name->providers) {
struct apk_package *pkg0 = p0->pkg;
@@ -294,7 +296,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp
static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
{
- struct apk_name *name0;
+ struct apk_name *name0, **pname0;
struct apk_dependency *dep;
struct apk_package *first_candidate = NULL;
struct apk_provider *p;
@@ -366,26 +368,41 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
foreach_array_item(p, name->providers)
p->pkg->ss.dependencies_used = p->pkg->ss.dependencies_merged;
- /* TODO: could merge versioning bits too */
/* propagate down common dependencies */
- foreach_array_item(dep, first_candidate->depends) {
- if (dep->conflict)
- continue;
- name0 = dep->name;
- if (name0->ss.merge_index == num_options) {
- /* common dependency name with all */
- if (name0->ss.requirers == 0) {
- dbg_printf("%s common dependency: %s\n",
- name->name, name0->name);
- name0->ss.requirers++;
- name_requirers_changed(ss, name0);
+ if (num_options == 1) {
+ /* FIXME: keeps increasing counts, use bit fields instead? */
+ foreach_array_item(dep, first_candidate->depends)
+ apply_constraint(ss, first_candidate, dep);
+ } else {
+ /* FIXME: could merge versioning bits too */
+ foreach_array_item(dep, first_candidate->depends) {
+ if (dep->conflict)
+ continue;
+ name0 = dep->name;
+ if (name0->ss.merge_index == num_options) {
+ /* common dependency name with all */
+ if (name0->ss.requirers == 0) {
+ dbg_printf("%s common dependency: %s\n",
+ name->name, name0->name);
+ name0->ss.requirers++;
+ name_requirers_changed(ss, name0);
+ }
}
+ name0->ss.merge_index = 0;
}
- name0->ss.merge_index = 0;
}
}
- dbg_printf("reconsider_name: %s [finished], has_options=%d\n",
- name->name, name->ss.has_options);
+ name->ss.reverse_deps_done = 1;
+ foreach_array_item(pname0, name->rdepends) {
+ name0 = *pname0;
+ if (name0->ss.seen && !name0->ss.locked) {
+ name->ss.reverse_deps_done = 0;
+ break;
+ }
+ }
+
+ dbg_printf("reconsider_name: %s [finished], has_options=%d, reverse_deps_done=%d\n",
+ name->name, name->ss.has_options, name->ss.reverse_deps_done);
}
static int compare_providers(struct apk_solver_state *ss,
@@ -400,50 +417,66 @@ static int compare_providers(struct apk_solver_state *ss,
if (pkgA == NULL || pkgB == NULL)
return (pkgA != NULL) - (pkgB != NULL);
- /* Prefer without errors */
- r = (int)pkgA->ss.available - (int)pkgB->ss.available;
- if (r)
- return r;
+ /* Latest version required? */
+ solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
+ if ((solver_flags & APK_SOLVERF_LATEST) &&
+ (pkgA->ss.pinning_allowed == APK_DEFAULT_PINNING_MASK) &&
+ (pkgB->ss.pinning_allowed == APK_DEFAULT_PINNING_MASK)) {
+ /* Prefer allowed pinning */
+ r = (int)pkgA->ss.tag_ok - (int)pkgB->ss.tag_ok;
+ if (r)
+ return r;
- /* Prefer those that were in last dependency merging group */
- r = (int)pkgA->ss.dependencies_used - (int)pkgB->ss.dependencies_used;
- if (r)
- return r;
- r = pkgB->ss.conflicts - pkgA->ss.conflicts;
- if (r)
- return r;
+ /* Prefer available */
+ if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
+ r = !!(pkgA->repos & db->available_repos) - !!(pkgB->repos & db->available_repos);
+ if (r)
+ return r;
+ }
+ } else {
+ /* Prefer without errors */
+ r = (int)pkgA->ss.available - (int)pkgB->ss.available;
+ if (r)
+ return r;
- /* Prefer installed on self-upgrade */
- solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
- if (db->performing_self_update && !(solver_flags & APK_SOLVERF_UPGRADE)) {
- r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ /* Prefer those that were in last dependency merging group */
+ r = (int)pkgA->ss.dependencies_used - (int)pkgB->ss.dependencies_used;
+ if (r)
+ return r;
+ r = pkgB->ss.conflicts - pkgA->ss.conflicts;
if (r)
return r;
- }
- /* Prefer allowed pinning */
- r = (int)pkgA->ss.tag_ok - (int)pkgB->ss.tag_ok;
- if (r)
- return r;
+ /* Prefer installed on self-upgrade */
+ if (db->performing_self_update && !(solver_flags & APK_SOLVERF_UPGRADE)) {
+ r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ if (r)
+ return r;
+ }
- /* Prefer available */
- if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
- r = !!(pkgA->repos & db->available_repos) -
- !!(pkgB->repos & db->available_repos);
+ /* Prefer allowed pinning */
+ r = (int)pkgA->ss.tag_ok - (int)pkgB->ss.tag_ok;
if (r)
return r;
- }
- /* Prefer preferred pinning */
- r = (int)pkgA->ss.tag_preferred - (int)pkgB->ss.tag_preferred;
- if (r)
- return r;
+ /* Prefer available */
+ if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
+ r = !!(pkgA->repos & db->available_repos) - !!(pkgB->repos & db->available_repos);
+ if (r)
+ return r;
+ }
- /* Prefer installed */
- if (!(solver_flags & APK_SOLVERF_UPGRADE)) {
- r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ /* Prefer preferred pinning */
+ r = (int)pkgA->ss.tag_preferred - (int)pkgB->ss.tag_preferred;
if (r)
return r;
+
+ /* Prefer installed */
+ if (!(solver_flags & APK_SOLVERF_UPGRADE)) {
+ r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
+ if (r)
+ return r;
+ }
}
/* Select latest by requested name */
@@ -747,17 +780,15 @@ restart:
name = NULL;
list_for_each_entry(name0, &ss->unresolved_head, ss.unresolved_list) {
- if ((!name0->ss.has_options) && name0->ss.requirers > 0) {
+ if (name0->ss.reverse_deps_done && name0->ss.requirers && !name0->ss.has_options) {
name = name0;
break;
}
if (name == NULL)
goto prefer;
- if (name0->ss.requirers == 0 && name->ss.requirers > 0)
+ if ((!!name0->ss.requirers) - (!!name->ss.requirers) < 0)
continue;
- if (name0->ss.requirers > 0 && name->ss.requirers == 0)
- goto prefer;
- if (name0->ss.max_dep_chain < name->ss.max_dep_chain)
+ if (name0->ss.max_dep_chain - name->ss.max_dep_chain < 0)
continue;
prefer:
name = name0;