diff options
author | Michael Schroeder <mls@suse.de> | 2017-09-01 15:55:05 +0200 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2018-03-28 13:26:20 +0300 |
commit | 2349e0efa3c0e7308d73aa940b5fc1451e484f42 (patch) | |
tree | c634a6802be74913470a7f1d5a69a4d6f1218e56 | |
parent | 039db6d9ea4983f206bed3c9203821f6b6dd65c2 (diff) | |
download | rpm-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.c | 36 | ||||
-rw-r--r-- | lib/order.c | 2 | ||||
-rw-r--r-- | lib/rpmdb.c | 4 | ||||
-rw-r--r-- | lib/rpmds.c | 5 | ||||
-rw-r--r-- | lib/rpmds.h | 3 |
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 { |