summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Schroeder <mls@suse.de>2017-08-03 14:06:33 +0200
committerPanu Matilainen <pmatilai@redhat.com>2018-03-28 13:25:23 +0300
commit4b910c2194f5aa3019a438f470e6a6a550ffedcf (patch)
tree3f5940aa42c6efb1261ab9d4cced2893aa7a2876
parentd62f7f03752dfdce925b4fae770cab758cbddf1c (diff)
downloadrpm-4b910c2194f5aa3019a438f470e6a6a550ffedcf.tar.gz
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)
-rw-r--r--lib/depends.c98
-rw-r--r--lib/rpmds.c35
-rw-r--r--lib/rpmds.h12
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 {