6be20da468
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.
815 lines
22 KiB
C
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:
|