Make rpmal store rpmtes and kill rpmte->pkgKey
This commit is contained in:
parent
85a84fdae7
commit
3e37044eb9
187
lib/depends.c
187
lib/depends.c
|
@ -21,17 +21,6 @@
|
|||
#include "debug.h"
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
typedef struct orderListIndex_s * orderListIndex;
|
||||
|
||||
/**
|
||||
*/
|
||||
struct orderListIndex_s {
|
||||
rpmalKey pkgKey;
|
||||
int orIndex;
|
||||
};
|
||||
|
||||
static int _cacheDependsRC = 1;
|
||||
|
||||
const char * const rpmNAME = PACKAGE;
|
||||
|
@ -64,7 +53,7 @@ static int intcmp(const void * a, const void * b)
|
|||
* @param depends installed package of pair (or RPMAL_NOMATCH on erase)
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int removePackage(rpmts ts, Header h, rpmalKey depends)
|
||||
static int removePackage(rpmts ts, Header h, rpmte depends)
|
||||
{
|
||||
rpmte p;
|
||||
unsigned int dboffset = headerGetInstance(h);
|
||||
|
@ -95,7 +84,7 @@ static int removePackage(rpmts ts, Header h, rpmalKey depends)
|
|||
ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
|
||||
}
|
||||
|
||||
p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, -1, RPMAL_NOMATCH);
|
||||
p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, -1);
|
||||
rpmteSetDependsOn(p, depends);
|
||||
|
||||
ts->order[ts->orderCount] = p;
|
||||
|
@ -121,7 +110,6 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
|
|||
const char * os = NULL;
|
||||
rpmds oldChk = NULL, newChk = NULL, sameChk = NULL;
|
||||
rpmds obsoletes;
|
||||
rpmalKey pkgKey; /* addedPackages key */
|
||||
int xx;
|
||||
int ec = 0;
|
||||
int rc;
|
||||
|
@ -136,7 +124,6 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
|
|||
if (headerGet(h, RPMTAG_OS, &td, HEADERGET_MINMEM))
|
||||
os = rpmtdGetString(&td);
|
||||
hcolor = headerGetColor(h);
|
||||
pkgKey = RPMAL_NOMATCH;
|
||||
|
||||
/* Check for supported payload format if it's a package */
|
||||
if (key && headerCheckPayloadFormat(h) != RPMRC_OK) {
|
||||
|
@ -222,7 +209,7 @@ int rpmtsAddInstallElement(rpmts ts, Header h,
|
|||
(pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
|
||||
(addNEVR ? addNEVR + 2 : "?addNEVR?"));
|
||||
duplicate = 1;
|
||||
pkgKey = rpmteAddedKey(p);
|
||||
rpmalDel(&ts->addedPackages, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +225,7 @@ addheader:
|
|||
ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
|
||||
}
|
||||
|
||||
p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
|
||||
p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1);
|
||||
|
||||
if (duplicate && oc < ts->orderCount) {
|
||||
ts->order[oc] = rpmteFree(ts->order[oc]);
|
||||
|
@ -250,15 +237,7 @@ addheader:
|
|||
rpmcliPackagesTotal++;
|
||||
}
|
||||
|
||||
pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
|
||||
rpmteDS(p, RPMTAG_PROVIDENAME),
|
||||
rpmteFI(p), tscolor);
|
||||
if (pkgKey == RPMAL_NOMATCH) {
|
||||
ts->order[oc] = rpmteFree(ts->order[oc]);
|
||||
ec = 1;
|
||||
goto exit;
|
||||
}
|
||||
(void) rpmteSetAddedKey(p, pkgKey);
|
||||
rpmalAdd(&ts->addedPackages, p, tscolor);
|
||||
|
||||
if (!duplicate) {
|
||||
ts->numAddedPackages++;
|
||||
|
@ -296,7 +275,7 @@ addheader:
|
|||
if (rpmVersionCompare(h, oh) == 0)
|
||||
continue;
|
||||
|
||||
xx = removePackage(ts, oh, pkgKey);
|
||||
xx = removePackage(ts, oh, p);
|
||||
}
|
||||
mi = rpmdbFreeIterator(mi);
|
||||
|
||||
|
@ -349,7 +328,7 @@ addheader:
|
|||
#ifdef DYING /* XXX see http://bugzilla.redhat.com #134497 */
|
||||
if (rpmVersionCompare(h, oh))
|
||||
#endif
|
||||
xx = removePackage(ts, oh, pkgKey);
|
||||
xx = removePackage(ts, oh, p);
|
||||
rpmlog(RPMLOG_DEBUG, " Obsoletes: %s\t\terases %s\n",
|
||||
rpmdsDNEVR(obsoletes)+2, ohNEVRA);
|
||||
ohNEVRA = _free(ohNEVRA);
|
||||
|
@ -371,7 +350,7 @@ exit:
|
|||
|
||||
int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
|
||||
{
|
||||
return removePackage(ts, h, RPMAL_NOMATCH);
|
||||
return removePackage(ts, h, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -462,7 +441,7 @@ retry:
|
|||
}
|
||||
|
||||
/* Search added packages for the dependency. */
|
||||
if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
|
||||
if (rpmalSatisfiesDepend(ts->addedPackages, dep) != NULL) {
|
||||
/*
|
||||
* XXX Ick, context sensitive answers from dependency cache.
|
||||
* XXX Always resolve added dependencies within context to disambiguate.
|
||||
|
@ -902,21 +881,17 @@ zapRelation(rpmte q, rpmte p,
|
|||
* Record next "q <- p" relation (i.e. "p" requires "q").
|
||||
* @param ts transaction set
|
||||
* @param p predecessor (i.e. package that "Requires: q")
|
||||
* @param selected boolean package selected array
|
||||
* @param requires relation
|
||||
* @return 0 always
|
||||
*/
|
||||
static inline int addRelation(rpmts ts,
|
||||
rpmal al,
|
||||
rpmte p,
|
||||
unsigned char * selected,
|
||||
rpmds requires)
|
||||
{
|
||||
rpmtsi qi; rpmte q;
|
||||
rpmte q;
|
||||
tsortInfo tsi;
|
||||
const char * Name;
|
||||
fnpyKey key;
|
||||
rpmalKey pkgKey;
|
||||
int teType = rpmteType(p);
|
||||
int i = 0;
|
||||
|
||||
|
@ -931,26 +906,9 @@ static inline int addRelation(rpmts ts,
|
|||
if (!strncmp(Name, "config(", sizeof("config(")-1))
|
||||
return 0;
|
||||
|
||||
pkgKey = RPMAL_NOMATCH;
|
||||
key = rpmalSatisfiesDepend(al, requires, &pkgKey);
|
||||
q = rpmalSatisfiesDepend(al, requires);
|
||||
|
||||
/* Ordering depends only on added/erased package relations. */
|
||||
if (pkgKey == RPMAL_NOMATCH)
|
||||
return 0;
|
||||
|
||||
/* XXX Set q to the added/removed package that was found. */
|
||||
/* XXX pretend erasedPackages are just appended to addedPackages. */
|
||||
if (teType == TR_REMOVED)
|
||||
pkgKey = (rpmalKey)(((long)pkgKey) + ts->numAddedPackages);
|
||||
|
||||
/* XXX FIXME: bsearch is possible/needed here */
|
||||
for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
|
||||
if (pkgKey == rpmteAddedKey(q))
|
||||
break;
|
||||
}
|
||||
|
||||
qi = rpmtsiFree(qi);
|
||||
if (q == NULL || i == ts->orderCount)
|
||||
if (q == NULL)
|
||||
return 0;
|
||||
|
||||
/* Avoid certain dependency relations. */
|
||||
|
@ -958,10 +916,11 @@ static inline int addRelation(rpmts ts,
|
|||
return 0;
|
||||
|
||||
/* Avoid redundant relations. */
|
||||
/* XXX TODO: add control bit. */
|
||||
if (selected[i] != 0)
|
||||
/* as we add all relations for p at once
|
||||
only the latest added relation
|
||||
can be from p already */
|
||||
if (p==q || rpmteTSI(q)->tsi_suc == p)
|
||||
return 0;
|
||||
selected[i] = 1;
|
||||
|
||||
/* Erasures are reversed installs. */
|
||||
if (teType == TR_REMOVED) {
|
||||
|
@ -989,19 +948,6 @@ static inline int addRelation(rpmts ts,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare ordered list entries by index (qsort/bsearch).
|
||||
* @param one 1st ordered list entry
|
||||
* @param two 2nd ordered list entry
|
||||
* @return result of comparison
|
||||
*/
|
||||
static int orderListIndexCmp(const void * one, const void * two)
|
||||
{
|
||||
long a = (long) ((const orderListIndex)one)->pkgKey;
|
||||
long b = (long) ((const orderListIndex)two)->pkgKey;
|
||||
return (a - b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add element to list sorting by tsi_qcnt.
|
||||
* @param p new element
|
||||
|
@ -1060,25 +1006,18 @@ int rpmtsOrder(rpmts ts)
|
|||
rpmtsi ri; rpmte r;
|
||||
tsortInfo tsi;
|
||||
tsortInfo tsi_next;
|
||||
rpmalKey * ordering;
|
||||
int orderingCount = 0;
|
||||
unsigned char *selected = xmalloc(sizeof(*selected) * (ts->orderCount + 1));
|
||||
int loopcheck;
|
||||
rpmte * newOrder;
|
||||
int newOrderCount = 0;
|
||||
orderListIndex orderList;
|
||||
int numOrderList;
|
||||
int npeer = 128; /* XXX more than deep enough for now. */
|
||||
int *peer = xcalloc(npeer, sizeof(*peer));
|
||||
int _printed = 0;
|
||||
char deptypechar;
|
||||
rpm_loff_t tsbytes;
|
||||
int oType = 0;
|
||||
int treex;
|
||||
int depth;
|
||||
int breadth;
|
||||
int qlen;
|
||||
int i, j;
|
||||
int rc;
|
||||
rpmal erasedPackages = rpmalCreate(5);
|
||||
|
||||
|
@ -1092,54 +1031,29 @@ int rpmtsOrder(rpmts ts)
|
|||
|
||||
/* Create erased package index. */
|
||||
pi = rpmtsiInit(ts);
|
||||
rpm_color_t tscolor = rpmtsColor(ts);
|
||||
while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
|
||||
rpmalKey pkgKey;
|
||||
fnpyKey key;
|
||||
rpm_color_t tscolor = rpmtsColor(ts);
|
||||
pkgKey = RPMAL_NOMATCH;
|
||||
key = (fnpyKey) p;
|
||||
pkgKey = rpmalAdd(&erasedPackages, pkgKey, key,
|
||||
rpmteDS(p, RPMTAG_PROVIDENAME),
|
||||
rpmteFI(p), tscolor);
|
||||
/* XXX pretend erasedPackages are just appended to addedPackages. */
|
||||
pkgKey = (rpmalKey)(((long)pkgKey) + ts->numAddedPackages);
|
||||
(void) rpmteSetAddedKey(p, pkgKey);
|
||||
rpmalAdd(&erasedPackages, p, tscolor);
|
||||
}
|
||||
pi = rpmtsiFree(pi);
|
||||
rpmalMakeIndex(erasedPackages);
|
||||
|
||||
|
||||
/* T1. Initialize. */
|
||||
if (oType == 0)
|
||||
numOrderList = ts->orderCount;
|
||||
else {
|
||||
numOrderList = 0;
|
||||
if (oType & TR_ADDED)
|
||||
numOrderList += ts->numAddedPackages;
|
||||
if (oType & TR_REMOVED)
|
||||
numOrderList += ts->numRemovedPackages;
|
||||
}
|
||||
ordering = xmalloc(sizeof(*ordering) * (numOrderList + 1));
|
||||
tsbytes = 0;
|
||||
|
||||
pi = rpmtsiInit(ts);
|
||||
while ((p = rpmtsiNext(pi, oType)) != NULL)
|
||||
while ((p = rpmtsiNext(pi, 0)) != NULL)
|
||||
rpmteNewTSI(p);
|
||||
pi = rpmtsiFree(pi);
|
||||
|
||||
/* Record all relations. */
|
||||
rpmlog(RPMLOG_DEBUG, "========== recording tsort relations\n");
|
||||
pi = rpmtsiInit(ts);
|
||||
while ((p = rpmtsiNext(pi, oType)) != NULL) {
|
||||
while ((p = rpmtsiNext(pi, 0)) != NULL) {
|
||||
|
||||
if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
|
||||
continue;
|
||||
|
||||
memset(selected, 0, sizeof(*selected) * ts->orderCount);
|
||||
|
||||
/* Avoid narcisstic relations. */
|
||||
selected[rpmtsiOc(pi)] = 1;
|
||||
|
||||
/* T2. Next "q <- p" relation. */
|
||||
|
||||
/* First, do pre-requisites. */
|
||||
|
@ -1155,7 +1069,7 @@ int rpmtsOrder(rpmts ts)
|
|||
if (!( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
|
||||
continue;
|
||||
/* T3. Record next "q <- p" relation (i.e. "p" requires "q") but reversed. */
|
||||
(void) addRelation(ts, erasedPackages, p, selected, requires);
|
||||
(void) addRelation(ts, erasedPackages, p, requires);
|
||||
|
||||
break;
|
||||
case TR_ADDED:
|
||||
|
@ -1163,7 +1077,7 @@ int rpmtsOrder(rpmts ts)
|
|||
if (!( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
|
||||
continue;
|
||||
/* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
|
||||
(void) addRelation(ts, ts->addedPackages, p, selected, requires);
|
||||
(void) addRelation(ts, ts->addedPackages, p, requires);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1182,7 +1096,7 @@ int rpmtsOrder(rpmts ts)
|
|||
|| ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
|
||||
continue;
|
||||
/* T3. Record next "q <- p" relation (i.e. "p" requires "q") but reversed. */
|
||||
(void) addRelation(ts, erasedPackages, p, selected, requires);
|
||||
(void) addRelation(ts, erasedPackages, p, requires);
|
||||
break;
|
||||
case TR_ADDED:
|
||||
/* Skip if %pre/%post requires or legacy prereq. */
|
||||
|
@ -1190,7 +1104,7 @@ int rpmtsOrder(rpmts ts)
|
|||
|| ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
|
||||
continue;
|
||||
/* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
|
||||
(void) addRelation(ts, ts->addedPackages, p, selected, requires);
|
||||
(void) addRelation(ts, ts->addedPackages, p, requires);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1200,7 +1114,7 @@ int rpmtsOrder(rpmts ts)
|
|||
/* Save predecessor count and mark tree roots. */
|
||||
treex = 0;
|
||||
pi = rpmtsiInit(ts);
|
||||
while ((p = rpmtsiNext(pi, oType)) != NULL) {
|
||||
while ((p = rpmtsiNext(pi, 0)) != NULL) {
|
||||
int npreds;
|
||||
|
||||
npreds = rpmteTSI(p)->tsi_count;
|
||||
|
@ -1224,7 +1138,8 @@ int rpmtsOrder(rpmts ts)
|
|||
rpmlog(RPMLOG_DEBUG, "========== tsorting packages (order, #predecessors, #succesors, tree, depth, breadth)\n");
|
||||
|
||||
/* Put installs first */
|
||||
oType = TR_ADDED;
|
||||
int oType = TR_ADDED;
|
||||
newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
|
||||
loopcheck = ts->numAddedPackages;
|
||||
|
||||
rescan:
|
||||
|
@ -1269,7 +1184,7 @@ rescan:
|
|||
(void) rpmteSetBreadth(q, breadth);
|
||||
|
||||
rpmlog(RPMLOG_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
|
||||
orderingCount, rpmteNpreds(q),
|
||||
newOrderCount, rpmteNpreds(q),
|
||||
rpmteTSI(q)->tsi_qcnt,
|
||||
treex, depth, breadth,
|
||||
(2 * depth), "",
|
||||
|
@ -1279,8 +1194,9 @@ rescan:
|
|||
(void) rpmteSetDegree(q, 0);
|
||||
tsbytes += rpmtePkgFileSize(q);
|
||||
|
||||
ordering[orderingCount] = rpmteAddedKey(q);
|
||||
orderingCount++;
|
||||
newOrder[newOrderCount] = q;
|
||||
|
||||
newOrderCount++;
|
||||
qlen--;
|
||||
loopcheck--;
|
||||
|
||||
|
@ -1307,7 +1223,7 @@ rescan:
|
|||
}
|
||||
if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
|
||||
_printed++;
|
||||
(void) rpmtsUnorderedSuccessors(ts, orderingCount);
|
||||
(void) rpmtsUnorderedSuccessors(ts, newOrderCount);
|
||||
rpmlog(RPMLOG_DEBUG, "========== successors only (%llu bytes)\n",
|
||||
(long long)tsbytes);
|
||||
|
||||
|
@ -1439,55 +1355,16 @@ rescan:
|
|||
rpmteFreeTSI(p);
|
||||
pi = rpmtsiFree(pi);
|
||||
|
||||
/*
|
||||
* The order ends up as installed packages followed by removed packages,
|
||||
* with removes for upgrades immediately following the installation of
|
||||
* the new package. This would be easier if we could sort the
|
||||
* addedPackages array, but we store indexes into it in various places.
|
||||
*/
|
||||
orderList = xcalloc(numOrderList, sizeof(*orderList));
|
||||
j = 0;
|
||||
pi = rpmtsiInit(ts);
|
||||
while ((p = rpmtsiNext(pi, 0)) != NULL) {
|
||||
/* Prepare added package ordering permutation. */
|
||||
orderList[j].pkgKey = rpmteAddedKey(p);
|
||||
orderList[j].orIndex = rpmtsiOc(pi);
|
||||
j++;
|
||||
}
|
||||
pi = rpmtsiFree(pi);
|
||||
|
||||
qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
|
||||
|
||||
newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
|
||||
for (i = 0, newOrderCount = 0; i < orderingCount; i++)
|
||||
{
|
||||
struct orderListIndex_s key;
|
||||
orderListIndex needle;
|
||||
|
||||
key.pkgKey = ordering[i];
|
||||
needle = bsearch(&key, orderList, numOrderList,
|
||||
sizeof(key), orderListIndexCmp);
|
||||
/* bsearch should never, ever fail */
|
||||
assert(needle != NULL);
|
||||
j = needle->orIndex;
|
||||
|
||||
newOrder[newOrderCount++] = ts->order[j];
|
||||
ts->order[j] = NULL;
|
||||
}
|
||||
|
||||
assert(newOrderCount == ts->orderCount);
|
||||
|
||||
ts->order = _free(ts->order);
|
||||
ts->order = newOrder;
|
||||
ts->orderAlloced = ts->orderCount;
|
||||
orderList = _free(orderList);
|
||||
rc = 0;
|
||||
|
||||
exit:
|
||||
freeBadDeps();
|
||||
free(selected);
|
||||
free(peer);
|
||||
free(ordering);
|
||||
rpmalFree(erasedPackages);
|
||||
|
||||
(void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
|
||||
|
|
104
lib/rpmal.c
104
lib/rpmal.c
|
@ -7,11 +7,13 @@
|
|||
|
||||
#include <rpm/rpmal.h>
|
||||
#include <rpm/rpmds.h>
|
||||
#include <rpm/rpmte.h>
|
||||
#include <rpm/rpmfi.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct availablePackage_s * availablePackage;
|
||||
typedef int rpmalNum;
|
||||
|
||||
int _rpmal_debug = 0;
|
||||
|
||||
|
@ -20,9 +22,9 @@ int _rpmal_debug = 0;
|
|||
* Info about a single package to be installed.
|
||||
*/
|
||||
struct availablePackage_s {
|
||||
rpmte p; /*!< transaction member */
|
||||
rpmds provides; /*!< Provides: dependencies. */
|
||||
rpmfi fi; /*!< File info set. */
|
||||
|
||||
rpm_color_t tscolor; /*!< Transaction color bits. */
|
||||
|
||||
fnpyKey key; /*!< Associated file name/python object */
|
||||
|
@ -35,7 +37,7 @@ typedef struct availableIndexEntry_s * availableIndexEntry;
|
|||
* A single available item (e.g. a Provides: dependency).
|
||||
*/
|
||||
struct availableIndexEntry_s {
|
||||
rpmalKey pkgKey; /*!< Containing package. */
|
||||
rpmalNum pkgNum; /*!< Containing package index. */
|
||||
const char * entry; /*!< Dependency name. */
|
||||
unsigned short entryLen; /*!< No. of bytes in name. */
|
||||
unsigned short entryIx; /*!< Dependency index. */
|
||||
|
@ -106,18 +108,6 @@ static void rpmalFreeIndex(rpmal al)
|
|||
}
|
||||
}
|
||||
|
||||
static inline rpmalNum alKey2Num(const rpmal al,
|
||||
rpmalKey pkgKey)
|
||||
{
|
||||
return ((rpmalNum)pkgKey);
|
||||
}
|
||||
|
||||
static inline rpmalKey alNum2Key(const rpmal al,
|
||||
rpmalNum pkgNum)
|
||||
{
|
||||
return ((rpmalKey)pkgNum);
|
||||
}
|
||||
|
||||
rpmal rpmalCreate(int delta)
|
||||
{
|
||||
rpmal al = xcalloc(1, sizeof(*al));
|
||||
|
@ -220,15 +210,23 @@ fprintf(stderr, "\n");
|
|||
return strcmp(a->baseName, b->baseName);
|
||||
}
|
||||
|
||||
void rpmalDel(rpmal al, rpmalKey pkgKey)
|
||||
void rpmalDel(rpmal al, rpmte p)
|
||||
{
|
||||
rpmalNum pkgNum = alKey2Num(al, pkgKey);
|
||||
availablePackage alp;
|
||||
rpmfi fi;
|
||||
rpmalNum pkgNum;
|
||||
|
||||
if (al == NULL || al->list == NULL)
|
||||
return; /* XXX can't happen */
|
||||
|
||||
// XXX use a search for self provide
|
||||
for (pkgNum=0; pkgNum<al->size; pkgNum++) {
|
||||
if (al->list[pkgNum].p == p) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pkgNum == al->size ) return; // Not found!
|
||||
|
||||
alp = al->list + pkgNum;
|
||||
|
||||
if (_rpmal_debug)
|
||||
|
@ -317,45 +315,39 @@ fprintf(stderr, " die[%5d] memset(%p,0,0x%lx)\n", al->numDirs, al->dirs + al-
|
|||
alp->fi = rpmfiFree(alp->fi);
|
||||
|
||||
memset(alp, 0, sizeof(*alp)); /* XXX trash and burn */
|
||||
// XXX leaves empty entry that is not recovered
|
||||
return;
|
||||
}
|
||||
|
||||
rpmalKey rpmalAdd(rpmal * alistp, rpmalKey pkgKey, fnpyKey key,
|
||||
rpmds provides, rpmfi fi, rpm_color_t tscolor)
|
||||
void rpmalAdd(rpmal * alistp, rpmte p, rpm_color_t tscolor)
|
||||
{
|
||||
rpmalNum pkgNum;
|
||||
rpmal al;
|
||||
availablePackage alp;
|
||||
rpmfi fi;
|
||||
|
||||
/* If list doesn't exist yet, create. */
|
||||
if (*alistp == NULL)
|
||||
*alistp = rpmalCreate(5);
|
||||
al = *alistp;
|
||||
pkgNum = alKey2Num(al, pkgKey);
|
||||
|
||||
if (pkgNum >= 0 && pkgNum < al->size) {
|
||||
rpmalDel(al, pkgKey);
|
||||
} else {
|
||||
if (al->size == al->alloced) {
|
||||
al->alloced += al->delta;
|
||||
al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
|
||||
}
|
||||
pkgNum = al->size++;
|
||||
if (al->size == al->alloced) {
|
||||
al->alloced += al->delta;
|
||||
al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
|
||||
}
|
||||
|
||||
if (al->list == NULL)
|
||||
return RPMAL_NOMATCH; /* XXX can't happen */
|
||||
pkgNum = al->size++;
|
||||
|
||||
alp = al->list + pkgNum;
|
||||
|
||||
alp->key = key;
|
||||
alp->p = p;
|
||||
alp->tscolor = tscolor;
|
||||
|
||||
if (_rpmal_debug)
|
||||
fprintf(stderr, "*** add %p[%d] 0x%x\n", al->list, (int) pkgNum, tscolor);
|
||||
|
||||
alp->provides = rpmdsLink(provides, RPMDBG_M("Provides (rpmalAdd)"));
|
||||
alp->fi = rpmfiLink(fi, RPMDBG_M("Files (rpmalAdd)"));
|
||||
alp->provides = rpmdsLink(rpmteDS(p, RPMTAG_PROVIDENAME),
|
||||
RPMDBG_M("Provides (rpmalAdd)"));
|
||||
alp->fi = rpmfiLink(rpmteFI(p), RPMDBG_M("Files (rpmalAdd)"));
|
||||
|
||||
fi = rpmfiLink(alp->fi, RPMDBG_M("Files index (rpmalAdd)"));
|
||||
fi = rpmfiInit(fi, 0);
|
||||
|
@ -485,7 +477,6 @@ fprintf(stderr, "\t%p[%3d] %p:%p[%2d] %s\n", die->files, die->numFiles, fie, fie
|
|||
rpmalFreeIndex(al);
|
||||
|
||||
assert(((rpmalNum)(alp - al->list)) == pkgNum);
|
||||
return ((rpmalKey)(alp - al->list));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -507,17 +498,14 @@ static int indexcmp(const void * one, const void * two)
|
|||
return strcmp(a->entry, b->entry);
|
||||
}
|
||||
|
||||
void rpmalAddProvides(rpmal al, rpmalKey pkgKey, rpmds provides, rpm_color_t tscolor)
|
||||
static void rpmalAddProvides(rpmal al, rpmalNum pkgNum, rpmds provides, rpm_color_t tscolor)
|
||||
{
|
||||
rpm_color_t dscolor;
|
||||
const char * Name;
|
||||
rpmalNum pkgNum = alKey2Num(al, pkgKey);
|
||||
availableIndex ai = &al->index;
|
||||
availableIndexEntry aie;
|
||||
int ix;
|
||||
|
||||
if (provides == NULL || pkgNum < 0 || pkgNum >= al->size)
|
||||
return;
|
||||
if (ai->index == NULL || ai->k < 0 || ai->k >= ai->size)
|
||||
return;
|
||||
|
||||
|
@ -535,7 +523,7 @@ void rpmalAddProvides(rpmal al, rpmalKey pkgKey, rpmds provides, rpm_color_t tsc
|
|||
aie = ai->index + ai->k;
|
||||
ai->k++;
|
||||
|
||||
aie->pkgKey = pkgKey;
|
||||
aie->pkgNum = pkgNum;
|
||||
aie->entry = Name;
|
||||
aie->entryLen = strlen(Name);
|
||||
ix = rpmdsIx(provides);
|
||||
|
@ -569,7 +557,7 @@ void rpmalMakeIndex(rpmal al)
|
|||
ai->k = 0;
|
||||
for (i = 0; i < al->size; i++) {
|
||||
alp = al->list + i;
|
||||
rpmalAddProvides(al, (rpmalKey)i, alp->provides, alp->tscolor);
|
||||
rpmalAddProvides(al, i, alp->provides, alp->tscolor);
|
||||
}
|
||||
|
||||
/* Reset size to the no. of provides added. */
|
||||
|
@ -577,8 +565,8 @@ void rpmalMakeIndex(rpmal al)
|
|||
qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
|
||||
}
|
||||
|
||||
fnpyKey *
|
||||
rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
|
||||
rpmte *
|
||||
rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds)
|
||||
{
|
||||
rpm_color_t tscolor;
|
||||
rpm_color_t ficolor;
|
||||
|
@ -590,14 +578,12 @@ rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
|
|||
struct fileIndexEntry_s fieNeedle;
|
||||
fileIndexEntry fie;
|
||||
availablePackage alp;
|
||||
fnpyKey * ret = NULL;
|
||||
rpmte * ret = NULL;
|
||||
const char * fileName;
|
||||
|
||||
memset(&dieNeedle, 0, sizeof(dieNeedle));
|
||||
memset(&fieNeedle, 0, sizeof(fieNeedle));
|
||||
|
||||
if (keyp) *keyp = RPMAL_NOMATCH;
|
||||
|
||||
if (al == NULL || (fileName = rpmdsN(ds)) == NULL || *fileName != '/')
|
||||
return NULL;
|
||||
|
||||
|
@ -659,9 +645,7 @@ fprintf(stderr, "==> fie %p %s\n", fie, (fie->baseName ? fie->baseName : "(nil)"
|
|||
|
||||
ret = xrealloc(ret, (found+2) * sizeof(*ret));
|
||||
if (ret) /* can't happen */
|
||||
ret[found] = alp->key;
|
||||
if (keyp)
|
||||
*keyp = alNum2Key(al, fie->pkgNum);
|
||||
ret[found] = alp->p;
|
||||
found++;
|
||||
}
|
||||
|
||||
|
@ -672,26 +656,24 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
fnpyKey *
|
||||
rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
|
||||
rpmte *
|
||||
rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds)
|
||||
{
|
||||
availableIndex ai;
|
||||
struct availableIndexEntry_s needle;
|
||||
availableIndexEntry match;
|
||||
fnpyKey * ret = NULL;
|
||||
rpmte * ret = NULL;
|
||||
int found = 0;
|
||||
const char * KName;
|
||||
availablePackage alp;
|
||||
int rc;
|
||||
|
||||
if (keyp) *keyp = RPMAL_NOMATCH;
|
||||
|
||||
if (al == NULL || ds == NULL || (KName = rpmdsN(ds)) == NULL)
|
||||
return ret;
|
||||
|
||||
if (*KName == '/') {
|
||||
/* First, look for files "contained" in package ... */
|
||||
ret = rpmalAllFileSatisfiesDepend(al, ds, keyp);
|
||||
ret = rpmalAllFileSatisfiesDepend(al, ds);
|
||||
if (ret != NULL && *ret != NULL)
|
||||
return ret;
|
||||
/* ... then, look for files "provided" by package. */
|
||||
|
@ -719,7 +701,7 @@ rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
|
|||
match < ai->index + ai->size && indexcmp(match, &needle) == 0;
|
||||
match++)
|
||||
{
|
||||
alp = al->list + alKey2Num(al, match->pkgKey);
|
||||
alp = al->list + match->pkgNum;
|
||||
|
||||
rc = 0;
|
||||
if (alp->provides != NULL) /* XXX can't happen */
|
||||
|
@ -739,9 +721,7 @@ rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
|
|||
if (rc) {
|
||||
ret = xrealloc(ret, (found + 2) * sizeof(*ret));
|
||||
if (ret) /* can't happen */
|
||||
ret[found] = alp->key;
|
||||
if (keyp)
|
||||
*keyp = match->pkgKey;
|
||||
ret[found] = alp->p;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
@ -753,13 +733,13 @@ rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
fnpyKey
|
||||
rpmalSatisfiesDepend(const rpmal al, const rpmds ds, rpmalKey * keyp)
|
||||
rpmte
|
||||
rpmalSatisfiesDepend(const rpmal al, const rpmds ds)
|
||||
{
|
||||
fnpyKey * tmp = rpmalAllSatisfiesDepend(al, ds, keyp);
|
||||
rpmte * tmp = rpmalAllSatisfiesDepend(al, ds);
|
||||
|
||||
if (tmp) {
|
||||
fnpyKey ret = tmp[0];
|
||||
rpmte ret = tmp[0];
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
|
50
lib/rpmal.h
50
lib/rpmal.h
|
@ -14,13 +14,6 @@ extern "C" {
|
|||
|
||||
extern int _rpmal_debug;
|
||||
|
||||
#define RPMAL_NOMATCH ((rpmalKey)-1L)
|
||||
|
||||
/** \ingroup rpmtrans
|
||||
* * An added/available package retrieval index.
|
||||
* */
|
||||
typedef intptr_t rpmalNum;
|
||||
|
||||
/**
|
||||
* Initialize available packckages, items, and directory list.
|
||||
* @param delta no. of entries to add on each realloc
|
||||
|
@ -38,36 +31,20 @@ rpmal rpmalFree(rpmal al);
|
|||
/**
|
||||
* Delete package from available list.
|
||||
* @param al available list
|
||||
* @param pkgKey package key
|
||||
* @param p package
|
||||
*/
|
||||
void rpmalDel(rpmal al, rpmalKey pkgKey);
|
||||
void rpmalDel(rpmal al, rpmte p);
|
||||
|
||||
/**
|
||||
* Add package to available list.
|
||||
* @param alistp address of available list
|
||||
* @param pkgKey package key, RPMAL_NOMATCH to force an append
|
||||
* @param key associated file name/python object
|
||||
* @param provides provides dependency set
|
||||
* @param fi file info set
|
||||
* @param p package
|
||||
* @param tscolor transaction color bits
|
||||
* @return available package index
|
||||
*/
|
||||
rpmalKey rpmalAdd(rpmal * alistp,
|
||||
rpmalKey pkgKey,
|
||||
fnpyKey key,
|
||||
rpmds provides, rpmfi fi,
|
||||
rpm_color_t tscolor);
|
||||
|
||||
/**
|
||||
* Add package provides to available list index.
|
||||
* @param al available list
|
||||
* @param pkgKey package key
|
||||
* @param provides added package provides
|
||||
* @param tscolor transaction color bits
|
||||
*/
|
||||
void rpmalAddProvides(rpmal al,
|
||||
rpmalKey pkgKey,
|
||||
rpmds provides, rpm_color_t tscolor);
|
||||
void rpmalAdd(rpmal * alistp,
|
||||
rpmte p,
|
||||
rpm_color_t tscolor);
|
||||
|
||||
/**
|
||||
* Generate index for available list.
|
||||
|
@ -79,32 +56,27 @@ void rpmalMakeIndex(rpmal al);
|
|||
* Check added package file lists for package(s) that provide a file.
|
||||
* @param al available list
|
||||
* @param ds dependency set
|
||||
* @retval keyp added package key pointer (or NULL)
|
||||
* @return associated package key(s), NULL if none
|
||||
* @return associated package(s), NULL if none
|
||||
*/
|
||||
fnpyKey * rpmalAllFileSatisfiesDepend(const rpmal al,
|
||||
const rpmds ds, rpmalKey * keyp);
|
||||
rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const rpmds ds);
|
||||
|
||||
/**
|
||||
* Check added package file lists for package(s) that have a provide.
|
||||
* @param al available list
|
||||
* @param ds dependency set
|
||||
* @retval keyp added package key pointer (or NULL)
|
||||
* @return associated package key(s), NULL if none
|
||||
* @return associated package(s), NULL if none
|
||||
*/
|
||||
fnpyKey * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds,
|
||||
rpmalKey * keyp);
|
||||
rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds);
|
||||
|
||||
/**
|
||||
* Check added package file lists for first package that has a provide.
|
||||
* @todo Eliminate.
|
||||
* @param al available list
|
||||
* @param ds dependency set
|
||||
* @retval keyp added package key pointer (or NULL)
|
||||
* @return associated package key, NULL if none
|
||||
*/
|
||||
fnpyKey rpmalSatisfiesDepend(const rpmal al, const rpmds ds,
|
||||
rpmalKey * keyp);
|
||||
rpmte rpmalSatisfiesDepend(const rpmal al, const rpmds ds);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
21
lib/rpmte.c
21
lib/rpmte.c
|
@ -66,8 +66,6 @@ struct rpmte_s {
|
|||
int transscripts; /*!< pre/posttrans script existence */
|
||||
int failed; /*!< (parent) install/erase failed */
|
||||
|
||||
rpmalKey pkgKey;
|
||||
|
||||
rpmfs fs;
|
||||
};
|
||||
|
||||
|
@ -319,15 +317,13 @@ rpmte rpmteNew(const rpmts ts, Header h,
|
|||
rpmElementType type,
|
||||
fnpyKey key,
|
||||
rpmRelocation * relocs,
|
||||
int dboffset,
|
||||
rpmalKey pkgKey)
|
||||
int dboffset)
|
||||
{
|
||||
rpmte p = xcalloc(1, sizeof(*p));
|
||||
uint32_t *ep;
|
||||
struct rpmtd_s size;
|
||||
|
||||
p->type = type;
|
||||
p->pkgKey = pkgKey;
|
||||
addTE(ts, p, h, key, relocs);
|
||||
switch (type) {
|
||||
case TR_ADDED:
|
||||
|
@ -551,21 +547,6 @@ void rpmteNewTSI(rpmte te)
|
|||
}
|
||||
}
|
||||
|
||||
rpmalKey rpmteAddedKey(rpmte te)
|
||||
{
|
||||
return (te != NULL ? te->pkgKey : RPMAL_NOMATCH);
|
||||
}
|
||||
|
||||
rpmalKey rpmteSetAddedKey(rpmte te, rpmalKey npkgKey)
|
||||
{
|
||||
rpmalKey opkgKey = RPMAL_NOMATCH;
|
||||
if (te != NULL) {
|
||||
opkgKey = te->pkgKey;
|
||||
te->pkgKey = npkgKey;
|
||||
}
|
||||
return opkgKey;
|
||||
}
|
||||
|
||||
void rpmteSetDependsOn(rpmte te, rpmte depends) {
|
||||
te->depends = depends;
|
||||
}
|
||||
|
|
22
lib/rpmte.h
22
lib/rpmte.h
|
@ -6,7 +6,7 @@
|
|||
* Structures used for an "rpmte" transaction element.
|
||||
*/
|
||||
|
||||
#include <rpm/rpmal.h>
|
||||
#include <rpm/rpmtypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -49,14 +49,12 @@ rpmte rpmteFree(rpmte te);
|
|||
* @param key (TR_ADDED) package retrieval key (e.g. file name)
|
||||
* @param relocs (TR_ADDED) package file relocations
|
||||
* @param dboffset unused
|
||||
* @param pkgKey associated added package (if any)
|
||||
* @return new transaction element
|
||||
*/
|
||||
rpmte rpmteNew(const rpmts ts, Header h, rpmElementType type,
|
||||
fnpyKey key,
|
||||
rpmRelocation * relocs,
|
||||
int dboffset,
|
||||
rpmalKey pkgKey);
|
||||
int dboffset);
|
||||
|
||||
/** \ingroup rpmte
|
||||
* Retrieve header from transaction element.
|
||||
|
@ -282,22 +280,6 @@ void rpmteNewTSI(rpmte te);
|
|||
*/
|
||||
void rpmteCleanDS(rpmte te);
|
||||
|
||||
/** \ingroup rpmte
|
||||
* Retrieve pkgKey of TR_ADDED transaction element.
|
||||
* @param te transaction element
|
||||
* @return pkgKey
|
||||
*/
|
||||
rpmalKey rpmteAddedKey(rpmte te);
|
||||
|
||||
/** \ingroup rpmte
|
||||
* Set pkgKey of TR_ADDED transaction element.
|
||||
* @param te transaction element
|
||||
* @param npkgKey new pkgKey
|
||||
* @return previous pkgKey
|
||||
*/
|
||||
rpmalKey rpmteSetAddedKey(rpmte te,
|
||||
rpmalKey npkgKey);
|
||||
|
||||
/** \ingroup rpmte
|
||||
* Set dependent element of TR_REMOVED transaction element.
|
||||
* @param te transaction element
|
||||
|
|
|
@ -25,53 +25,31 @@ rpmal_Debug(rpmalObject * s, PyObject * args, PyObject * kwds)
|
|||
static PyObject *
|
||||
rpmal_Add(rpmalObject * s, PyObject * args, PyObject * kwds)
|
||||
{
|
||||
rpmdsObject * dso;
|
||||
rpmfiObject * fio;
|
||||
PyObject * key;
|
||||
rpmalKey pkgKey;
|
||||
char * kwlist[] = {"packageKey", "key", "dso", "fileInfo", NULL};
|
||||
rpmte p;
|
||||
char * kwlist[] = {"package", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "iOO!O!:Add", kwlist,
|
||||
&pkgKey, &key, &rpmds_Type, &dso, &rpmfi_Type, &fio))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:Add", kwlist,
|
||||
&p))
|
||||
return NULL;
|
||||
|
||||
/* XXX errors */
|
||||
/* XXX transaction colors */
|
||||
pkgKey = rpmalAdd(&s->al, pkgKey, key, dso->ds, fio->fi, 0);
|
||||
|
||||
return Py_BuildValue("i", pkgKey);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
rpmal_Del(rpmalObject * s, PyObject * args, PyObject * kwds)
|
||||
{
|
||||
rpmalKey pkgKey;
|
||||
char * kwlist[] = {"key", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Del", kwlist, &pkgKey))
|
||||
return NULL;
|
||||
|
||||
rpmalDel(s->al, pkgKey);
|
||||
rpmalAdd(&s->al, p, 0);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
rpmal_AddProvides(rpmalObject * s, PyObject * args, PyObject * kwds)
|
||||
rpmal_Del(rpmalObject * s, PyObject * args, PyObject * kwds)
|
||||
{
|
||||
rpmdsObject * dso;
|
||||
rpmalKey pkgKey;
|
||||
char * kwlist[] = {"index", "packageIndex", "dso", NULL};
|
||||
rpmte p;
|
||||
char * kwlist[] = {"key", NULL};
|
||||
|
||||
/* XXX: why is there an argument listed in the format string that
|
||||
* isn't handled? Is that for transaction color? */
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "iOO!O!:AddProvides", kwlist,
|
||||
&pkgKey, &rpmds_Type, &dso))
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:Del", kwlist, &p))
|
||||
return NULL;
|
||||
|
||||
/* XXX transaction colors */
|
||||
rpmalAddProvides(s->al, pkgKey, dso->ds, 0);
|
||||
rpmalDel(s->al, p);
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
@ -93,8 +71,6 @@ static struct PyMethodDef rpmal_methods[] = {
|
|||
NULL},
|
||||
{"delete", (PyCFunction)rpmal_Del, METH_VARARGS|METH_KEYWORDS,
|
||||
NULL},
|
||||
{"addProvides",(PyCFunction)rpmal_AddProvides, METH_VARARGS|METH_KEYWORDS,
|
||||
NULL},
|
||||
{"makeIndex",(PyCFunction)rpmal_MakeIndex, METH_NOARGS,
|
||||
NULL},
|
||||
{NULL, NULL } /* sentinel */
|
||||
|
|
|
@ -491,7 +491,5 @@ void init_rpm(void)
|
|||
REGISTER_ENUM(TR_REMOVED);
|
||||
|
||||
REGISTER_ENUM(RPMDBI_PACKAGES);
|
||||
|
||||
REGISTER_ENUM((intptr_t)RPMAL_NOMATCH);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,18 +149,13 @@ rpmte_Tree(rpmteObject * s)
|
|||
{
|
||||
return Py_BuildValue("i", rpmteTree(s->te));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
rpmte_AddedKey(rpmteObject * s)
|
||||
{
|
||||
return Py_BuildValue("i", rpmteAddedKey(s->te));
|
||||
}
|
||||
|
||||
/*
|
||||
static PyObject *
|
||||
rpmte_DependsOnKey(rpmteObject * s)
|
||||
{
|
||||
return Py_BuildValue("i", rpmteDependsOnKey(s->te));
|
||||
}
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
rpmte_DBOffset(rpmteObject * s)
|
||||
|
@ -267,10 +262,8 @@ static struct PyMethodDef rpmte_methods[] = {
|
|||
NULL},
|
||||
{"Tree", (PyCFunction)rpmte_Tree, METH_NOARGS,
|
||||
NULL},
|
||||
{"AddedKey",(PyCFunction)rpmte_AddedKey, METH_NOARGS,
|
||||
NULL},
|
||||
{"DependsOnKey",(PyCFunction)rpmte_DependsOnKey, METH_NOARGS,
|
||||
NULL},
|
||||
/* {"DependsOnKey",(PyCFunction)rpmte_DependsOnKey, METH_NOARGS,
|
||||
NULL}, */
|
||||
{"DBOffset",(PyCFunction)rpmte_DBOffset, METH_NOARGS,
|
||||
NULL},
|
||||
{"Key", (PyCFunction)rpmte_Key, METH_NOARGS,
|
||||
|
|
Loading…
Reference in New Issue