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.
This commit is contained in:
parent
87b8b19eba
commit
dac1c70256
|
@ -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. */
|
||||
|
|
27
lib/rpmds.c
27
lib/rpmds.c
|
@ -1381,6 +1381,8 @@ static struct RichOpComp {
|
|||
{ "or", RPMRICHOP_OR},
|
||||
{ "if", RPMRICHOP_IF},
|
||||
{ "else", RPMRICHOP_ELSE},
|
||||
{ "with", RPMRICHOP_WITH},
|
||||
{ "without", RPMRICHOP_WITHOUT},
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
|
@ -1420,6 +1422,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;
|
||||
}
|
||||
|
||||
|
@ -1467,10 +1473,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;
|
||||
|
@ -1491,7 +1498,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)
|
||||
|
@ -1515,15 +1522,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)
|
||||
|
@ -1532,6 +1547,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;
|
||||
|
|
|
@ -459,7 +459,9 @@ typedef enum rpmrichOp_e {
|
|||
RPMRICHOP_AND = 2,
|
||||
RPMRICHOP_OR = 3,
|
||||
RPMRICHOP_IF = 4,
|
||||
RPMRICHOP_ELSE = 5
|
||||
RPMRICHOP_ELSE = 5,
|
||||
RPMRICHOP_WITH = 6,
|
||||
RPMRICHOP_WITHOUT = 7
|
||||
} rpmrichOp;
|
||||
|
||||
typedef enum rpmrichParseType_e {
|
||||
|
|
Loading…
Reference in New Issue