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_UPGRADE 0x0001
|
||||||
#define APK_SOLVERF_AVAILABLE 0x0002
|
#define APK_SOLVERF_AVAILABLE 0x0002
|
||||||
#define APK_SOLVERF_REINSTALL 0x0004
|
#define APK_SOLVERF_REINSTALL 0x0004
|
||||||
|
#define APK_SOLVERF_LATEST 0x0008
|
||||||
|
|
||||||
void apk_solver_set_name_flags(struct apk_name *name,
|
void apk_solver_set_name_flags(struct apk_name *name,
|
||||||
unsigned short solver_flags,
|
unsigned short solver_flags,
|
||||||
|
|
|
@ -32,6 +32,7 @@ struct apk_solver_name_state {
|
||||||
unsigned locked : 1;
|
unsigned locked : 1;
|
||||||
unsigned has_iif : 1;
|
unsigned has_iif : 1;
|
||||||
unsigned has_options : 1;
|
unsigned has_options : 1;
|
||||||
|
unsigned reverse_deps_done : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct apk_solver_package_state {
|
struct apk_solver_package_state {
|
||||||
|
|
17
src/commit.c
17
src/commit.c
|
@ -370,13 +370,18 @@ static void print_pinning_errors(struct print_state *ps, struct apk_package *pkg
|
||||||
|
|
||||||
if (pkg->ipkg != NULL)
|
if (pkg->ipkg != NULL)
|
||||||
return;
|
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->available_repos)) {
|
||||||
if (pkg->repos & db->repo_tags[i].allowed_repos) {
|
label_start(ps, "masked in:");
|
||||||
label_start(ps, "masked in:");
|
apk_print_indented_fmt(&ps->i, "--no-network");
|
||||||
apk_print_indented(&ps->i, db->repo_tags[i].tag);
|
} 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);
|
label_end(ps);
|
||||||
|
|
149
src/solver.c
149
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);
|
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_VER_PRINTF(pkg),
|
||||||
pkg->ss.tag_ok,
|
pkg->ss.tag_ok,
|
||||||
pkg->ss.tag_preferred,
|
pkg->ss.tag_preferred,
|
||||||
pkg->ss.max_dep_chain);
|
pkg->ss.max_dep_chain,
|
||||||
|
pkg->ss.available);
|
||||||
}
|
}
|
||||||
foreach_array_item(pname0, name->rinstall_if)
|
foreach_array_item(pname0, name->rinstall_if)
|
||||||
discover_name(ss, *pname0);
|
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));
|
BLOB_PRINTF(*dep->version));
|
||||||
|
|
||||||
name->ss.requirers += !dep->conflict;
|
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) {
|
foreach_array_item(p0, name->providers) {
|
||||||
struct apk_package *pkg0 = p0->pkg;
|
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)
|
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_dependency *dep;
|
||||||
struct apk_package *first_candidate = NULL;
|
struct apk_package *first_candidate = NULL;
|
||||||
struct apk_provider *p;
|
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)
|
foreach_array_item(p, name->providers)
|
||||||
p->pkg->ss.dependencies_used = p->pkg->ss.dependencies_merged;
|
p->pkg->ss.dependencies_used = p->pkg->ss.dependencies_merged;
|
||||||
|
|
||||||
/* TODO: could merge versioning bits too */
|
|
||||||
/* propagate down common dependencies */
|
/* propagate down common dependencies */
|
||||||
foreach_array_item(dep, first_candidate->depends) {
|
if (num_options == 1) {
|
||||||
if (dep->conflict)
|
/* FIXME: keeps increasing counts, use bit fields instead? */
|
||||||
continue;
|
foreach_array_item(dep, first_candidate->depends)
|
||||||
name0 = dep->name;
|
apply_constraint(ss, first_candidate, dep);
|
||||||
if (name0->ss.merge_index == num_options) {
|
} else {
|
||||||
/* common dependency name with all */
|
/* FIXME: could merge versioning bits too */
|
||||||
if (name0->ss.requirers == 0) {
|
foreach_array_item(dep, first_candidate->depends) {
|
||||||
dbg_printf("%s common dependency: %s\n",
|
if (dep->conflict)
|
||||||
name->name, name0->name);
|
continue;
|
||||||
name0->ss.requirers++;
|
name0 = dep->name;
|
||||||
name_requirers_changed(ss, name0);
|
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->ss.reverse_deps_done = 1;
|
||||||
name->name, name->ss.has_options);
|
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,
|
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)
|
if (pkgA == NULL || pkgB == NULL)
|
||||||
return (pkgA != NULL) - (pkgB != NULL);
|
return (pkgA != NULL) - (pkgB != NULL);
|
||||||
|
|
||||||
/* Prefer without errors */
|
/* Latest version required? */
|
||||||
r = (int)pkgA->ss.available - (int)pkgB->ss.available;
|
|
||||||
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 installed on self-upgrade */
|
|
||||||
solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
|
solver_flags = pkgA->ss.solver_flags | pkgB->ss.solver_flags;
|
||||||
if (db->performing_self_update && !(solver_flags & APK_SOLVERF_UPGRADE)) {
|
if ((solver_flags & APK_SOLVERF_LATEST) &&
|
||||||
r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
|
(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)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
/* Prefer allowed pinning */
|
/* Prefer available */
|
||||||
r = (int)pkgA->ss.tag_ok - (int)pkgB->ss.tag_ok;
|
if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
|
||||||
if (r)
|
r = !!(pkgA->repos & db->available_repos) - !!(pkgB->repos & db->available_repos);
|
||||||
return r;
|
if (r)
|
||||||
|
return r;
|
||||||
/* Prefer available */
|
}
|
||||||
if (solver_flags & (APK_SOLVERF_AVAILABLE | APK_SOLVERF_REINSTALL)) {
|
} else {
|
||||||
r = !!(pkgA->repos & db->available_repos) -
|
/* Prefer without errors */
|
||||||
!!(pkgB->repos & db->available_repos);
|
r = (int)pkgA->ss.available - (int)pkgB->ss.available;
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
/* Prefer preferred pinning */
|
/* Prefer those that were in last dependency merging group */
|
||||||
r = (int)pkgA->ss.tag_preferred - (int)pkgB->ss.tag_preferred;
|
r = (int)pkgA->ss.dependencies_used - (int)pkgB->ss.dependencies_used;
|
||||||
if (r)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* Prefer installed */
|
|
||||||
if (!(solver_flags & APK_SOLVERF_UPGRADE)) {
|
|
||||||
r = (pkgA->ipkg != NULL) - (pkgB->ipkg != NULL);
|
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
r = pkgB->ss.conflicts - pkgA->ss.conflicts;
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
/* Select latest by requested name */
|
||||||
|
@ -747,17 +780,15 @@ restart:
|
||||||
|
|
||||||
name = NULL;
|
name = NULL;
|
||||||
list_for_each_entry(name0, &ss->unresolved_head, ss.unresolved_list) {
|
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;
|
name = name0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
goto prefer;
|
goto prefer;
|
||||||
if (name0->ss.requirers == 0 && name->ss.requirers > 0)
|
if ((!!name0->ss.requirers) - (!!name->ss.requirers) < 0)
|
||||||
continue;
|
continue;
|
||||||
if (name0->ss.requirers > 0 && name->ss.requirers == 0)
|
if (name0->ss.max_dep_chain - name->ss.max_dep_chain < 0)
|
||||||
goto prefer;
|
|
||||||
if (name0->ss.max_dep_chain < name->ss.max_dep_chain)
|
|
||||||
continue;
|
continue;
|
||||||
prefer:
|
prefer:
|
||||||
name = name0;
|
name = name0;
|
||||||
|
|
|
@ -35,6 +35,9 @@ static int upgrade_parse(void *ctx, struct apk_db_options *dbopts,
|
||||||
case 'a':
|
case 'a':
|
||||||
uctx->solver_flags |= APK_SOLVERF_AVAILABLE;
|
uctx->solver_flags |= APK_SOLVERF_AVAILABLE;
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
uctx->solver_flags |= APK_SOLVERF_LATEST;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +134,9 @@ static struct apk_option upgrade_options[] = {
|
||||||
"replacing or downgrading packages (instead of holding them) "
|
"replacing or downgrading packages (instead of holding them) "
|
||||||
"if the currently installed package is no longer available "
|
"if the currently installed package is no longer available "
|
||||||
"from any repository" },
|
"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",
|
{ 0x10000, "no-self-upgrade",
|
||||||
"Do not do early upgrade of 'apk-tools' package" },
|
"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
|
add a>2
|
||||||
@EXPECT
|
@EXPECT
|
||||||
ERROR: unsatisfiable constraints:
|
ERROR: unsatisfiable constraints:
|
||||||
d-1.5:
|
d-2.0:
|
||||||
breaks: a-3[d>1.5]
|
breaks: b-1[d<2.0]
|
||||||
satisfies: b-1[d<2.0] c-1[d>1.0]
|
satisfies: a-3[d>1.5] c-1[d>1.0]
|
||||||
|
|
Loading…
Reference in New Issue