| |
@@ -0,0 +1,306 @@
|
| |
+ From c3ec27e58d9eb24919945eb7690fb02c8e5a4b6e Mon Sep 17 00:00:00 2001
|
| |
+ From: Michael Schroeder <mls@suse.de>
|
| |
+ Date: Thu, 3 Aug 2017 14:06:33 +0200
|
| |
+ Subject: [PATCH 7/7] Implement with/without rich dependencies
|
| |
+
|
| |
+ Unlike the other rich rependencies they work by evaluating package
|
| |
+ sets. This means, "Requires: (foo with bar)" is only fulfilled
|
| |
+ by a package that provides both foo and bar. In comparison,
|
| |
+ "Requires: (foo and bar)" can be fulfilled by two different
|
| |
+ packages.
|
| |
+
|
| |
+ Without implements set subtraction, e.g. "Requires: (foo without bar)"
|
| |
+ is only fulfilled by a package that provides foo but not bar.
|
| |
+
|
| |
+ (cherry picked from commit dac1c702562f57bd7ab080172d7e228cda25a819)
|
| |
+ ---
|
| |
+ lib/depends.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
|
| |
+ lib/rpmds.c | 35 ++++++++++++++++-----
|
| |
+ lib/rpmds.h | 12 +++++---
|
| |
+ 3 files changed, 128 insertions(+), 17 deletions(-)
|
| |
+
|
| |
+ diff --git a/lib/depends.c b/lib/depends.c
|
| |
+ index fc413a903..c73e64953 100644
|
| |
+ --- a/lib/depends.c
|
| |
+ +++ b/lib/depends.c
|
| |
+ @@ -17,6 +17,8 @@
|
| |
+ #include "lib/rpmfi_internal.h" /* rpmfiles stuff for now */
|
| |
+ #include "lib/misc.h"
|
| |
+
|
| |
+ +#include "lib/backend/dbiset.h"
|
| |
+ +
|
| |
+ #include "debug.h"
|
| |
+
|
| |
+ const char * const RPMVERSION = VERSION;
|
| |
+ @@ -510,7 +512,7 @@ int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
|
| |
+ }
|
| |
+
|
| |
+ /* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */
|
| |
+ -static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
|
| |
+ +static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep, dbiIndexSet *matches)
|
| |
+ {
|
| |
+ const char * Name = rpmdsN(dep);
|
| |
+ const char * DNEVR = rpmdsDNEVR(dep);
|
| |
+ @@ -524,7 +526,7 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
|
| |
+ unsigned int keyhash = 0;
|
| |
+
|
| |
+ /* See if we already looked this up */
|
| |
+ - if (prune) {
|
| |
+ + if (prune && !matches) {
|
| |
+ keyhash = depCacheKeyHash(dcache, DNEVR);
|
| |
+ if (depCacheGetHEntry(dcache, DNEVR, keyhash, &cachedrc, NULL, NULL)) {
|
| |
+ rc = *cachedrc;
|
| |
+ @@ -533,6 +535,8 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
|
| |
+ }
|
| |
+ }
|
| |
+
|
| |
+ + if (matches)
|
| |
+ + *matches = dbiIndexSetNew(0);
|
| |
+ /*
|
| |
+ * See if a filename dependency is a real file in some package,
|
| |
+ * taking file state into account: replaced, wrong colored and
|
| |
+ @@ -547,6 +551,10 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
|
| |
+ if (instance && instance == rpmdsInstance(dep))
|
| |
+ continue;
|
| |
+ }
|
| |
+ + if (matches) {
|
| |
+ + dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
|
| |
+ + continue;
|
| |
+ + }
|
| |
+ rpmdsNotify(dep, "(db files)", rc);
|
| |
+ break;
|
| |
+ }
|
| |
+ @@ -577,6 +585,10 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
|
| |
+ match = 0;
|
| |
+ }
|
| |
+ if (match) {
|
| |
+ + if (matches) {
|
| |
+ + dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
|
| |
+ + continue;
|
| |
+ + }
|
| |
+ rpmdsNotify(dep, "(db provides)", rc);
|
| |
+ break;
|
| |
+ }
|
| |
+ @@ -585,13 +597,81 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)
|
| |
+ }
|
| |
+ rc = (h != NULL) ? 0 : 1;
|
| |
+
|
| |
+ + if (matches) {
|
| |
+ + dbiIndexSetUniq(*matches, 0);
|
| |
+ + rc = dbiIndexSetCount(*matches) ? 0 : 1;
|
| |
+ + }
|
| |
+ +
|
| |
+ /* Cache the relatively expensive rpmdb lookup results */
|
| |
+ /* Caching the oddball non-pruned case would mess up other results */
|
| |
+ - if (prune)
|
| |
+ + if (prune && !matches)
|
| |
+ depCacheAddHEntry(dcache, xstrdup(DNEVR), keyhash, rc);
|
| |
+ return rc;
|
| |
+ }
|
| |
+
|
| |
+ +static dbiIndexSet unsatisfiedDependSet(rpmts ts, rpmds dep)
|
| |
+ +{
|
| |
+ + dbiIndexSet set1 = NULL, set2 = NULL;
|
| |
+ + tsMembers tsmem = rpmtsMembers(ts);
|
| |
+ + rpmsenseFlags dsflags = rpmdsFlags(dep);
|
| |
+ +
|
| |
+ + if (dsflags & RPMSENSE_RPMLIB)
|
| |
+ + goto exit;
|
| |
+ +
|
| |
+ + if (rpmdsIsRich(dep)) {
|
| |
+ + rpmds ds1, ds2;
|
| |
+ + rpmrichOp op;
|
| |
+ + char *emsg = 0;
|
| |
+ +
|
| |
+ + if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {
|
| |
+ + rpmdsNotify(dep, emsg ? emsg : "(parse error)", 1);
|
| |
+ + _free(emsg);
|
| |
+ + goto exit;
|
| |
+ + }
|
| |
+ + /* only a subset of ops is supported in set mode */
|
| |
+ + if (op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT
|
| |
+ + && op != RPMRICHOP_OR && op != RPMRICHOP_SINGLE) {
|
| |
+ + rpmdsNotify(dep, "(unsupported op in set mode)", 1);
|
| |
+ + goto exit_rich;
|
| |
+ + }
|
| |
+ +
|
| |
+ + set1 = unsatisfiedDependSet(ts, ds1);
|
| |
+ + if (op == RPMRICHOP_SINGLE)
|
| |
+ + goto exit_rich;
|
| |
+ + if (op != RPMRICHOP_OR && dbiIndexSetCount(set1) == 0)
|
| |
+ + goto exit_rich;
|
| |
+ + set2 = unsatisfiedDependSet(ts, ds2);
|
| |
+ + if (op == RPMRICHOP_WITH) {
|
| |
+ + dbiIndexSetFilterSet(set1, set2, 0);
|
| |
+ + } else if (op == RPMRICHOP_WITHOUT) {
|
| |
+ + dbiIndexSetPruneSet(set1, set2, 0);
|
| |
+ + } else if (op == RPMRICHOP_OR) {
|
| |
+ + dbiIndexSetAppendSet(set1, set2, 0);
|
| |
+ + }
|
| |
+ +exit_rich:
|
| |
+ + ds1 = rpmdsFree(ds1);
|
| |
+ + ds2 = rpmdsFree(ds2);
|
| |
+ + goto exit;
|
| |
+ + }
|
| |
+ +
|
| |
+ + /* match database entries */
|
| |
+ + rpmdbProvides(ts, NULL, dep, &set1);
|
| |
+ +
|
| |
+ + /* Pretrans dependencies can't be satisfied by added packages. */
|
| |
+ + if (!(dsflags & RPMSENSE_PRETRANS)) {
|
| |
+ + rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
|
| |
+ + if (matches) {
|
| |
+ + for (rpmte *p = matches; *p; p++)
|
| |
+ + dbiIndexSetAppendOne(set1, rpmalLookupTE(tsmem->addedPackages, *p), 1, 0);
|
| |
+ + }
|
| |
+ + _free(matches);
|
| |
+ + }
|
| |
+ +
|
| |
+ +exit:
|
| |
+ + set2 = dbiIndexSetFree(set2);
|
| |
+ + return set1 ? set1 : dbiIndexSetNew(0);
|
| |
+ +}
|
| |
+ +
|
| |
+ /**
|
| |
+ * Check dep for an unsatisfied dependency.
|
| |
+ * @param ts transaction set
|
| |
+ @@ -643,6 +723,16 @@ retry:
|
| |
+ _free(emsg);
|
| |
+ goto exit;
|
| |
+ }
|
| |
+ + if (op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) {
|
| |
+ + /* switch to set mode processing */
|
| |
+ + dbiIndexSet set = unsatisfiedDependSet(ts, dep);
|
| |
+ + rc = dbiIndexSetCount(set) ? 0 : 1;
|
| |
+ + dbiIndexSetFree(set);
|
| |
+ + ds1 = rpmdsFree(ds1);
|
| |
+ + ds2 = rpmdsFree(ds2);
|
| |
+ + rpmdsNotify(dep, "(rich)", rc);
|
| |
+ + goto exit;
|
| |
+ + }
|
| |
+ if (op == RPMRICHOP_IF) {
|
| |
+ if (rpmdsIsRich(ds2)) {
|
| |
+ /* check if this is a IF...ELSE combination */
|
| |
+ @@ -683,7 +773,7 @@ retry:
|
| |
+ }
|
| |
+
|
| |
+ /* See if the rpmdb provides it */
|
| |
+ - if (rpmdbProvides(ts, dcache, dep) == 0)
|
| |
+ + if (rpmdbProvides(ts, dcache, dep, NULL) == 0)
|
| |
+ goto exit;
|
| |
+
|
| |
+ /* Search for an unsatisfied dependency. */
|
| |
+ diff --git a/lib/rpmds.c b/lib/rpmds.c
|
| |
+ index ba6e24448..be788d7e2 100644
|
| |
+ --- a/lib/rpmds.c
|
| |
+ +++ b/lib/rpmds.c
|
| |
+ @@ -1354,10 +1354,12 @@ static struct RichOpComp {
|
| |
+ const char * token;
|
| |
+ rpmrichOp op;
|
| |
+ } const RichOps[] = {
|
| |
+ - { "and", RPMRICHOP_AND},
|
| |
+ - { "or", RPMRICHOP_OR},
|
| |
+ - { "if", RPMRICHOP_IF},
|
| |
+ - { "else", RPMRICHOP_ELSE},
|
| |
+ + { "and", RPMRICHOP_AND},
|
| |
+ + { "or", RPMRICHOP_OR},
|
| |
+ + { "if", RPMRICHOP_IF},
|
| |
+ + { "else", RPMRICHOP_ELSE},
|
| |
+ + { "with", RPMRICHOP_WITH},
|
| |
+ + { "without", RPMRICHOP_WITHOUT},
|
| |
+ { NULL, 0 },
|
| |
+ };
|
| |
+
|
| |
+ @@ -1397,6 +1399,10 @@ const char *rpmrichOpStr(rpmrichOp op)
|
| |
+ return "if";
|
| |
+ if (op == RPMRICHOP_ELSE)
|
| |
+ return "else";
|
| |
+ + if (op == RPMRICHOP_WITH)
|
| |
+ + return "with";
|
| |
+ + if (op == RPMRICHOP_WITHOUT)
|
| |
+ + return "without";
|
| |
+ return NULL;
|
| |
+ }
|
| |
+
|
| |
+ @@ -1444,10 +1450,11 @@ static rpmRC parseSimpleDep(const char **dstrp, char **emsg, rpmrichParseFunctio
|
| |
+ return RPMRC_OK;
|
| |
+ }
|
| |
+
|
| |
+ -rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
|
| |
+ +static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, int *nowithp)
|
| |
+ {
|
| |
+ const char *p = *dstrp, *pe;
|
| |
+ rpmrichOp op = RPMRICHOP_SINGLE, chainop = 0;
|
| |
+ + int nowith = 0;
|
| |
+
|
| |
+ if (cb(cbdata, RPMRICH_PARSE_ENTER, p, 0, 0, 0, 0, op, emsg) != RPMRC_OK)
|
| |
+ return RPMRC_FAIL;
|
| |
+ @@ -1468,7 +1475,7 @@ rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, voi
|
| |
+ return RPMRC_FAIL;
|
| |
+ }
|
| |
+ if (*p == '(') {
|
| |
+ - if (rpmrichParse(&p, emsg, cb, cbdata) != RPMRC_OK)
|
| |
+ + if (rpmrichParseInternal(&p, emsg, cb, cbdata, &nowith) != RPMRC_OK)
|
| |
+ return RPMRC_FAIL;
|
| |
+ } else {
|
| |
+ if (parseSimpleDep(&p, emsg, cb, cbdata) != RPMRC_OK)
|
| |
+ @@ -1492,15 +1499,23 @@ rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, voi
|
| |
+ rasprintf(emsg, _("Cannot chain different ops"));
|
| |
+ return RPMRC_FAIL;
|
| |
+ }
|
| |
+ - if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR) {
|
| |
+ + if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR &&
|
| |
+ + op != RPMRICHOP_WITH) {
|
| |
+ if (emsg)
|
| |
+ - rasprintf(emsg, _("Can only chain AND and OR ops"));
|
| |
+ + rasprintf(emsg, _("Can only chain and/or/with ops"));
|
| |
+ return RPMRC_FAIL;
|
| |
+ }
|
| |
+ if (cb(cbdata, RPMRICH_PARSE_OP, p, pe - p, 0, 0, 0, op, emsg) != RPMRC_OK)
|
| |
+ return RPMRC_FAIL;
|
| |
+ chainop = op;
|
| |
+ p = pe;
|
| |
+ + if (nowithp && op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT && op != RPMRICHOP_OR)
|
| |
+ + *nowithp = 1;
|
| |
+ + }
|
| |
+ + if ((op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) && nowith) {
|
| |
+ + if (emsg)
|
| |
+ + rasprintf(emsg, _("Illegal ops in with/without"));
|
| |
+ + return RPMRC_FAIL;
|
| |
+ }
|
| |
+ p++;
|
| |
+ if (cb(cbdata, RPMRICH_PARSE_LEAVE, *dstrp, p - *dstrp , 0, 0, 0, op, emsg) != RPMRC_OK)
|
| |
+ @@ -1509,6 +1524,10 @@ rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, voi
|
| |
+ return RPMRC_OK;
|
| |
+ }
|
| |
+
|
| |
+ +rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)
|
| |
+ +{
|
| |
+ + return rpmrichParseInternal(dstrp, emsg, cb, cbdata, NULL);
|
| |
+ +}
|
| |
+
|
| |
+ struct rpmdsParseRichDepData {
|
| |
+ rpmds dep;
|
| |
+ diff --git a/lib/rpmds.h b/lib/rpmds.h
|
| |
+ index a113609ae..8f1c0c3ef 100644
|
| |
+ --- a/lib/rpmds.h
|
| |
+ +++ b/lib/rpmds.h
|
| |
+ @@ -464,11 +464,13 @@ int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp);
|
| |
+
|
| |
+
|
| |
+ typedef enum rpmrichOp_e {
|
| |
+ - RPMRICHOP_SINGLE = 1,
|
| |
+ - RPMRICHOP_AND = 2,
|
| |
+ - RPMRICHOP_OR = 3,
|
| |
+ - RPMRICHOP_IF = 4,
|
| |
+ - RPMRICHOP_ELSE = 5
|
| |
+ + RPMRICHOP_SINGLE = 1,
|
| |
+ + RPMRICHOP_AND = 2,
|
| |
+ + RPMRICHOP_OR = 3,
|
| |
+ + RPMRICHOP_IF = 4,
|
| |
+ + RPMRICHOP_ELSE = 5,
|
| |
+ + RPMRICHOP_WITH = 6,
|
| |
+ + RPMRICHOP_WITHOUT = 7
|
| |
+ } rpmrichOp;
|
| |
+
|
| |
+ typedef enum rpmrichParseType_e {
|
| |
Signed-off-by: Igor Gnatenko ignatenkobrain@fedoraproject.org