Determine when to perform Collection actions

There are three times during a transaction when Collection actions can be
performed:

1) After the last time a member of a collection is either installed or removed
2) After the last time a member of a collection is installed only
3) Before the first time a member of a collection is removed only

This patch adds three lists to the rpmte structure to mark which transaction
elements fall into each of these groups, and the collections that caused that.
A new function is added to the TSM to scan through all the transaction elements
and update these lists. When a collection is added to one of these lists, it
signifies that when that transaction element is installed, the appropriate
action should be performed for that collection.
This commit is contained in:
Steve Lawrence 2010-06-21 17:04:37 -04:00 committed by Panu Matilainen
parent 04bdec775a
commit 85d89bafdc
4 changed files with 194 additions and 0 deletions

View File

@ -63,6 +63,11 @@ struct rpmte_s {
int failed; /*!< (parent) install/erase failed */
rpmfs fs;
ARGV_t lastInCollectionsAny; /*!< list of collections this te is the last to be installed or removed */
ARGV_t lastInCollectionsAdd; /*!< list of collections this te is the last to be only installed */
ARGV_t firstInCollectionsRemove; /*!< list of collections this te is the first to be only removed */
ARGV_t collections; /*!< list of collections */
};
/* forward declarations */
@ -185,6 +190,8 @@ static void buildRelocs(rpmte p, Header h, rpmRelocation *relocs)
*/
static void addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
{
struct rpmtd_s colls;
p->name = headerGetAsString(h, RPMTAG_NAME);
p->version = headerGetAsString(h, RPMTAG_VERSION);
p->release = headerGetAsString(h, RPMTAG_RELEASE);
@ -228,6 +235,19 @@ static void addTE(rpmte p, Header h, fnpyKey key, rpmRelocation * relocs)
headerIsEntry(h, RPMTAG_POSTTRANSPROG)) ?
RPMTE_HAVE_POSTTRANS : 0;
p->lastInCollectionsAny = NULL;
p->lastInCollectionsAdd = NULL;
p->firstInCollectionsRemove = NULL;
p->collections = NULL;
if (headerGet(h, RPMTAG_COLLECTIONS, &colls, HEADERGET_MINMEM)) {
const char *collname;
while ((collname = rpmtdNextString(&colls))) {
argvAdd(&p->collections, collname);
}
argvSort(p->collections, NULL);
rpmtdFreeData(&colls);
}
rpmteColorDS(p, RPMTAG_PROVIDENAME);
rpmteColorDS(p, RPMTAG_REQUIRENAME);
return;
@ -261,6 +281,11 @@ rpmte rpmteFree(rpmte te)
rpmteCleanDS(te);
rpmtsUnlink(te->ts);
argvFree(te->collections);
argvFree(te->lastInCollectionsAny);
argvFree(te->lastInCollectionsAdd);
argvFree(te->firstInCollectionsRemove);
memset(te, 0, sizeof(*te)); /* XXX trash and burn */
free(te);
}
@ -368,6 +393,46 @@ rpm_color_t rpmteSetColor(rpmte te, rpm_color_t color)
return ocolor;
}
ARGV_const_t rpmteCollections(rpmte te)
{
return (te != NULL) ? te->collections : NULL;
}
int rpmteHasCollection(rpmte te, const char *collname)
{
return (argvSearch(rpmteCollections(te), collname, NULL) != NULL);
}
int rpmteAddToLastInCollectionAdd(rpmte te, const char *collname)
{
if (te != NULL) {
argvAdd(&te->lastInCollectionsAdd, collname);
argvSort(te->lastInCollectionsAdd, NULL);
return 0;
}
return -1;
}
int rpmteAddToLastInCollectionAny(rpmte te, const char *collname)
{
if (te != NULL) {
argvAdd(&te->lastInCollectionsAny, collname);
argvSort(te->lastInCollectionsAny, NULL);
return 0;
}
return -1;
}
int rpmteAddToFirstInCollectionRemove(rpmte te, const char *collname)
{
if (te != NULL) {
argvAdd(&te->firstInCollectionsRemove, collname);
argvSort(te->firstInCollectionsRemove, NULL);
return 0;
}
return -1;
}
rpm_loff_t rpmtePkgFileSize(rpmte te)
{
return (te != NULL ? te->pkgFileSize : 0);

View File

@ -7,6 +7,7 @@
*/
#include <rpm/rpmtypes.h>
#include <rpm/argv.h>
#ifdef __cplusplus
extern "C" {
@ -236,6 +237,22 @@ rpmds rpmteDS(rpmte te, rpmTag tag);
*/
rpmfi rpmteFI(rpmte te);
/** \ingroup rpmte
* Retrieve list of collections
* @param te transaction element
* @return list of collections
*/
ARGV_const_t rpmteCollections(rpmte te);
/** \ingroup rpmte
* Determine a transaction element is part of a collection
* @param te transaction element
* @param collname collection name
* @return 1 if collname is part of a collection, 0 if not
*/
int rpmteHasCollection(rpmte te, const char * collname);
#ifdef __cplusplus
}
#endif

View File

@ -104,5 +104,36 @@ unsigned int rpmteHeaderSize(rpmte te);
RPM_GNUC_INTERNAL
rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal);
/** \ingroup rpmte
* Add a collection to the list of last collections for the installation
* section of a transaction element
* @param te transaction element
* @param collname collection name
* @return 0 on success, non-zero on error
*/
RPM_GNUC_INTERNAL
int rpmteAddToLastInCollectionAdd(rpmte te, const char * collname);
/** \ingroup rpmte
* Add a collection to the list of last collections for the installation
* or removal section of a transaction element
* @param te transaction element
* @param collname collection name
* @return 0 on success, non-zero on error
*/
RPM_GNUC_INTERNAL
int rpmteAddToLastInCollectionAny(rpmte te, const char * collname);
/** \ingroup rpmte
* Add a collection to the list of first collections for the removal
* section of a transaction element
* @param te transaction element
* @param collname collection name
* @return 0 on success, non-zero on error
*/
RPM_GNUC_INTERNAL
int rpmteAddToFirstInCollectionRemove(rpmte te, const char * collname);
#endif /* _RPMTE_INTERNAL_H */

View File

@ -1108,6 +1108,85 @@ static int runTransScripts(rpmts ts, pkgGoal goal)
return 0; /* what to do about failures? */
}
static int rpmtsDetermineCollectionPoints(rpmts ts)
{
/* seenCollectionsPost and TEs are basically a key-value pair. each item in
* seenCollectionsPost is a collection that has been seen from any package,
* and the associated index in the TEs is the last transaction element
* where that collection was seen. */
ARGV_t seenCollectionsPost = NULL;
rpmte *TEs = NULL;
int numSeenPost = 0;
/* seenCollectionsPre is a list of collections that have been seen from
* only removed packages */
ARGV_t seenCollectionsPre = NULL;
int numSeenPre = 0;
ARGV_const_t collname;
int installing = 1;
int i;
rpmte p;
rpmtsi pi = rpmtsiInit(ts);
while ((p = rpmtsiNext(pi, 0)) != NULL) {
/* detect when we switch from installing to removing packages, and
* update the lastInCollectionAdd lists */
if (installing && rpmteType(p) == TR_REMOVED) {
installing = 0;
for (i = 0; i < numSeenPost; i++) {
rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]);
}
}
for (collname = rpmteCollections(p); collname && *collname; collname++) {
/* figure out if we've seen this collection in post before */
for (i = 0; i < numSeenPost && strcmp(*collname, seenCollectionsPost[i]); i++) {
}
if (i < numSeenPost) {
/* we've seen the collection, update the index */
TEs[i] = p;
} else {
/* haven't seen the collection yet, add it */
argvAdd(&seenCollectionsPost, *collname);
TEs = xrealloc(TEs, sizeof(*TEs) * (numSeenPost + 1));
TEs[numSeenPost] = p;
numSeenPost++;
}
/* figure out if we've seen this collection in pre remove before */
if (installing == 0) {
for (i = 0; i < numSeenPre && strcmp(*collname, seenCollectionsPre[i]); i++) {
}
if (i >= numSeenPre) {
/* haven't seen this collection, add it */
rpmteAddToFirstInCollectionRemove(p, *collname);
argvAdd(&seenCollectionsPre, *collname);
numSeenPre++;
}
}
}
}
pi = rpmtsiFree(pi);
/* we've looked at all the rpmte's, update the lastInCollectionAny lists */
for (i = 0; i < numSeenPost; i++) {
rpmteAddToLastInCollectionAny(TEs[i], seenCollectionsPost[i]);
if (installing == 1) {
/* lastInCollectionAdd is only updated above if packages were
* removed. if nothing is removed in the transaction, we need to
* update that list here */
rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]);
}
}
argvFree(seenCollectionsPost);
argvFree(seenCollectionsPre);
_free(TEs);
return 0;
}
/* Add fingerprint for each file not skipped. */
static void addFingerprints(rpmts ts, uint64_t fileCount, rpmFpHash ht, fingerPrintCache fpc)
{
@ -1347,6 +1426,8 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
goto exit;
}
rpmtsDetermineCollectionPoints(ts);
/* Check package set for problems */
tsprobs = checkProblems(ts);