[Rpm-maint] [PATCH v2 2/5] Determine when to perform Collection actions

Steve Lawrence slawrence at tresys.com
Mon Jun 21 21:04:37 UTC 2010


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.
---
 lib/rpmte.c          |   65 ++++++++++++++++++++++++++++++++++++++++
 lib/rpmte.h          |   17 ++++++++++
 lib/rpmte_internal.h |   31 +++++++++++++++++++
 lib/transaction.c    |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 194 insertions(+), 0 deletions(-)

diff --git a/lib/rpmte.c b/lib/rpmte.c
index 7765f70..5304e7b 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -61,6 +61,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 */
@@ -183,6 +188,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);
@@ -226,6 +233,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;
@@ -259,6 +279,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);
     }
@@ -366,6 +391,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);
diff --git a/lib/rpmte.h b/lib/rpmte.h
index 0d1fc8d..17854d7 100644
--- a/lib/rpmte.h
+++ b/lib/rpmte.h
@@ -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
diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h
index 0aa78b2..2425868 100644
--- a/lib/rpmte_internal.h
+++ b/lib/rpmte_internal.h
@@ -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 */
 
diff --git a/lib/transaction.c b/lib/transaction.c
index 9881426..5202ee2 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -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);
 
-- 
1.6.2.5



More information about the Rpm-maint mailing list