Commit f27f194d authored by Timo Teräs's avatar Timo Teräs

solver, test: make conflicts unconditional

Solver will now never report partial solution where a conflict
constraint is not satisfied. The is because with --force we might
install the partial solution; and if conflicted packages were to
be installed we might have extra trouble.
parent 2e8fe783
......@@ -75,8 +75,8 @@ static int add_main(void *ctx, struct apk_database *db, int argc, char **argv)
return -1;
apk_blob_pull_dep(&b, db, &virtdep);
if (APK_BLOB_IS_NULL(b) ||
virtdep.result_mask != APK_DEPMASK_REQUIRE ||
if (APK_BLOB_IS_NULL(b) || virtdep.conflict ||
virtdep.result_mask != APK_DEPMASK_ANY ||
virtdep.version != &apk_null_blob) {
apk_error("%s: bad package specifier");
return -1;
......
......@@ -61,7 +61,7 @@ struct apk_dependency {
struct apk_name *name;
apk_blob_t *version;
unsigned short repository_tag;
unsigned optional : 1;
unsigned conflict : 1;
unsigned result_mask : 3;
};
APK_ARRAY(apk_dependency_array, struct apk_dependency);
......
......@@ -18,8 +18,7 @@
#define APK_VERSION_LESS 2
#define APK_VERSION_GREATER 4
#define APK_DEPMASK_CONFLICT (0)
#define APK_DEPMASK_REQUIRE (APK_VERSION_EQUAL|APK_VERSION_LESS|\
#define APK_DEPMASK_ANY (APK_VERSION_EQUAL|APK_VERSION_LESS|\
APK_VERSION_GREATER)
#define APK_DEPMASK_CHECKSUM (APK_VERSION_LESS|APK_VERSION_GREATER)
......
......@@ -177,7 +177,7 @@ static int fetch_main(void *ctx, struct apk_database *db, int argc, char **argv)
struct apk_dependency dep = (struct apk_dependency) {
.name = apk_db_get_name(db, APK_BLOB_STR(argv[i])),
.version = apk_blob_atomize(APK_BLOB_NULL),
.result_mask = APK_DEPMASK_REQUIRE,
.result_mask = APK_DEPMASK_ANY,
};
if (fctx->flags & FETCH_RECURSIVE) {
......
......@@ -118,7 +118,7 @@ static int info_who_owns(struct info_ctx *ctx, struct apk_database *db,
dep = (struct apk_dependency) {
.name = pkg->name,
.version = apk_blob_atomize(APK_BLOB_NULL),
.result_mask = APK_DEPMASK_REQUIRE,
.result_mask = APK_DEPMASK_ANY,
};
apk_deps_add(&deps, &dep);
} else {
......
......@@ -218,7 +218,7 @@ void apk_blob_pull_dep(apk_blob_t *b, struct apk_database *db, struct apk_depend
{
struct apk_name *name;
apk_blob_t bdep, bname, bop, bver = APK_BLOB_NULL, btag;
int mask = APK_DEPMASK_REQUIRE, optional = 0, tag = 0;
int mask = APK_DEPMASK_ANY, conflict = 0, tag = 0;
/* [!]name[<,<=,=,>=,>,><]ver */
if (APK_BLOB_IS_NULL(*b))
......@@ -240,7 +240,7 @@ void apk_blob_pull_dep(apk_blob_t *b, struct apk_database *db, struct apk_depend
if (bdep.ptr[0] == '!') {
bdep.ptr++;
bdep.len--;
optional = 1;
conflict = 1;
}
if (apk_blob_cspn(bdep, apk_spn_dependency_comparer, &bname, &bop)) {
......@@ -281,15 +281,12 @@ void apk_blob_pull_dep(apk_blob_t *b, struct apk_database *db, struct apk_depend
if (name == NULL)
goto fail;
if (optional)
mask ^= APK_DEPMASK_REQUIRE;
*dep = (struct apk_dependency){
.name = name,
.version = apk_blob_atomize_dup(bver),
.repository_tag = tag,
.result_mask = mask,
.optional = optional,
.conflict = conflict,
};
return;
fail:
......@@ -340,46 +337,44 @@ static int apk_dep_match_checksum(struct apk_dependency *dep, struct apk_package
int apk_dep_is_provided(struct apk_dependency *dep, struct apk_provider *p)
{
if (p == NULL)
return dep->optional;
if (p == NULL || p->pkg == NULL)
return dep->conflict;
switch (dep->result_mask) {
case APK_DEPMASK_CHECKSUM:
return apk_dep_match_checksum(dep, p->pkg);
case APK_DEPMASK_CONFLICT:
return 0;
case APK_DEPMASK_REQUIRE:
return 1;
case APK_DEPMASK_ANY:
return !dep->conflict;
default:
if (p->version == &apk_null_blob)
return dep->conflict;
if (apk_version_compare_blob(*p->version, *dep->version)
& dep->result_mask)
return 1;
return 0;
return !dep->conflict;
return dep->conflict;
}
return 0;
return dep->conflict;
}
int apk_dep_is_materialized(struct apk_dependency *dep, struct apk_package *pkg)
{
if (pkg == NULL)
return dep->optional;
return dep->conflict;
if (dep->name != pkg->name)
return 0;
return dep->conflict;
switch (dep->result_mask) {
case APK_DEPMASK_CHECKSUM:
return apk_dep_match_checksum(dep, pkg);
case APK_DEPMASK_CONFLICT:
return 0;
case APK_DEPMASK_REQUIRE:
return 1;
case APK_DEPMASK_ANY:
return !dep->conflict;
default:
if (apk_version_compare_blob(*pkg->version, *dep->version)
& dep->result_mask)
return 1;
return 0;
return !dep->conflict;
return dep->conflict;
}
return 0;
return dep->conflict;
}
int apk_dep_is_materialized_or_provided(struct apk_dependency *dep, struct apk_package *pkg)
......@@ -387,7 +382,7 @@ int apk_dep_is_materialized_or_provided(struct apk_dependency *dep, struct apk_p
int i;
if (pkg == NULL)
return dep->optional;
return dep->conflict;
if (dep->name == pkg->name)
return apk_dep_is_materialized(dep, pkg);
......@@ -401,17 +396,15 @@ int apk_dep_is_materialized_or_provided(struct apk_dependency *dep, struct apk_p
return apk_dep_is_provided(dep, &p);
}
return dep->optional;
return dep->conflict;
}
void apk_blob_push_dep(apk_blob_t *to, struct apk_database *db, struct apk_dependency *dep)
{
int result_mask = dep->result_mask;
if (dep->optional) {
if (dep->conflict)
apk_blob_push_blob(to, APK_BLOB_PTR_LEN("!", 1));
result_mask ^= APK_DEPMASK_REQUIRE;
}
apk_blob_push_blob(to, APK_BLOB_STR(dep->name->name));
if (dep->repository_tag && db != NULL) {
......
......@@ -96,7 +96,9 @@ struct apk_package_state {
unsigned short inherited_upgrade;
unsigned short inherited_reinstall;
unsigned short conflicts;
unsigned short must_not;
unsigned short incompat_dep;
unsigned char preference;
unsigned handle_install_if : 1;
unsigned allowed : 1;
......@@ -152,6 +154,7 @@ struct apk_solver_state {
struct apk_score best_score;
unsigned solver_flags : 4;
unsigned impossible_state : 1;
};
typedef enum {
......@@ -367,7 +370,7 @@ static int get_topology_score(
int score_locked = TRUE, sticky_installed = FALSE;
score = (struct apk_score) {
.conflicts = ps->conflicts,
.conflicts = ps->incompat_dep,
.preference = ps->preference,
};
......@@ -796,6 +799,7 @@ static solver_result_t apply_decision(struct apk_solver_state *ss,
struct apk_score score;
int i;
ss->impossible_state = 0;
ns->name_touched = 1;
if (pkg != NULL) {
struct apk_package_state *ps = pkg_to_ps(pkg);
......@@ -855,6 +859,13 @@ static solver_result_t apply_decision(struct apk_solver_state *ss,
}
}
if (ss->impossible_state) {
dbg_printf("%s: %s impossible constraints\n",
name->name,
(d->type == DECISION_ASSIGN) ? "ASSIGN" : "EXCLUDE");
return SOLVERR_PRUNED;
}
if (cmpscore(&ss->score, &ss->best_score) >= 0) {
dbg_printf("%s: %s penalty too big: "SCORE_FMT">="SCORE_FMT"\n",
name->name,
......@@ -1024,13 +1035,18 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
else
dbg_printf("%s: locked to empty\n",
name->name);
if (!apk_dep_is_provided(dep, &ns->chosen))
if (!apk_dep_is_provided(dep, &ns->chosen)) {
dbg_printf("%s: constraint violation %d\n",
name->name, strength);
ss->score.conflicts += strength;
if (dep->conflict)
ss->impossible_state = 1;
}
return;
}
if (name->providers->num == 0) {
if (!dep->optional)
if (!dep->conflict)
ss->score.conflicts += strength;
return;
}
......@@ -1045,10 +1061,14 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
continue;
if (!apk_dep_is_provided(dep, p0)) {
ps0->conflicts++;
if (dep->conflict)
ps0->must_not++;
else
ps0->incompat_dep++;
dbg_printf(PKG_VER_FMT ": conflicts++ -> %d\n",
PKG_VER_PRINTF(pkg0),
ps0->conflicts);
ps0->must_not);
changed |= 1;
} else if (requirer_pkg != NULL) {
dbg_printf(PKG_VER_FMT ": inheriting flags and pinning from"PKG_VER_FMT"\n",
......@@ -1061,7 +1081,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
if (changed)
ns->last_touched_decision = ss->num_decisions;
if (!dep->optional)
if (!dep->conflict)
ns->requirers += strength;
promote_name(ss, name);
......@@ -1096,7 +1116,7 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
return;
}
if (name->providers->num == 0) {
if (!dep->optional)
if (!dep->conflict)
ss->score.conflicts -= strength;
return;
}
......@@ -1111,10 +1131,13 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
continue;
if (!apk_dep_is_provided(dep, p0)) {
ps0->conflicts--;
if (dep->conflict)
ps0->must_not--;
else
ps0->incompat_dep--;
dbg_printf(PKG_VER_FMT ": conflicts-- -> %d\n",
PKG_VER_PRINTF(pkg0),
ps0->conflicts);
ps0->must_not);
} else if (requirer_pkg != NULL) {
dbg_printf(PKG_VER_FMT ": uninheriting flags and pinning from "PKG_VER_FMT"\n",
PKG_VER_PRINTF(pkg0),
......@@ -1130,7 +1153,7 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
if (ns->last_touched_decision > ss->num_decisions)
ns->last_touched_decision = ss->num_decisions;
if (!dep->optional)
if (!dep->conflict)
ns->requirers -= strength;
demote_name(ss, name);
......@@ -1163,7 +1186,7 @@ static int reconsider_name(struct apk_solver_state *ss, struct apk_name *name)
struct apk_package_state *ps0 = pkg_to_ps(pkg0);
struct apk_score pkg0_score;
if (ps0 == NULL || ps0->locked ||
if (ps0 == NULL || ps0->locked || ps0->must_not ||
ss->topology_position < pkg0->topology_hard ||
(pkg0->ipkg == NULL && (!ps0->allowed || !pkg_available(ss->db, pkg0))))
continue;
......@@ -1274,7 +1297,7 @@ static int expand_branch(struct apk_solver_state *ss)
if (!ns->none_excluded) {
struct apk_package_state *ps0 = pkg_to_ps(pkg0);
if (ps0->conflicts > ns->requirers)
if (ps0->incompat_dep > ns->requirers)
primary_decision = DECISION_ASSIGN;
else
primary_decision = DECISION_EXCLUDE;
......
......@@ -114,7 +114,7 @@ static int upgrade_main(void *ctx, struct apk_database *db, int argc, char **arg
for (i = 0; i < world->num; i++) {
struct apk_dependency *dep = &world->item[i];
if (dep->result_mask == APK_DEPMASK_CHECKSUM) {
dep->result_mask = APK_DEPMASK_REQUIRE;
dep->result_mask = APK_DEPMASK_ANY;
dep->version = apk_blob_atomize(APK_BLOB_NULL);
}
}
......
......@@ -3,4 +3,4 @@
add a b>1
@EXPECT
ERROR: 1 unsatisfiable dependencies:
a-1: !b>1
world: a
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment