solver, pkg: implement versioned conflicts
One can now say in dependency "!foo<2" which means, that if foo is installed, it needs to be >=2, but it's not a required dependency.cute-signatures
parent
bd0242e1de
commit
e682e6596c
|
@ -59,7 +59,8 @@ struct apk_sign_ctx {
|
||||||
struct apk_dependency {
|
struct apk_dependency {
|
||||||
struct apk_name *name;
|
struct apk_name *name;
|
||||||
apk_blob_t *version;
|
apk_blob_t *version;
|
||||||
int result_mask;
|
unsigned optional : 1;
|
||||||
|
unsigned result_mask : 3;
|
||||||
};
|
};
|
||||||
APK_ARRAY(apk_dependency_array, struct apk_dependency);
|
APK_ARRAY(apk_dependency_array, struct apk_dependency);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#define APK_DEPMASK_REQUIRE (APK_VERSION_EQUAL|APK_VERSION_LESS|\
|
#define APK_DEPMASK_REQUIRE (APK_VERSION_EQUAL|APK_VERSION_LESS|\
|
||||||
APK_VERSION_GREATER)
|
APK_VERSION_GREATER)
|
||||||
#define APK_DEPMASK_CHECKSUM (APK_VERSION_LESS|APK_VERSION_GREATER)
|
#define APK_DEPMASK_CHECKSUM (APK_VERSION_LESS|APK_VERSION_GREATER)
|
||||||
#define APK_DEPMASK_CONFLICT (0)
|
|
||||||
|
|
||||||
const char *apk_version_op_string(int result_mask);
|
const char *apk_version_op_string(int result_mask);
|
||||||
int apk_version_result_mask(const char *str);
|
int apk_version_result_mask(const char *str);
|
||||||
|
|
|
@ -58,8 +58,7 @@ static void foreach_installed_reverse_dependency(
|
||||||
for (k = 0; k < pkg0->depends->num; k++) {
|
for (k = 0; k < pkg0->depends->num; k++) {
|
||||||
struct apk_dependency *dep = &pkg0->depends->item[k];
|
struct apk_dependency *dep = &pkg0->depends->item[k];
|
||||||
if (dep->name == name &&
|
if (dep->name == name &&
|
||||||
(dep->result_mask == APK_DEPMASK_CONFLICT ||
|
apk_dep_is_satisfied(dep, pkg))
|
||||||
apk_dep_is_satisfied(dep, pkg)))
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (k >= pkg0->depends->num)
|
if (k >= pkg0->depends->num)
|
||||||
|
|
|
@ -195,16 +195,16 @@ void apk_blob_pull_dep(apk_blob_t *b, struct apk_database *db, struct apk_depend
|
||||||
{
|
{
|
||||||
struct apk_name *name;
|
struct apk_name *name;
|
||||||
apk_blob_t bname, bop, bver = APK_BLOB_NULL;
|
apk_blob_t bname, bop, bver = APK_BLOB_NULL;
|
||||||
int mask = APK_DEPMASK_REQUIRE;
|
int mask = APK_DEPMASK_REQUIRE, optional = 0;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
/* [!]name[<,<=,=,>=,>]ver */
|
/* [!]name[<,<=,=,>=,>]ver */
|
||||||
if (APK_BLOB_IS_NULL(*b))
|
if (APK_BLOB_IS_NULL(*b))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (b->ptr[0] == '!') {
|
if (b->ptr[0] == '!') {
|
||||||
mask = 0;
|
|
||||||
b->ptr++;
|
b->ptr++;
|
||||||
b->len--;
|
b->len--;
|
||||||
|
optional = 1;
|
||||||
}
|
}
|
||||||
if (apk_blob_cspn(*b, "<>= ", &bname, &bop)) {
|
if (apk_blob_cspn(*b, "<>= ", &bname, &bop)) {
|
||||||
int i;
|
int i;
|
||||||
|
@ -243,10 +243,14 @@ void apk_blob_pull_dep(apk_blob_t *b, struct apk_database *db, struct apk_depend
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (optional)
|
||||||
|
mask ^= APK_DEPMASK_REQUIRE;
|
||||||
|
|
||||||
*dep = (struct apk_dependency){
|
*dep = (struct apk_dependency){
|
||||||
.name = name,
|
.name = name,
|
||||||
.version = apk_blob_atomize_dup(bver),
|
.version = apk_blob_atomize_dup(bver),
|
||||||
.result_mask = mask,
|
.result_mask = mask,
|
||||||
|
.optional = optional,
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
fail:
|
fail:
|
||||||
|
@ -292,11 +296,8 @@ static int parse_depend(void *ctx, apk_blob_t blob)
|
||||||
|
|
||||||
int apk_dep_is_satisfied(struct apk_dependency *dep, struct apk_package *pkg)
|
int apk_dep_is_satisfied(struct apk_dependency *dep, struct apk_package *pkg)
|
||||||
{
|
{
|
||||||
if (pkg == NULL) {
|
if (pkg == NULL)
|
||||||
if (dep->result_mask == APK_DEPMASK_CONFLICT)
|
return dep->optional;
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (dep->name != pkg->name)
|
if (dep->name != pkg->name)
|
||||||
return 0;
|
return 0;
|
||||||
if (dep->result_mask == APK_DEPMASK_CHECKSUM) {
|
if (dep->result_mask == APK_DEPMASK_CHECKSUM) {
|
||||||
|
@ -326,13 +327,16 @@ void apk_blob_pull_deps(apk_blob_t *b, struct apk_database *db, struct apk_depen
|
||||||
|
|
||||||
void apk_blob_push_dep(apk_blob_t *to, struct apk_dependency *dep)
|
void apk_blob_push_dep(apk_blob_t *to, struct apk_dependency *dep)
|
||||||
{
|
{
|
||||||
if (dep->result_mask == APK_DEPMASK_CONFLICT)
|
int result_mask = dep->result_mask;
|
||||||
|
|
||||||
|
if (dep->optional) {
|
||||||
apk_blob_push_blob(to, APK_BLOB_PTR_LEN("!", 1));
|
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));
|
apk_blob_push_blob(to, APK_BLOB_STR(dep->name->name));
|
||||||
|
|
||||||
if (dep->result_mask != APK_DEPMASK_CONFLICT &&
|
if (!APK_BLOB_IS_NULL(*dep->version)) {
|
||||||
dep->result_mask != APK_DEPMASK_REQUIRE) {
|
|
||||||
apk_blob_push_blob(to, APK_BLOB_STR(apk_version_op_string(dep->result_mask)));
|
apk_blob_push_blob(to, APK_BLOB_STR(apk_version_op_string(dep->result_mask)));
|
||||||
apk_blob_push_blob(to, *dep->version);
|
apk_blob_push_blob(to, *dep->version);
|
||||||
}
|
}
|
||||||
|
|
10
src/solver.c
10
src/solver.c
|
@ -126,8 +126,7 @@ static void foreach_dependency_pkg(
|
||||||
struct apk_package *pkg0 = name0->pkgs->item[j];
|
struct apk_package *pkg0 = name0->pkgs->item[j];
|
||||||
|
|
||||||
/* conflict depends on all to be not installed */
|
/* conflict depends on all to be not installed */
|
||||||
if (dep->result_mask != APK_DEPMASK_CONFLICT &&
|
if (!apk_dep_is_satisfied(dep, pkg0))
|
||||||
!apk_dep_is_satisfied(dep, pkg0))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cb(ss, pkg0);
|
cb(ss, pkg0);
|
||||||
|
@ -154,8 +153,7 @@ static void foreach_rinstall_if_pkg(
|
||||||
for (k = 0; k < pkg0->install_if->num; k++) {
|
for (k = 0; k < pkg0->install_if->num; k++) {
|
||||||
struct apk_dependency *dep = &pkg0->install_if->item[k];
|
struct apk_dependency *dep = &pkg0->install_if->item[k];
|
||||||
if (dep->name == name &&
|
if (dep->name == name &&
|
||||||
(dep->result_mask == APK_DEPMASK_CONFLICT ||
|
apk_dep_is_satisfied(dep, pkg))
|
||||||
apk_dep_is_satisfied(dep, pkg)))
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (k >= pkg0->install_if->num)
|
if (k >= pkg0->install_if->num)
|
||||||
|
@ -635,7 +633,7 @@ static void apply_constraint(struct apk_solver_state *ss, struct apk_dependency
|
||||||
if (ss->latest_decision != NULL)
|
if (ss->latest_decision != NULL)
|
||||||
inherit_name_state(name, ss->latest_decision->name);
|
inherit_name_state(name, ss->latest_decision->name);
|
||||||
|
|
||||||
if (dep->result_mask != APK_DEPMASK_CONFLICT)
|
if (!dep->optional)
|
||||||
ns->requirers++;
|
ns->requirers++;
|
||||||
update_name_state(ss, name);
|
update_name_state(ss, name);
|
||||||
}
|
}
|
||||||
|
@ -675,7 +673,7 @@ static void undo_constraint(struct apk_solver_state *ss, struct apk_dependency *
|
||||||
if (ss->latest_decision && has_inherited_state(ss->latest_decision->name))
|
if (ss->latest_decision && has_inherited_state(ss->latest_decision->name))
|
||||||
recalculate_inherted_name_state(name);
|
recalculate_inherted_name_state(name);
|
||||||
|
|
||||||
if (dep->result_mask != APK_DEPMASK_CONFLICT)
|
if (!dep->optional)
|
||||||
ns->requirers--;
|
ns->requirers--;
|
||||||
update_name_state(ss, name);
|
update_name_state(ss, name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
C:Q1EyN5AdpAOBJWKMR89pp/C66o+OE=
|
||||||
|
P:a
|
||||||
|
V:1
|
||||||
|
S:1
|
||||||
|
I:1
|
||||||
|
D:!b<2
|
||||||
|
|
||||||
|
C:Q1C4uoV7SdMdDhYg4OCVmI71D8HIA=
|
||||||
|
P:b
|
||||||
|
V:1
|
||||||
|
S:1
|
||||||
|
I:1
|
||||||
|
|
||||||
|
C:Q1hdUpqRv5mYgJEqW52UmVsvmyysE=
|
||||||
|
P:b
|
||||||
|
V:2
|
||||||
|
S:1
|
||||||
|
I:1
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Installing b (2)
|
||||||
|
Installing a (1)
|
|
@ -0,0 +1,2 @@
|
||||||
|
1 unsatisfiable dependencies (solution with 2 names)
|
||||||
|
world: b<2
|
Loading…
Reference in New Issue