summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Schroeder <mls@suse.de>2017-09-01 15:55:05 +0200
committerPanu Matilainen <pmatilai@redhat.com>2018-03-28 13:26:20 +0300
commit2349e0efa3c0e7308d73aa940b5fc1451e484f42 (patch)
treec634a6802be74913470a7f1d5a69a4d6f1218e56
parent039db6d9ea4983f206bed3c9203821f6b6dd65c2 (diff)
downloadrpm-2349e0efa3c0e7308d73aa940b5fc1451e484f42.tar.gz
Add support for 'unless' rich dependencies
An (A unless B) dependency implements (A and not(B)). This kind is useful for "or" type dependencies, e.g. "Conflicts" or "Supplements". As "Conflicts: (A unless B)" is equivalent to "Requires: (B if A)", I thought this type is not needed. But there is no such equivalence for Supplements, thus the change in mind. Like with "if" we also have a syntactic sugar "else" flavor: (A unless B else C) is the same as ((A unless B) or (B and C)) This commit also makes the "else" handling code in depends.c much easier to understand. (cherry picked from commit 37982efbacdc2ccc00cea988a049dfa32749936f)
-rw-r--r--lib/depends.c36
-rw-r--r--lib/order.c2
-rw-r--r--lib/rpmdb.c4
-rw-r--r--lib/rpmds.c5
-rw-r--r--lib/rpmds.h3
5 files changed, 31 insertions, 19 deletions
diff --git a/lib/depends.c b/lib/depends.c
index c73e64953..94842f961 100644
--- a/lib/depends.c
+++ b/lib/depends.c
@@ -733,30 +733,38 @@ retry:
rpmdsNotify(dep, "(rich)", rc);
goto exit;
}
- if (op == RPMRICHOP_IF) {
+ if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS) {
+ /* A IF B -> A OR NOT(B) */
+ /* A UNLESS B -> A AND NOT(B) */
if (rpmdsIsRich(ds2)) {
- /* check if this is a IF...ELSE combination */
+ /* check if this has an ELSE clause */
rpmds ds21 = NULL, ds22 = NULL;
rpmrichOp op2;
if (rpmdsParseRichDep(ds2, &ds21, &ds22, &op2, NULL) == RPMRC_OK && op2 == RPMRICHOP_ELSE) {
- rc = unsatisfiedDepend(ts, dcache, ds21);
- if (rc) {
- rpmdsFree(ds1);
- ds1 = ds22;
- ds22 = NULL;
+ /* A IF B ELSE C -> (A OR NOT(B)) AND (C OR B) */
+ /* A UNLESS B ELSE C -> (A AND NOT(B)) OR (C AND B) */
+ rc = !unsatisfiedDepend(ts, dcache, ds21); /* NOT(B) */
+ if ((rc && op == RPMRICHOP_IF) || (!rc && op == RPMRICHOP_UNLESS)) {
+ rc = unsatisfiedDepend(ts, dcache, ds1); /* A */
+ } else {
+ rc = unsatisfiedDepend(ts, dcache, ds22); /* C */
}
- rc = 1;
+ rpmdsFree(ds21);
+ rpmdsFree(ds22);
+ goto exitrich;
}
rpmdsFree(ds21);
rpmdsFree(ds22);
}
- if (!rc)
- rc = !unsatisfiedDepend(ts, dcache, ds2);
- }
- if (op != RPMRICHOP_IF || rc)
+ rc = !unsatisfiedDepend(ts, dcache, ds2); /* NOT(B) */
+ if ((rc && op == RPMRICHOP_IF) || (!rc && op == RPMRICHOP_UNLESS))
+ rc = unsatisfiedDepend(ts, dcache, ds1);
+ } else {
rc = unsatisfiedDepend(ts, dcache, ds1);
- if ((rc && op == RPMRICHOP_OR) || (!rc && op == RPMRICHOP_AND))
- rc = unsatisfiedDepend(ts, dcache, ds2);
+ if ((rc && op == RPMRICHOP_OR) || (!rc && op == RPMRICHOP_AND))
+ rc = unsatisfiedDepend(ts, dcache, ds2);
+ }
+exitrich:
ds1 = rpmdsFree(ds1);
ds2 = rpmdsFree(ds2);
rpmdsNotify(dep, "(rich)", rc);
diff --git a/lib/order.c b/lib/order.c
index 854f37e98..50fde30aa 100644
--- a/lib/order.c
+++ b/lib/order.c
@@ -159,7 +159,7 @@ static inline int addRelation(rpmts ts,
if (rpmdsParseRichDep(requires, &ds1, &ds2, &op, NULL) == RPMRC_OK) {
if (op != RPMRICHOP_ELSE)
addRelation(ts, al, p, ds1);
- if (op == RPMRICHOP_IF) {
+ if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS) {
rpmds ds21, ds22;
rpmrichOp op2;
if (rpmdsParseRichDep(requires, &ds21, &ds22, &op2, NULL) == RPMRC_OK && op2 == RPMRICHOP_ELSE) {
diff --git a/lib/rpmdb.c b/lib/rpmdb.c
index 9469ede33..a17a89f20 100644
--- a/lib/rpmdb.c
+++ b/lib/rpmdb.c
@@ -2194,7 +2194,7 @@ static rpmRC updateRichDepCB(void *cbdata, rpmrichParseType type,
data->nargv++;
_free(name);
}
- if (type == RPMRICH_PARSE_OP && op == RPMRICHOP_IF) {
+ if (type == RPMRICH_PARSE_OP && (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS)) {
/* save nargv in case of ELSE */
data->nargv_level[data->level - 1] = data->nargv;
data->neg ^= 1;
@@ -2211,7 +2211,7 @@ static rpmRC updateRichDepCB(void *cbdata, rpmrichParseType type,
}
data->neg ^= 1;
}
- if (type == RPMRICH_PARSE_LEAVE && op == RPMRICHOP_IF) {
+ if (type == RPMRICH_PARSE_LEAVE && (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS)) {
data->neg ^= 1;
}
return RPMRC_OK;
diff --git a/lib/rpmds.c b/lib/rpmds.c
index be788d7e2..c57ac1f7f 100644
--- a/lib/rpmds.c
+++ b/lib/rpmds.c
@@ -1357,6 +1357,7 @@ static struct RichOpComp {
{ "and", RPMRICHOP_AND},
{ "or", RPMRICHOP_OR},
{ "if", RPMRICHOP_IF},
+ { "unless", RPMRICHOP_UNLESS},
{ "else", RPMRICHOP_ELSE},
{ "with", RPMRICHOP_WITH},
{ "without", RPMRICHOP_WITHOUT},
@@ -1397,6 +1398,8 @@ const char *rpmrichOpStr(rpmrichOp op)
return "or";
if (op == RPMRICHOP_IF)
return "if";
+ if (op == RPMRICHOP_UNLESS)
+ return "unless";
if (op == RPMRICHOP_ELSE)
return "else";
if (op == RPMRICHOP_WITH)
@@ -1492,7 +1495,7 @@ static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseF
pe = p;
if (parseRichDepOp(&pe, &op, emsg) != RPMRC_OK)
return RPMRC_FAIL;
- if (op == RPMRICHOP_ELSE && chainop == RPMRICHOP_IF)
+ if (op == RPMRICHOP_ELSE && (chainop == RPMRICHOP_IF || chainop == RPMRICHOP_UNLESS))
chainop = 0;
if (chainop && op != chainop) {
if (emsg)
diff --git a/lib/rpmds.h b/lib/rpmds.h
index 8f1c0c3ef..b1a587dfa 100644
--- a/lib/rpmds.h
+++ b/lib/rpmds.h
@@ -470,7 +470,8 @@ typedef enum rpmrichOp_e {
RPMRICHOP_IF = 4,
RPMRICHOP_ELSE = 5,
RPMRICHOP_WITH = 6,
- RPMRICHOP_WITHOUT = 7
+ RPMRICHOP_WITHOUT = 7,
+ RPMRICHOP_UNLESS = 8
} rpmrichOp;
typedef enum rpmrichParseType_e {