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

Steve Lawrence slawrence at tresys.com
Thu Jun 17 19:55:24 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       |   80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/rpmte.h       |   64 ++++++++++++++++++++++++++++++++++++++++++
 lib/transaction.c |   79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 223 insertions(+), 0 deletions(-)

diff --git a/lib/rpmte.c b/lib/rpmte.c
index 7765f70..77385e1 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 */
@@ -226,6 +231,21 @@ 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 (headerIsEntry(h, RPMTAG_COLLECTIONS)) {
+	struct rpmtd_s colls;
+	const char * collname;
+	headerGet(h, RPMTAG_COLLECTIONS, &colls, HEADERGET_MINMEM);
+	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,61 @@ 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);
+}
+
+ARGV_const_t rpmteLastInCollectionAdd(rpmte te)
+{
+	return (te != NULL) ? te->lastInCollectionsAdd : NULL;
+}
+
+ARGV_const_t rpmteLastInCollectionAny(rpmte te)
+{
+	return (te != NULL) ? te->lastInCollectionsAny : NULL;
+}
+
+ARGV_const_t rpmteFirstInCollectionRemove(rpmte te)
+{
+	return (te != NULL) ? te->firstInCollectionsRemove : 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..e167f19 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" {
@@ -107,6 +108,69 @@ rpm_color_t rpmteColor(rpmte te);
 rpm_color_t rpmteSetColor(rpmte te, rpm_color_t color);
 
 /** \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);
+
+/** \ingroup rpmte
+ * Retrieve list of collections that should be executed via post_add
+ * @param te		transaction element
+ * @return		list of collections
+ */
+ARGV_const_t rpmteLastInCollectionAdd(rpmte te);
+
+/** \ingroup rpmte
+ * Retrieve list of collections that should be executed via post_any
+ * @param te		transaction element
+ * @return		list of collections
+ */
+ARGV_const_t rpmteLastInCollectionAny(rpmte te);
+
+/** \ingroup rpmte
+ * Retrieve list of collections that should be executed via pre_remove
+ * @param te		transaction element
+ * @return		list of collections
+ */
+ARGV_const_t rpmteFirstInCollectionRemove(rpmte te);
+
+/** \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
+ */
+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
+ */
+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
+ */
+int rpmteAddToFirstInCollectionRemove(rpmte te, const char * collname);
+
+/** \ingroup rpmte
  * Retrieve last instance installed to the database.
  * @param te		transaction element
  * @return		last install instance.
diff --git a/lib/transaction.c b/lib/transaction.c
index 9881426..4c5cdb3 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -1108,6 +1108,83 @@ 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 +1424,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