diff options
-rw-r--r-- | src/apk_solver.h | 1 | ||||
-rw-r--r-- | src/apk_solver_data.h | 1 | ||||
-rw-r--r-- | src/commit.c | 17 | ||||
-rw-r--r-- | src/solver.c | 143 | ||||
-rw-r--r-- | src/upgrade.c | 6 | ||||
-rw-r--r-- | test/basic12.test | 15 | ||||
-rw-r--r-- | test/basic13.test | 10 | ||||
-rw-r--r-- | test/error5.test | 6 |
8 files changed, 134 insertions, 65 deletions
diff --git a/src/apk_solver.h b/src/apk_solver.h index 15620e9..b6067e2 100644 --- a/src/apk_solver.h +++ b/src/apk_solver.h @@ -33,6 +33,7 @@ struct apk_changeset { #define APK_SOLVERF_UPGRADE 0x0001 #define APK_SOLVERF_AVAILABLE 0x0002 #define APK_SOLVERF_REINSTALL 0x0004 +#define APK_SOLVERF_LATEST 0x0008 void apk_solver_set_name_flags(struct apk_name *name, unsigned short solver_flags, diff --git a/src/apk_solver_data.h b/src/apk_solver_data.h index cc41f6d..7a5e275 100644 --- a/src/apk_solver_data.h +++ b/src/apk_solver_data.h @@ -32,6 +32,7 @@ struct apk_solver_name_state { unsigned locked : 1; unsigned has_iif : 1; unsigned has_options : 1; + unsigned reverse_deps_done : 1; }; struct apk_solver_package_state { diff --git a/src/commit.c b/src/commit.c index 7136627..6a2580d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -370,13 +370,18 @@ static void print_pinning_errors(struct print_state *ps, struct apk_package *pkg if (pkg->ipkg != NULL) return; - if (pkg->repos & apk_db_get_pinning_mask_repos(db, APK_DEFAULT_PINNING_MASK | BIT(tag))) - return; - for (i = 0; i < db->num_repo_tags; i++) { - if (pkg->repos & db->repo_tags[i].allowed_repos) { - label_start(ps, "masked in:"); - apk_print_indented(&ps->i, db->repo_tags[i].tag); + if (!(pkg->repos & db->available_repos)) { + label_start(ps, "masked in:"); + apk_print_indented_fmt(&ps->i, "--no-network"); + } else { + if (pkg->repos & apk_db_get_pinning_mask_repos(db, APK_DEFAULT_PINNING_MASK | BIT(tag))) + return; + for (i = 0; i < db->num_repo_tags; i++) { + if (pkg->repos & db->repo_tags[i].allowed_repos) { + label_start(ps, "masked in:"); + apk_print_indented(&ps->i, db->repo_tags[i].tag); + } } } label_end(ps); 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; diff --git a/src/upgrade.c b/src/upgrade.c index 41d3cf7..f23ea91 100644 --- a/src/upgrade.c +++ b/src/upgrade.c @@ -35,6 +35,9 @@ static int upgrade_parse(void *ctx, struct apk_db_options *dbopts, case 'a': uctx->solver_flags |= APK_SOLVERF_AVAILABLE; break; + case 'l': + uctx->solver_flags |= APK_SOLVERF_LATEST; + break; default: return -1; } @@ -131,6 +134,9 @@ static struct apk_option upgrade_options[] = { "replacing or downgrading packages (instead of holding them) " "if the currently installed package is no longer available " "from any repository" }, + { 'l', "latest", + "Select latest version of package (if it is not pinned), and " + "print error if it cannot be installed due to other dependencies" }, { 0x10000, "no-self-upgrade", "Do not do early upgrade of 'apk-tools' package" }, }; diff --git a/test/basic12.test b/test/basic12.test new file mode 100644 index 0000000..f43b8ce --- /dev/null +++ b/test/basic12.test @@ -0,0 +1,15 @@ +@ARGS +--no-network +--test-repo basic.repo +--test-instdb basic.installed +--test-world a +--latest +upgrade +@EXPECT +ERROR: unsatisfiable constraints: + b-2: + masked in: --no-network + satisfies: a-2[b] + a-2: + masked in: --no-network + satisfies: world[a] diff --git a/test/basic13.test b/test/basic13.test new file mode 100644 index 0000000..40f5bb6 --- /dev/null +++ b/test/basic13.test @@ -0,0 +1,10 @@ +@ARGS +--test-repo basic.repo +--test-instdb basic.installed +--test-world a<2 +--latest +upgrade +@EXPECT +ERROR: unsatisfiable constraints: + a-2: + breaks: world[a<2] diff --git a/test/error5.test b/test/error5.test index 949fbe8..4becb3d 100644 --- a/test/error5.test +++ b/test/error5.test @@ -3,6 +3,6 @@ add a>2 @EXPECT ERROR: unsatisfiable constraints: - d-1.5: - breaks: a-3[d>1.5] - satisfies: b-1[d<2.0] c-1[d>1.0] + d-2.0: + breaks: b-1[d<2.0] + satisfies: a-3[d>1.5] c-1[d>1.0] |