summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/rpmte.c65
-rw-r--r--lib/rpmte.h17
-rw-r--r--lib/rpmte_internal.h31
-rw-r--r--lib/transaction.c81
4 files changed, 194 insertions, 0 deletions
diff --git a/lib/rpmte.c b/lib/rpmte.c
index e622558ed..2c3360558 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -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);
diff --git a/lib/rpmte.h b/lib/rpmte.h
index 0d1fc8d95..17854d7e4 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 0aa78b245..242586849 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 9881426be..5202ee2e5 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);