diff options
-rw-r--r-- | lib/rpmte.c | 65 | ||||
-rw-r--r-- | lib/rpmte.h | 17 | ||||
-rw-r--r-- | lib/rpmte_internal.h | 31 | ||||
-rw-r--r-- | lib/transaction.c | 81 |
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); |