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.cute-signatures
parent
f91b01fea8
commit
d315c9019c
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -370,15 +370,20 @@ static void print_pinning_errors(struct print_state *ps, struct apk_package *pkg
|
|||
|
||||
if (pkg->ipkg != NULL)
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
59
src/solver.c
59
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,6 +267,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_package *pp
|
|||
BLOB_PRINTF(*dep->version));
|
||||
|
||||
name->ss.requirers += !dep->conflict;
|
||||
if (name->ss.requirers == 1 && !dep->conflict)
|
||||
name_requirers_changed(ss, name);
|
||||
|
||||
foreach_array_item(p0, name->providers) {
|
||||
|
@ -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,8 +368,13 @@ 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 */
|
||||
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;
|
||||
|
@ -384,8 +391,18 @@ static void reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
|
|||
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,6 +417,23 @@ static int compare_providers(struct apk_solver_state *ss,
|
|||
if (pkgA == NULL || pkgB == NULL)
|
||||
return (pkgA != NULL) - (pkgB != NULL);
|
||||
|
||||
/* 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 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)
|
||||
|
@ -414,7 +448,6 @@ static int compare_providers(struct apk_solver_state *ss,
|
|||
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);
|
||||
if (r)
|
||||
|
@ -428,8 +461,7 @@ static int compare_providers(struct apk_solver_state *ss,
|
|||
|
||||
/* Prefer available */
|
||||
if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
|
||||
r = !!(pkgA->repos & db->available_repos) -
|
||||
!!(pkgB->repos & db->available_repos);
|
||||
r = !!(pkgA->repos & db->available_repos) - !!(pkgB->repos & db->available_repos);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
@ -445,6 +477,7 @@ static int compare_providers(struct apk_solver_state *ss,
|
|||
if (r)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Select latest by requested name */
|
||||
switch (apk_version_compare_blob(*pA->version, *pB->version)) {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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" },
|
||||
};
|
||||
|
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue