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
Timo Teräs 2011-10-21 15:24:24 -04:00
parent bd0242e1de
commit e682e6596c
8 changed files with 44 additions and 20 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);
} }

View File

@ -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);
} }

19
test/conflict.repo Normal file
View File

@ -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

2
test/conflict1.expect Normal file
View File

@ -0,0 +1,2 @@
Installing b (2)
Installing a (1)

2
test/conflict2.expect Normal file
View File

@ -0,0 +1,2 @@
1 unsatisfiable dependencies (solution with 2 names)
world: b<2