rpm-build/build/interdep.c
Ivan Zakharyaschev 6be20da468 headerNVR() replaced by the new header{NVRD,Name{,Version}}() in trivial cases
These are the cases where even the release was not needed (so, the
disttag is not needed, too), or one case where the filename is
contructed (and it doesn't include the disttag).

Now grep -Ee 'headerNVR[^D]' will show the remaining non-trivial
cases, where adapting to disttags may be needed.
2019-02-26 23:16:13 +03:00

815 lines
22 KiB
C

/*
* interdep.c - inter-package analysis and optimizations based on
* strict dependencies between subpackages (Requires: N = [E:]V-R[:D]).
*
* Written by Alexey Tourbin <at@altlinux.org>.
* License: GPLv2+.
*/
#include "system.h"
#include "psm.h" // TFI_t
#include "rpmbuild.h"
#include "interdep.h"
static
const char *pkgName(Package pkg)
{
TFI_t fi = pkg->cpioList;
if (fi)
return fi->name;
const char *name;
headerName(pkg->header, &name);
return name;
}
static
const char *skipPrefixDash(const char *str, const char *prefix)
{
int len = strlen(prefix);
if (strncmp(str, prefix, len))
return NULL;
if (str[len] != '-')
return NULL;
return str + len + 1;
}
struct Req {
int c;
struct Pair {
Package pkg1;
Package pkg2;
} *v;
};
static
int Requires(struct Req *r, Package pkg1, Package pkg2)
{
int i;
for (i = 0; i < r->c; i++)
if (pkg1 == r->v[i].pkg1 && pkg2 == r->v[i].pkg2)
return 1;
return 0;
}
static
int addRequires(struct Req *r, Package pkg1, Package pkg2)
{
if (pkg1 == pkg2)
return 0;
if (Requires(r, pkg1, pkg2))
return 0;
AUTO_REALLOC(r->v, r->c, 8);
r->v[r->c++] = (struct Pair) { pkg1, pkg2 };
return 1;
}
static void
propagateRequires(struct Req *r)
{
unsigned propagated;
do {
propagated = 0;
int i1, i2;
for (i1 = 0; i1 < r->c; i1++)
for (i2 = i1; i2 < r->c; i2++) {
struct Pair r1 = r->v[i1];
struct Pair r2 = r->v[i2];
if (r1.pkg2 == r2.pkg1 && addRequires(r, r1.pkg1, r2.pkg2))
propagated = 1;
if (r2.pkg2 == r1.pkg1 && addRequires(r, r2.pkg1, r1.pkg2))
propagated = 1;
}
}
while (propagated);
}
static void
addDeps1(struct Req *r, Package pkg1, Package pkg2)
{
const char *name = pkgName(pkg2);
const char *evrd = headerSprintf(pkg2->header,
"%|epoch?{%{epoch}:}|%{version}-%{release}%|disttag?{:%{disttag}}|",
rpmTagTable, rpmHeaderFormats, NULL);
assert(evrd);
int flags = RPMSENSE_EQUAL | RPMSENSE_FIND_REQUIRES;
int added = !addReqProv(NULL, pkg1->header, flags, name, evrd, 0);
if (added) {
if (addRequires(r, pkg1, pkg2))
propagateRequires(r);
rpmMessage(RPMMESS_NORMAL, "Adding to %s a strict dependency on %s\n",
pkgName(pkg1), pkgName(pkg2));
}
evrd = _free(evrd);
}
static
void makeReq1(struct Req *r, Package pkg1, Package pkg2, int warn)
{
int c = 0;
const char **reqNv = NULL;
const char **reqVv = NULL;
const int *reqFv = NULL;
const HGE_t hge = (HGE_t)headerGetEntryMinMemory;
int ok =
hge(pkg1->header, RPMTAG_REQUIRENAME, NULL, (void **) &reqNv, &c) &&
hge(pkg1->header, RPMTAG_REQUIREVERSION, NULL, (void **) &reqVv, NULL) &&
hge(pkg1->header, RPMTAG_REQUIREFLAGS, NULL, (void **) &reqFv, NULL);
if (!ok)
return;
const char *provN, *provV, *provR, *provD;
headerNVRD(pkg2->header, &provN, &provV, &provR, &provD);
int i;
for (i = 0; i < c; i++) {
if (strcmp(reqNv[i], provN))
continue;
if ((reqFv[i] & RPMSENSE_SENSEMASK) != RPMSENSE_EQUAL)
continue;
const char *reqVR = reqVv[i];
if (*reqVR == '\0')
continue;
const char *colon = NULL;
const char *reqR = skipPrefixDash(reqVR, provV);
if (reqR == NULL && xisdigit(*reqVR)) {
colon = strchr(reqVR, ':');
if (colon) {
/* reqVR contains an epoch */
reqR = skipPrefixDash(colon + 1, provV);
}
}
if (reqR == NULL)
continue;
const char *reqD = NULL;
if (strcmp(reqR, provR)) {
/* Check whether reqR contains a disttag. */
reqD = strchr(reqR, ':');
if (!reqD)
continue;
if (strncmp(provR, reqR, reqD - reqR)
|| provR[reqD - reqR])
continue;
reqD++;
if (provD && strcmp(provD, reqD))
continue;
}
if (warn && colon == NULL && headerIsEntry(pkg2->header, RPMTAG_EPOCH)) {
rpmMessage(RPMMESS_WARNING, "%s: dependency on %s needs Epoch\n",
pkgName(pkg1), pkgName(pkg2));
addDeps1(r, pkg1, pkg2);
} else if (warn && provD && !reqD) {
rpmMessage(RPMMESS_DEBUG, "%s: dependency on %s needs disttag\n",
pkgName(pkg1), pkgName(pkg2));
addDeps1(r, pkg1, pkg2);
} else {
addRequires(r, pkg1, pkg2);
}
break;
}
const HFD_t hfd = (HFD_t) headerFreeData;
reqNv = hfd(reqNv, RPM_STRING_ARRAY_TYPE);
reqVv = hfd(reqVv, RPM_STRING_ARRAY_TYPE);
}
#include "al.h"
// check if pkg1 has (possibly non-strict) dependency on pkg2
static
int depRequires(Package pkg1, Package pkg2)
{
if (pkg1 == pkg2)
return 0;
int reqc = 0;
const char **reqNv = NULL;
const char **reqVv = NULL;
const int *reqFv = NULL;
const HGE_t hge = (HGE_t) headerGetEntryMinMemory;
int ok =
hge(pkg1->header, RPMTAG_REQUIRENAME, NULL, (void **) &reqNv, &reqc) &&
hge(pkg1->header, RPMTAG_REQUIREVERSION, NULL, (void **) &reqVv, NULL) &&
hge(pkg1->header, RPMTAG_REQUIREFLAGS, NULL, (void **) &reqFv, NULL);
if (!ok)
return 0;
struct availableList_s proval;
alCreate(&proval);
alAddPackage(&proval, pkg2->header, NULL, NULL, NULL);
int i;
struct availablePackage *ap = NULL;
for (i = 0; i < reqc; i++) {
ap = alSatisfiesDepend(&proval, reqNv[i], reqVv[i], reqFv[i]);
if (ap)
break;
}
const HFD_t hfd = (HFD_t) headerFreeData;
reqNv = hfd(reqNv, RPM_STRING_ARRAY_TYPE);
reqVv = hfd(reqVv, RPM_STRING_ARRAY_TYPE);
alFree(&proval);
return ap ? 1 : 0;
}
static
struct Req *freeRequires(struct Req *r)
{
r->v = _free(r->v);
return _free(r);
}
/*
* For every subpackage pkg2 in the set, pkg1 will get a strict dep
* on pkg2 if at least one of these conditions is met:
* - pkg1 has a RPMSENSE_FIND_REQUIRES dep on pkg2;
* - pkg1 has a manual dep on pkg2 and
* this dep has no ~RPMSENSE_EQUAL sense flags;
* - pkg1 has a RPMSENSE_FIND_REQUIRES dep on X, and
* pkg2 is the only subpackage in the set that satisfies X.
*/
static void
fix_weak_deps(struct Req *r, Package pkg1, Package packages)
{
int reqc = 0;
const char **reqNv = NULL;
const char **reqVv = NULL;
const int *reqFv = NULL;
const HGE_t hge = (HGE_t) headerGetEntryMinMemory;
int ok =
hge(pkg1->header, RPMTAG_REQUIRENAME, NULL, (void **) &reqNv, &reqc) &&
hge(pkg1->header, RPMTAG_REQUIREVERSION, NULL, (void **) &reqVv, NULL) &&
hge(pkg1->header, RPMTAG_REQUIREFLAGS, NULL, (void **) &reqFv, NULL);
if (!ok)
return;
int i;
Package pkg2;
for (i = 0, pkg2 = packages; pkg2; ++i, pkg2 = pkg2->next)
;;
Package *provs = xcalloc(i, sizeof(*provs));
availableList proval = xcalloc(i, sizeof(*proval));
for (i = 0, pkg2 = packages; pkg2; ++i, pkg2 = pkg2->next) {
if (pkg1 != pkg2 && pkg2->cpioList) {
alCreate(&proval[i]);
alAddPackage(&proval[i], pkg2->header, NULL, NULL, NULL);
}
}
for (i = 0; i < reqc; ++i) {
if (reqFv[i] & RPMSENSE_SENSEMASK & ~RPMSENSE_EQUAL &&
!(reqFv[i] & RPMSENSE_FIND_REQUIRES))
continue;
int j;
for (j = 0, pkg2 = packages; pkg2; ++j, pkg2 = pkg2->next) {
if (pkg1 != pkg2 && pkg2->cpioList && !strcmp(reqNv[i], pkgName(pkg2))) {
provs[j] = pkg2;
break;
}
}
int k;
Package prov = NULL;
for (j = 0, pkg2 = packages; pkg2; ++j, pkg2 = pkg2->next) {
if (pkg1 != pkg2 && pkg2->cpioList) {
if (alSatisfiesDepend(&proval[j], reqNv[i], reqVv[i], reqFv[i])) {
if (prov) {
prov = NULL;
break;
}
prov = pkg2;
k = j;
}
}
}
if (prov && reqFv[i] & RPMSENSE_FIND_REQUIRES)
provs[k] = prov;
}
for (i = 0, pkg2 = packages; pkg2; ++i, pkg2 = pkg2->next) {
if (pkg1 != pkg2 && pkg2->cpioList)
alFree(&proval[i]);
}
proval = _free(proval);
const HFD_t hfd = (HFD_t) headerFreeData;
reqNv = hfd(reqNv, RPM_STRING_ARRAY_TYPE);
reqVv = hfd(reqVv, RPM_STRING_ARRAY_TYPE);
for (i = 0, pkg2 = packages; pkg2; ++i, pkg2 = pkg2->next) {
if (provs[i])
addDeps1(r, pkg1, provs[i]);
}
provs = _free(provs);
}
static
struct Req *makeRequires(Spec spec, int warn)
{
struct Req *r = xcalloc(1, sizeof *r);
Package pkg1, pkg2;
for (pkg1 = spec->packages; pkg1; pkg1 = pkg1->next) {
if (!pkg1->cpioList)
continue;
for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) {
if (!pkg2->cpioList)
continue;
makeReq1(r, pkg1, pkg2, warn & 1);
makeReq1(r, pkg2, pkg1, warn & 1);
}
}
propagateRequires(r);
for (pkg1 = spec->packages; pkg1; pkg1 = pkg1->next) {
if (!pkg1->cpioList)
continue;
fix_weak_deps(r, pkg1, spec->packages);
}
if ((warn & 2) == 0)
return r;
for (pkg1 = spec->packages; pkg1; pkg1 = pkg1->next) {
if (!pkg1->cpioList)
continue;
for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) {
if (!pkg2->cpioList)
continue;
if (!Requires(r, pkg1, pkg2) && depRequires(pkg1, pkg2))
rpmMessage(RPMMESS_WARNING, "%s: non-strict dependency on %s\n",
pkgName(pkg1), pkgName(pkg2));
if (!Requires(r, pkg2, pkg1) && depRequires(pkg2, pkg1))
rpmMessage(RPMMESS_WARNING, "%s: non-strict dependency on %s\n",
pkgName(pkg2), pkgName(pkg1));
}
}
return r;
}
#include "checkFiles.h" // fiIntersect
static
void fiPrune(TFI_t fi, char pruned[])
{
int *dil_;
const char **bnl, **dnl;
int bnc, dnc, dic;
int ok =
fi->hge(fi->h, RPMTAG_BASENAMES, NULL, (void **) &bnl, &bnc) &&
fi->hge(fi->h, RPMTAG_DIRNAMES, NULL, (void **) &dnl, &dnc) &&
fi->hge(fi->h, RPMTAG_DIRINDEXES, NULL, (void **) &dil_, &dic);
assert(ok);
assert(fi->fc == bnc);
assert(bnc == dic);
int i, j, k;
// dil must be copied, cf. relocateFileList
int dil[dic];
for (i = 0; i < dic; i++)
dil[i] = dil_[i];
// mark used dirnames
int dirused[dnc];
bzero(dirused, dnc * sizeof *dirused);
for (i = 0; i < bnc; i++)
if (!pruned[i])
dirused[dil[i]]++;
int propagated;
do {
propagated = 0;
// for each unused dirname
for (i = 0; i < dnc; i++) {
if (dirused[i])
continue;
// find its corresponding parent_dir+name entry
for (j = 0; j < bnc; j++) {
if (pruned[j])
continue;
const char *D = dnl[i];
const char *d = dnl[dil[j]];
int dlen = strlen(d);
if (strncmp(D, d, dlen))
continue;
const char *b = bnl[j];
int blen = strlen(b);
if (strncmp(D + dlen, b, blen))
continue;
if (strncmp(D + dlen + blen, "/", 2))
continue;
// makr parent_dir+name for removal
rpmMessage(RPMMESS_NORMAL, "also prunning dir %s%s\n", d, b);
pruned[j] = 1;
// decrement parent_dir usage
if (--dirused[dil[j]] == 0)
propagated++;
}
}
}
while (propagated);
// new count for bnc-like values
int oldc = bnc;
int newc = 0;
for (i = 0; i < oldc; i++)
if (!pruned[i])
newc++;
// establish new dirnames and dirindexes
for (i = 0, j = 0; i < dnc; i++) {
if (!dirused[i])
continue;
if (i == j)
goto skip;
dnl[j] = dnl[i];
for (k = 0; k < dic; k++)
if (dil[k] == i)
dil[k] = j;
skip:
j++;
}
dnc = j;
// handle bnl, dnl and dil
#define PruneV(v) \
for (i = 0, j = 0; i < oldc; i++) \
if (!pruned[i]) \
v[j++] = v[i]
PruneV(bnl);
PruneV(dil);
PruneV(fi->bnl);
PruneV(fi->dil);
fi->hme(fi->h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE, bnl, newc);
fi->hme(fi->h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE, dnl, dnc);
fi->hme(fi->h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE, dil, newc);
bnl = fi->hfd(bnl, RPM_STRING_ARRAY_TYPE);
dnl = fi->hfd(dnl, RPM_STRING_ARRAY_TYPE);
// prune header tags
rpmTagType tagt;
int tagc;
const char **strv;
#define PruneStrTag(tag) \
if (fi->hge(fi->h, tag, &tagt, (void **) &strv, &tagc)) { \
assert(tagt == RPM_STRING_ARRAY_TYPE); \
assert(tagc == oldc); \
PruneV(strv); \
fi->hme(fi->h, tag, RPM_STRING_ARRAY_TYPE, strv, newc); \
fi->hfd(strv, RPM_STRING_ARRAY_TYPE); \
}
short *INT16p, INT16v[oldc];
int *INT32p, INT32v[oldc];
#define PruneIntTag(INT, tag) \
if (fi->hge(fi->h, tag, &tagt, (void **) &INT ## p, &tagc)) { \
assert(tagt == RPM_ ## INT ## _TYPE); \
assert(tagc == oldc); \
for (i = 0; i < oldc; i++) \
INT ## v[i] = INT ## p[i]; \
PruneV(INT ## v); \
fi->hme(fi->h, tag, RPM_ ## INT ##_TYPE, INT ## v, newc); \
}
#define PruneI16Tag(tag) PruneIntTag(INT16, tag)
#define PruneI32Tag(tag) PruneIntTag(INT32, tag)
PruneI32Tag(RPMTAG_FILESIZES);
PruneStrTag(RPMTAG_FILEUSERNAME);
PruneStrTag(RPMTAG_FILEGROUPNAME);
PruneI32Tag(RPMTAG_FILEMTIMES);
PruneI16Tag(RPMTAG_FILEMODES);
PruneI16Tag(RPMTAG_FILERDEVS);
PruneI32Tag(RPMTAG_FILEDEVICES);
PruneI32Tag(RPMTAG_FILEINODES);
PruneStrTag(RPMTAG_FILELANGS);
PruneStrTag(RPMTAG_FILEMD5S);
PruneStrTag(RPMTAG_FILELINKTOS);
PruneI32Tag(RPMTAG_FILEVERIFYFLAGS);
PruneI32Tag(RPMTAG_FILEFLAGS);
// update fi, cf. genCpioListAndHeader
PruneV(fi->apath);
PruneV(fi->actions);
PruneV(fi->fmapflags);
PruneV(fi->fuids);
PruneV(fi->fgids);
PruneV(fi->fsts);
struct transactionFileInfo_s save_fi;
#define MV(a) save_fi.a = fi->a; fi->a = NULL
MV(bnl); MV(dnl); MV(dil);
MV(apath); MV(actions); MV(fmapflags); MV(fuids); MV(fgids); MV(fsts);
save_fi.h = fi->h;
save_fi.astriplen = fi->astriplen;
freeFi(fi);
bzero(fi, sizeof *fi);
fi->type = TR_ADDED;
loadFi(save_fi.h, fi);
assert(fi->fc == newc);
fi->dnl = _free(fi->dnl);
fi->bnl = _free(fi->bnl);
#undef MV
#define MV(a) fi->a = save_fi.a
MV(bnl); MV(dnl); MV(dil);
MV(apath); MV(actions); MV(fmapflags); MV(fuids); MV(fgids); MV(fsts);
fi->astriplen = save_fi.astriplen;
}
static
void fiIntersect_cb(const TFI_t fi1, const TFI_t fi2, const char *f,
int i1, int i2, void *data)
{
(void) fi2;
(void) i2;
if (S_ISDIR(fi1->fmodes[i1]))
return;
const char src[] = "/usr/src/debug/";
if (strncmp(f, src, sizeof(src) - 1))
return;
struct {
unsigned int n;
char list[fi1->fc];
} *pruned = data;
pruned->list[i1] = 1;
pruned->n++;
}
// prune src dups from pkg1 and add dependency on pkg2
static
void pruneSrc1(struct Req *r, Package pkg1, Package pkg2)
{
TFI_t fi1 = pkg1->cpioList;
const TFI_t fi2 = pkg2->cpioList;
if (!fi1 || !fi2) return;
struct {
unsigned int n;
char list[fi1->fc];
} pruned;
bzero(&pruned, sizeof(pruned));
fiIntersect(fi1, fi2, fiIntersect_cb, &pruned);
if (pruned.n == 0)
return;
addDeps1(r, pkg1, pkg2);
rpmMessage(RPMMESS_NORMAL, "Removing from %s %d sources provided by %s\n",
pkgName(pkg1), pruned.n, pkgName(pkg2));
fiPrune(fi1, pruned.list);
}
static void
processDependentDebuginfo(struct Req *r, Spec spec,
void (*cb)(struct Req *r, Package pkg1, Package pkg2), int mutual)
{
int i1, i2;
struct Pair r1, r2;
const char *Nd, *Np;
const char *suf;
// r1 = { pkg1-debuginfo, pkg1 }
for (i1 = 0; i1 < r->c; i1++) {
r1 = r->v[i1];
Nd = pkgName(r1.pkg1);
Np = pkgName(r1.pkg2);
suf = skipPrefixDash(Nd, Np);
if (suf == NULL || strcmp(suf, "debuginfo"))
continue;
// r2 = { pkg2-debuginfo, pkg2 }
for (i2 = i1; i2 < r->c; i2++) {
r2 = r->v[i2];
Nd = pkgName(r2.pkg1);
Np = pkgName(r2.pkg2);
suf = skipPrefixDash(Nd, Np);
if (suf == NULL || strcmp(suf, "debuginfo"))
continue;
// (pkg1 <-> pkg2) => (pkg1-debuginfo <-> pkg2-debuginfo)
if (Requires(r, r1.pkg2, r2.pkg2)) {
cb(r, r1.pkg1, r2.pkg1);
if (!mutual)
continue;
}
if (Requires(r, r2.pkg2, r1.pkg2))
cb(r, r2.pkg1, r1.pkg1);
}
}
}
static
void pruneDebuginfoSrc(struct Req *r, Spec spec)
{
processDependentDebuginfo(r, spec, pruneSrc1, 0);
}
// if pkg1 implicitly requires pkg2, add strict dependency
static void
liftDeps1(struct Req *r, Package pkg1, Package pkg2)
{
if (!Requires(r, pkg1, pkg2) && depRequires(pkg1, pkg2))
addDeps1(r, pkg1, pkg2);
}
static
void liftDebuginfoDeps(struct Req *r, Spec spec)
{
processDependentDebuginfo(r, spec, liftDeps1, 1);
}
// assuming pkg1 has strict dependency on pkg2, prune deps provided by pkg2
static
void pruneDeps1(Package pkg1, Package pkg2)
{
TFI_t fi = pkg1->cpioList;
if (fi == NULL)
return;
int reqc = 0;
const char **reqNv = NULL;
const char **reqVv = NULL;
const int *reqFv_ = NULL;
int ok =
fi->hge(pkg1->header, RPMTAG_REQUIRENAME, NULL, (void **) &reqNv, &reqc) &&
fi->hge(pkg1->header, RPMTAG_REQUIREVERSION, NULL, (void **) &reqVv, NULL) &&
fi->hge(pkg1->header, RPMTAG_REQUIREFLAGS, NULL, (void **) &reqFv_, NULL);
if (!ok)
return;
assert(reqc > 0);
int i, j;
int reqFv[reqc];
for (i = 0; i < reqc; i++)
reqFv[i] = reqFv_[i];
struct availableList_s proval;
alCreate(&proval);
alAddPackage(&proval, pkg2->header, NULL, NULL, NULL);
int flags = 0, *flagsp = NULL;
struct availablePackage *ap = NULL;
int rpmlibSetVersions = -1;
int hasSetVersions = 0;
int npruned = 0;
char pruned[reqc];
bzero(pruned, reqc);
for (i = 0; i < reqc; i++) {
if ((reqFv[i] & RPMSENSE_SENSEMASK) == RPMSENSE_EQUAL &&
strcmp(reqNv[i], pkgName(pkg2)) == 0)
{
if (flagsp == NULL)
flagsp = &reqFv[i];
continue;
}
if ((reqFv[i] & RPMSENSE_RPMLIB) &&
strcmp(reqNv[i], "rpmlib(SetVersions)") == 0)
{
if (rpmlibSetVersions == -1)
rpmlibSetVersions = i;
continue;
}
ap = alSatisfiesDepend(&proval, reqNv[i], reqVv[i], reqFv[i]);
if (ap == NULL) {
if ((reqFv[i] & RPMSENSE_SENSEMASK))
if (strncmp(reqVv[i], "set:", 4) == 0)
hasSetVersions++;
continue;
}
pruned[i] = 1;
npruned++;
flags |= reqFv[i];
}
alFree(&proval);
if (npruned == 0) {
reqNv = fi->hfd(reqNv, RPM_STRING_ARRAY_TYPE);
reqVv = fi->hfd(reqVv, RPM_STRING_ARRAY_TYPE);
return;
}
if (hasSetVersions == 0 && rpmlibSetVersions >= 0) {
pruned[rpmlibSetVersions] = 1;
npruned++;
}
rpmMessage(RPMMESS_NORMAL,
"Removing %d extra deps from %s due to dependency on %s\n",
npruned, pkgName(pkg1), pkgName(pkg2));
if (flagsp)
*flagsp |= (flags & RPMSENSE_PREREQ);
for (i = 0, j = 0; i < reqc; i++) {
if (pruned[i])
continue;
if (i == j)
goto skip;
reqNv[j] = reqNv[i];
reqVv[j] = reqVv[i];
reqFv[j] = reqFv[i];
skip:
j++;
}
reqc = j;
fi->hme(fi->h, RPMTAG_REQUIRENAME, RPM_STRING_ARRAY_TYPE, reqNv, reqc);
fi->hme(fi->h, RPMTAG_REQUIREVERSION, RPM_STRING_ARRAY_TYPE, reqVv, reqc);
fi->hme(fi->h, RPMTAG_REQUIREFLAGS, RPM_INT32_TYPE, reqFv, reqc);
reqNv = fi->hfd(reqNv, RPM_STRING_ARRAY_TYPE);
reqVv = fi->hfd(reqVv, RPM_STRING_ARRAY_TYPE);
}
static
void pruneExtraDeps(struct Req *r, Spec spec)
{
int i;
for (i = 0; i < r->c; i++)
pruneDeps1(r->v[i].pkg1, r->v[i].pkg2);
}
// assuming pkg1 has strict dependency on pkg2, prune deps required by pkg2
static
void pruneRDeps1(struct Req *r, Spec spec, Package pkg1, Package pkg2)
{
TFI_t fi = pkg1->cpioList;
if (fi == NULL)
return;
int reqc = 0;
const char **reqNv = NULL;
const char **reqVv = NULL;
const int *reqFv_ = NULL;
int ok =
fi->hge(fi->h, RPMTAG_REQUIRENAME, NULL, (void **) &reqNv, &reqc) &&
fi->hge(fi->h, RPMTAG_REQUIREVERSION, NULL, (void **) &reqVv, NULL) &&
fi->hge(fi->h, RPMTAG_REQUIREFLAGS, NULL, (void **) &reqFv_, NULL);
if (!ok)
return;
int i, j;
int reqFv[reqc];
for (i = 0; i < reqc; i++)
reqFv[i] = reqFv_[i];
int provc = 0;
const char **provNv = NULL;
const char **provVv = NULL;
const int *provFv = NULL;
const HGE_t hge = (HGE_t) headerGetEntryMinMemory;
const HFD_t hfd = (HFD_t) headerFreeData;
ok =
hge(pkg2->header, RPMTAG_REQUIRENAME, NULL, (void **) &provNv, &provc) &&
hge(pkg2->header, RPMTAG_REQUIREVERSION, NULL, (void **) &provVv, NULL) &&
hge(pkg2->header, RPMTAG_REQUIREFLAGS, NULL, (void **) &provFv, NULL);
if (!ok) {
reqNv = fi->hfd(reqNv, RPM_STRING_ARRAY_TYPE);
reqVv = fi->hfd(reqVv, RPM_STRING_ARRAY_TYPE);
return;
}
int npruned = 0;
char pruned[reqc];
bzero(pruned, reqc);
// check if pkg2 is part of a cycle
int cycle = 0;
Package pkg3;
for (pkg3 = spec->packages; pkg3; pkg3 = pkg3->next) {
if (pkg3 == pkg1 || pkg3 == pkg2)
continue;
if (Requires(r, pkg2, pkg3) && Requires(r, pkg3, pkg2)) {
cycle = 1;
break;
}
}
for (i = 0; i < reqc; i++)
for (j = 0; j < provc; j++) {
if (strcmp(reqNv[i], provNv[j]))
continue;
if (cycle && (reqFv[i] & RPMSENSE_SENSEMASK) == RPMSENSE_EQUAL)
continue;
dep_compare_t cmp = compare_deps(RPMTAG_REQUIRENAME,
provVv[j], provFv[j], reqVv[i], reqFv[i]);
if (!(cmp == DEP_ST || cmp == DEP_EQ))
continue;
pruned[i] = 1;
npruned++;
}
if (npruned == 0)
goto free;
rpmMessage(RPMMESS_NORMAL,
"Removing %d extra deps from %s due to repentancy on %s\n",
npruned, pkgName(pkg1), pkgName(pkg2));
for (i = 0, j = 0; i < reqc; i++) {
if (pruned[i])
continue;
if (i == j)
goto skip;
reqNv[j] = reqNv[i];
reqVv[j] = reqVv[i];
reqFv[j] = reqFv[i];
skip:
j++;
}
reqc = j;
fi->hme(fi->h, RPMTAG_REQUIRENAME, RPM_STRING_ARRAY_TYPE, reqNv, reqc);
fi->hme(fi->h, RPMTAG_REQUIREVERSION, RPM_STRING_ARRAY_TYPE, reqVv, reqc);
fi->hme(fi->h, RPMTAG_REQUIREFLAGS, RPM_INT32_TYPE, reqFv, reqc);
free:
reqNv = fi->hfd(reqNv, RPM_STRING_ARRAY_TYPE);
reqVv = fi->hfd(reqVv, RPM_STRING_ARRAY_TYPE);
provNv = hfd(provNv, RPM_STRING_ARRAY_TYPE);
provVv = hfd(provVv, RPM_STRING_ARRAY_TYPE);
}
static
void pruneExtraRDeps(struct Req *r, Spec spec)
{
Package pkg1, pkg2;
for (pkg1 = spec->packages; pkg1; pkg1 = pkg1->next) {
if (!pkg1->cpioList)
continue;
for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) {
if (!pkg2->cpioList)
continue;
if (Requires(r, pkg1, pkg2))
pruneRDeps1(r, spec, pkg1, pkg2);
// "else" guards against mutual deletions
else if (Requires(r, pkg2, pkg1))
pruneRDeps1(r, spec, pkg2, pkg1);
}
}
}
int processInterdep(Spec spec)
{
struct Req *r;
int optlevel = rpmExpandNumeric("%{?_deps_optimization}%{?!_deps_optimization:3}");
if (optlevel >= 1) {
r = makeRequires(spec, 1);
pruneDebuginfoSrc(r, spec);
liftDebuginfoDeps(r, spec);
r = freeRequires(r);
}
if (optlevel >= 3) {
r = makeRequires(spec, 2);
pruneExtraDeps(r, spec);
pruneExtraRDeps(r, spec);
r = freeRequires(r);
}
return 0;
}
// ex: set ts=8 sts=4 sw=4 noet: