Dmitry V. Levin
0358825884
The check for cycles introduced in 4.0.4-alt100.17-6-ga71e004 appeared to be incomplete. For example, it fails to recognize a cycle in the following example: %package -n test Requires: libtest = %version-%release %package -n libtest Requires: libtest-common = %version-%release %package -n libtest-common Requires: libtest = %version-%release
687 lines
19 KiB
C
687 lines
19 KiB
C
/*
|
|
* interdep.c - inter-package analysis and optimizations based on
|
|
* strict dependencies between subpackages (Requires: N = [E:]V-R).
|
|
*
|
|
* 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;
|
|
headerNVR(pkg->header, &name, NULL, NULL);
|
|
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
|
|
void addRequires(struct Req *r, Package pkg1, Package pkg2)
|
|
{
|
|
if (pkg1 == pkg2)
|
|
return;
|
|
if (Requires(r, pkg1, pkg2))
|
|
return;
|
|
AUTO_REALLOC(r->v, r->c, 8);
|
|
r->v[r->c++] = (struct Pair) { pkg1, pkg2 };
|
|
}
|
|
|
|
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;
|
|
headerNVR(pkg2->header, &provN, &provV, &provR);
|
|
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)
|
|
reqR = skipPrefixDash(colon + 1, provV);
|
|
}
|
|
if (reqR == NULL)
|
|
continue;
|
|
if (strcmp(reqR, provR))
|
|
continue;
|
|
addRequires(r, pkg1, pkg2);
|
|
if (warn && colon == NULL && headerIsEntry(pkg2->header, RPMTAG_EPOCH))
|
|
fprintf(stderr, "warning: %s: dependency on %s needs Epoch\n",
|
|
pkgName(pkg1), pkgName(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)
|
|
{
|
|
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;
|
|
availableList proval = alloca(sizeof 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 *makeRequires(Spec spec, int warn)
|
|
{
|
|
struct Req *r = xmalloc(sizeof *r);
|
|
r->c = 0;
|
|
r->v = NULL;
|
|
Package pkg1, pkg2;
|
|
for (pkg1 = spec->packages; pkg1; pkg1 = pkg1->next)
|
|
for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) {
|
|
makeReq1(r, pkg1, pkg2, warn & 1);
|
|
makeReq1(r, pkg2, pkg1, warn & 1);
|
|
}
|
|
int 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 && r1.pkg1 != r2.pkg2 &&
|
|
!Requires(r, r1.pkg1, r2.pkg2))
|
|
{
|
|
addRequires(r, r1.pkg1, r2.pkg2);
|
|
propagated++;
|
|
}
|
|
if (r2.pkg2 == r1.pkg1 && r2.pkg1 != r1.pkg2 &&
|
|
!Requires(r, r2.pkg1, r1.pkg2))
|
|
{
|
|
addRequires(r, r2.pkg1, r1.pkg2);
|
|
propagated++;
|
|
}
|
|
}
|
|
}
|
|
while (propagated);
|
|
if ((warn & 2) == 0)
|
|
return r;
|
|
for (pkg1 = spec->packages; pkg1; pkg1 = pkg1->next)
|
|
for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next) {
|
|
if (!Requires(r, pkg1, pkg2) && depRequires(pkg1, pkg2))
|
|
fprintf(stderr, "warning: %s: non-strict dependency on %s\n",
|
|
pkgName(pkg1), pkgName(pkg2));
|
|
if (!Requires(r, pkg2, pkg1) && depRequires(pkg2, pkg1))
|
|
fprintf(stderr, "warning: %s: non-strict dependency on %s\n",
|
|
pkgName(pkg2), pkgName(pkg1));
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static
|
|
struct Req *freeRequires(struct Req *r)
|
|
{
|
|
r->v = _free(r->v);
|
|
return _free(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
|
|
fprintf(stderr, "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;
|
|
}
|
|
|
|
// prune src dups from pkg1 and add dependency on pkg2
|
|
static
|
|
void pruneSrc1(Package pkg1, Package pkg2)
|
|
{
|
|
TFI_t fi1 = pkg1->cpioList;
|
|
TFI_t fi2 = pkg2->cpioList;
|
|
if (fi1 == NULL) return;
|
|
if (fi2 == NULL) return;
|
|
int npruned = 0;
|
|
char pruned[fi1->fc];
|
|
bzero(pruned, fi1->fc);
|
|
void cb(char *f, int i1, int i2)
|
|
{
|
|
(void) i2;
|
|
if (S_ISDIR(fi1->fmodes[i1]))
|
|
return;
|
|
const char src[] = "/usr/src/debug/";
|
|
if (strncmp(f, src, sizeof(src) - 1))
|
|
return;
|
|
pruned[i1] = 1;
|
|
npruned++;
|
|
}
|
|
fiIntersect(fi1, fi2, cb);
|
|
if (npruned == 0)
|
|
return;
|
|
fprintf(stderr, "removing %d sources from %s and adding dependency on %s\n",
|
|
npruned, pkgName(pkg1), pkgName(pkg2));
|
|
fiPrune(fi1, pruned);
|
|
const char *name = pkgName(pkg2);
|
|
const char *evr = headerSprintf(pkg2->header,
|
|
"%|epoch?{%{epoch}:}|%{version}-%{release}",
|
|
rpmTagTable, rpmHeaderFormats, NULL);
|
|
assert(evr);
|
|
int flags = RPMSENSE_EQUAL | RPMSENSE_FIND_REQUIRES;
|
|
assert(pkg1->header == fi1->h);
|
|
headerAddOrAppendEntry(fi1->h, RPMTAG_REQUIRENAME, RPM_STRING_ARRAY_TYPE, &name, 1);
|
|
headerAddOrAppendEntry(fi1->h, RPMTAG_REQUIREVERSION, RPM_STRING_ARRAY_TYPE, &evr, 1);
|
|
headerAddOrAppendEntry(fi1->h, RPMTAG_REQUIREFLAGS, RPM_INT32_TYPE, &flags, 1);
|
|
evr = _free(evr);
|
|
}
|
|
|
|
static void
|
|
processDependentDebuginfo(struct Req *r, Spec spec,
|
|
void (*cb)(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(r1.pkg1, r2.pkg1);
|
|
if (!mutual)
|
|
continue;
|
|
}
|
|
if (Requires(r, r2.pkg2, r1.pkg2))
|
|
cb(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(Package pkg1, Package pkg2)
|
|
{
|
|
if (!depRequires(pkg1, pkg2))
|
|
return;
|
|
const char *name = pkgName(pkg2);
|
|
const char *evr = headerSprintf(pkg2->header,
|
|
"%|epoch?{%{epoch}:}|%{version}-%{release}",
|
|
rpmTagTable, rpmHeaderFormats, NULL);
|
|
assert(evr);
|
|
int flags = RPMSENSE_EQUAL | RPMSENSE_FIND_REQUIRES;
|
|
if (addReqProv(NULL, pkg1->header, flags, name, evr, 0) == 0)
|
|
fprintf(stderr, "%s: adding strict dependency on %s\n",
|
|
pkgName(pkg1), pkgName(pkg2));
|
|
evr = _free(evr);
|
|
}
|
|
|
|
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];
|
|
availableList proval = alloca(sizeof 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++;
|
|
}
|
|
fprintf(stderr, "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;
|
|
}
|
|
}
|
|
void prune(int i, int j)
|
|
{
|
|
if (strcmp(reqNv[i], provNv[j]))
|
|
return;
|
|
if (cycle && (reqFv[i] & RPMSENSE_SENSEMASK) == RPMSENSE_EQUAL)
|
|
return;
|
|
dep_compare_t cmp = compare_deps(RPMTAG_REQUIRENAME,
|
|
provVv[j], provFv[j], reqVv[i], reqFv[i]);
|
|
if (!(cmp == DEP_ST || cmp == DEP_EQ))
|
|
return;
|
|
pruned[i] = 1;
|
|
npruned++;
|
|
}
|
|
for (i = 0; i < reqc; i++)
|
|
for (j = 0; j < provc; j++)
|
|
prune(i, j);
|
|
if (npruned == 0)
|
|
goto free;
|
|
fprintf(stderr, "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)
|
|
for (pkg2 = pkg1->next; pkg2; pkg2 = pkg2->next)
|
|
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 = makeRequires(spec, 1);
|
|
pruneDebuginfoSrc(r, spec);
|
|
liftDebuginfoDeps(r, spec);
|
|
r = freeRequires(r);
|
|
int optlevel = rpmExpandNumeric("%{?_deps_optimization}%{?!_deps_optimization:2}");
|
|
if (optlevel < 2)
|
|
return 0;
|
|
r = makeRequires(spec, 2);
|
|
pruneExtraDeps(r, spec);
|
|
pruneExtraRDeps(r, spec);
|
|
r = freeRequires(r);
|
|
return 0;
|
|
}
|
|
|
|
// ex: set ts=8 sts=4 sw=4 noet:
|