#3 [f25] Implement with/without rich dependencies
Closed 6 years ago by ignatenkobrain. Opened 6 years ago by ignatenkobrain.
rpms/ ignatenkobrain/rpm f25-rich-with  into  f25

@@ -0,0 +1,69 @@ 

+ From 4eb9844c2b64d1b70da2ce9af34dae8d0e45111a Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Thu, 3 Aug 2017 13:21:49 +0200

+ Subject: [PATCH 1/7] Remove duplicated code in dbiIndexSetAppendSet

+ 

+ Implement dbiIndexSetAppendSet in terms of dbiIndexSetAppend. Also,

+ appending an empty set is not an error.

+ 

+ (cherry picked from commit cb9bbf9d7da7cf1e7fc66cdac0a0cf4549b4e4c7)

+ ---

+  lib/backend/dbiset.c | 33 ++++++++++++++-------------------

+  1 file changed, 14 insertions(+), 19 deletions(-)

+ 

+ diff --git a/lib/backend/dbiset.c b/lib/backend/dbiset.c

+ index ad0114e6e..290a9ba5e 100644

+ --- a/lib/backend/dbiset.c

+ +++ b/lib/backend/dbiset.c

+ @@ -75,30 +75,17 @@ void dbiIndexSetUniq(dbiIndexSet set, int sorted)

+      }

+  }

+  

+ -int dbiIndexSetAppendSet(dbiIndexSet dest, dbiIndexSet src, int sortset)

+ -{

+ -    if (dest == NULL || src == NULL || src->count == 0)

+ -	return 1;

+ -

+ -    dbiIndexSetGrow(dest, src->count);

+ -    memcpy(dest->recs + dest->count,

+ -	   src->recs, src->count * sizeof(*src->recs));

+ -    dest->count += src->count;

+ -

+ -    if (sortset && dest->count > 1)

+ -	qsort(dest->recs, dest->count, sizeof(*(dest->recs)), hdrNumCmp);

+ -    return 0;

+ -}

+ -

+  int dbiIndexSetAppend(dbiIndexSet set, dbiIndexItem recs,

+  		      unsigned int nrecs, int sortset)

+  {

+ -    if (set == NULL || recs == NULL || nrecs == 0)

+ +    if (set == NULL || recs == NULL)

+  	return 1;

+  

+ -    dbiIndexSetGrow(set, nrecs);

+ -    memcpy(set->recs + set->count, recs, nrecs * sizeof(*(set->recs)));

+ -    set->count += nrecs;

+ +    if (nrecs) {

+ +	dbiIndexSetGrow(set, nrecs);

+ +	memcpy(set->recs + set->count, recs, nrecs * sizeof(*(set->recs)));

+ +	set->count += nrecs;

+ +    }

+      

+      if (sortset && set->count > 1)

+  	qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);

+ @@ -106,6 +93,14 @@ int dbiIndexSetAppend(dbiIndexSet set, dbiIndexItem recs,

+      return 0;

+  }

+  

+ +int dbiIndexSetAppendSet(dbiIndexSet set, dbiIndexSet oset, int sortset)

+ +{

+ +    if (oset == NULL)

+ +	return 1;

+ +    return dbiIndexSetAppend(set, oset->recs, oset->count, sortset);

+ +}

+ +

+ +

+  int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,

+  		     unsigned int nrecs, int sorted)

+  {

@@ -0,0 +1,95 @@ 

+ From bcd7ad2e190597c3854c808100a188320121cb34 Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Thu, 3 Aug 2017 13:29:10 +0200

+ Subject: [PATCH 2/7] Add dbiIndexSetAppendOne helper

+ 

+ Easier to use and faster than creating a record and using dbiIndexSetAppend.

+ 

+ (cherry picked from commit a0e92e8b1f00ec3520a08279c59e9af1c97ca953)

+ ---

+  lib/backend/dbiset.c | 16 ++++++++++++++++

+  lib/backend/dbiset.h | 12 ++++++++++++

+  lib/rpmdb.c          | 13 ++++---------

+  3 files changed, 32 insertions(+), 9 deletions(-)

+ 

+ diff --git a/lib/backend/dbiset.c b/lib/backend/dbiset.c

+ index 290a9ba5e..9ad143f28 100644

+ --- a/lib/backend/dbiset.c

+ +++ b/lib/backend/dbiset.c

+ @@ -100,6 +100,22 @@ int dbiIndexSetAppendSet(dbiIndexSet set, dbiIndexSet oset, int sortset)

+      return dbiIndexSetAppend(set, oset->recs, oset->count, sortset);

+  }

+  

+ +int dbiIndexSetAppendOne(dbiIndexSet set, unsigned int hdrNum,

+ +			 unsigned int tagNum, int sortset)

+ +{

+ +    if (set == NULL)

+ +	return 1;

+ +    dbiIndexSetGrow(set, 1);

+ +

+ +    set->recs[set->count].hdrNum = hdrNum;

+ +    set->recs[set->count].tagNum = tagNum;

+ +    set->count += 1;

+ +

+ +    if (sortset && set->count > 1)

+ +	qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);

+ +

+ +    return 0;

+ +}

+  

+  int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,

+  		     unsigned int nrecs, int sorted)

+ diff --git a/lib/backend/dbiset.h b/lib/backend/dbiset.h

+ index 7b106ba15..88182d24a 100644

+ --- a/lib/backend/dbiset.h

+ +++ b/lib/backend/dbiset.h

+ @@ -52,6 +52,18 @@ RPM_GNUC_INTERNAL

+  int dbiIndexSetAppend(dbiIndexSet set, dbiIndexItem recs,

+  		      unsigned int nrecs, int sortset);

+  

+ +/**

+ +  * Append a single element to a set of index database items.

+ +  * @param set          set of index database items

+ +  * @param hdrNum       header instance in db

+ +  * @param tagNum       tag index in header

+ +  * @param sortset      should resulting set be sorted?

+ +  * @return             0 success, 1 failure (bad args)

+ +  */

+ +RPM_GNUC_INTERNAL

+ +int dbiIndexSetAppendOne(dbiIndexSet set, unsigned int hdrNum,

+ +			 unsigned int tagNum, int sortset);

+ +

+  /**

+   * Remove element(s) from set of index database items.

+   * @param set		set of index database items

+ diff --git a/lib/rpmdb.c b/lib/rpmdb.c

+ index c6718ab43..9469ede33 100644

+ --- a/lib/rpmdb.c

+ +++ b/lib/rpmdb.c

+ @@ -734,11 +734,8 @@ static rpmRC rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,

+  	    if (!skip) {

+  		const char *dirName = dirNames[dirIndexes[num]];

+  		if (fpLookupEquals(fpc, fp1, dirName, baseNames[num])) {

+ -		    struct dbiIndexItem_s rec = { 

+ -			.hdrNum = dbiIndexRecordOffset(allMatches, i),

+ -			.tagNum = dbiIndexRecordFileNumber(allMatches, i),

+ -		    };

+ -		    dbiIndexSetAppend(*matches, &rec, 1, 0);

+ +		    dbiIndexSetAppendOne(*matches, dbiIndexRecordOffset(allMatches, i),

+ +					 dbiIndexRecordFileNumber(allMatches, i), 0);

+  		}

+  	    }

+  

+ @@ -1712,10 +1709,8 @@ int rpmdbAppendIterator(rpmdbMatchIterator mi,

+      if (mi->mi_set == NULL)

+  	mi->mi_set = dbiIndexSetNew(nHdrNums);

+  

+ -    for (unsigned int i = 0; i < nHdrNums; i++) {

+ -	struct dbiIndexItem_s rec = { .hdrNum = hdrNums[i], .tagNum = 0 };

+ -	dbiIndexSetAppend(mi->mi_set, &rec, 1, 0);

+ -    }

+ +    for (unsigned int i = 0; i < nHdrNums; i++)

+ +	dbiIndexSetAppendOne(mi->mi_set, hdrNums[i], 0, 0);

+      return 0;

+  }

+  

@@ -0,0 +1,63 @@ 

+ From 337956ea0fe6d50cf6b4eaf21604a0878dd38c6b Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Thu, 3 Aug 2017 13:34:59 +0200

+ Subject: [PATCH 3/7] Add dbiIndexSetPruneSet helper

+ 

+ Also make pruning from an empty set non-fatal.

+ 

+ (cherry picked from commit 8d54160ecea351e5b5ef055ceb1378cb6adaf8e4)

+ ---

+  lib/backend/dbiset.c | 11 ++++++++++-

+  lib/backend/dbiset.h | 10 ++++++++++

+  2 files changed, 20 insertions(+), 1 deletion(-)

+ 

+ diff --git a/lib/backend/dbiset.c b/lib/backend/dbiset.c

+ index 9ad143f28..649ea8866 100644

+ --- a/lib/backend/dbiset.c

+ +++ b/lib/backend/dbiset.c

+ @@ -126,7 +126,9 @@ int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,

+      unsigned int numCopied = 0;

+      size_t recsize = sizeof(*recs);

+  

+ -    assert(set->count > 0);

+ +    if (num == 0 || nrecs == 0)

+ +	return 1;

+ +

+      if (nrecs > 1 && !sorted)

+  	qsort(recs, nrecs, recsize, hdrNumCmp);

+  

+ @@ -143,6 +145,13 @@ int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,

+      return (numCopied == num);

+  }

+  

+ +int dbiIndexSetPruneSet(dbiIndexSet set, dbiIndexSet oset, int sortset)

+ +{

+ +    if (oset == NULL)

+ +	return 1;

+ +    return dbiIndexSetPrune(set, oset->recs, oset->count, sortset);

+ +}

+ +

+  unsigned int dbiIndexSetCount(dbiIndexSet set)

+  {

+      return (set != NULL) ? set->count : 0;

+ diff --git a/lib/backend/dbiset.h b/lib/backend/dbiset.h

+ index 88182d24a..506375865 100644

+ --- a/lib/backend/dbiset.h

+ +++ b/lib/backend/dbiset.h

+ @@ -76,6 +76,16 @@ RPM_GNUC_INTERNAL

+  int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,

+  		     unsigned int nrecs, int sorted);

+  

+ +/**

+ + * Remove an index set from another.

+ + * @param set          set of index database items

+ + * @param oset         set of entries that should be removed

+ + * @param sorted       oset is already sorted?

+ + * @return             0 success, 1 failure (no items found)

+ + */

+ +RPM_GNUC_INTERNAL

+ +int dbiIndexSetPruneSet(dbiIndexSet set, dbiIndexSet oset, int sorted);

+ +

+  /* Count items in index database set. */

+  RPM_GNUC_INTERNAL

+  unsigned int dbiIndexSetCount(dbiIndexSet set);

@@ -0,0 +1,90 @@ 

+ From cfdc5a4e29b305bc66bd5ca640bf82cd5f29e3dd Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Thu, 3 Aug 2017 13:41:31 +0200

+ Subject: [PATCH 4/7] Add dbiIndexSetFilter and dbiIndexSetFilterSet methods

+ 

+ They will be used to resolve "with" rich dependencies.

+ 

+ (cherry picked from commit 8a06ede5139abd621b7d4734e5206dd97c763d41)

+ ---

+  lib/backend/dbiset.c | 33 +++++++++++++++++++++++++++++++++

+  lib/backend/dbiset.h | 22 ++++++++++++++++++++++

+  2 files changed, 55 insertions(+)

+ 

+ diff --git a/lib/backend/dbiset.c b/lib/backend/dbiset.c

+ index 649ea8866..0ac514582 100644

+ --- a/lib/backend/dbiset.c

+ +++ b/lib/backend/dbiset.c

+ @@ -152,6 +152,39 @@ int dbiIndexSetPruneSet(dbiIndexSet set, dbiIndexSet oset, int sortset)

+      return dbiIndexSetPrune(set, oset->recs, oset->count, sortset);

+  }

+  

+ +int dbiIndexSetFilter(dbiIndexSet set, dbiIndexItem recs,

+ +                        unsigned int nrecs, int sorted)

+ +{

+ +    unsigned int from;

+ +    unsigned int to = 0;

+ +    unsigned int num = set->count;

+ +    unsigned int numCopied = 0;

+ +    size_t recsize = sizeof(*recs);

+ +

+ +    if (num == 0 || nrecs == 0) {

+ +	set->count = 0;

+ +	return num ? 0 : 1;

+ +    }

+ +    if (nrecs > 1 && !sorted)

+ +	qsort(recs, nrecs, recsize, hdrNumCmp);

+ +    for (from = 0; from < num; from++) {

+ +	if (!bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {

+ +	    set->count--;

+ +	    continue;

+ +	}

+ +	if (from != to)

+ +	    set->recs[to] = set->recs[from]; /* structure assignment */

+ +	to++;

+ +	numCopied++;

+ +    }

+ +    return (numCopied == num);

+ +}

+ +

+ +int dbiIndexSetFilterSet(dbiIndexSet set, dbiIndexSet oset, int sorted)

+ +{

+ +    return dbiIndexSetFilter(set, oset->recs, oset->count, sorted);

+ +}

+ +

+  unsigned int dbiIndexSetCount(dbiIndexSet set)

+  {

+      return (set != NULL) ? set->count : 0;

+ diff --git a/lib/backend/dbiset.h b/lib/backend/dbiset.h

+ index 506375865..da196c865 100644

+ --- a/lib/backend/dbiset.h

+ +++ b/lib/backend/dbiset.h

+ @@ -86,6 +86,28 @@ int dbiIndexSetPrune(dbiIndexSet set, dbiIndexItem recs,

+  RPM_GNUC_INTERNAL

+  int dbiIndexSetPruneSet(dbiIndexSet set, dbiIndexSet oset, int sorted);

+  

+ +/**

+ + * Filter element(s) from set of index database items.

+ + * @param set          set of index database items

+ + * @param recs         array of items to remove from set

+ + * @param nrecs                number of items

+ + * @param sorted       recs array is already sorted?

+ + * @return             0 success, 1 failure (no items removed)

+ + */

+ +RPM_GNUC_INTERNAL

+ +int dbiIndexSetFilter(dbiIndexSet set, dbiIndexItem recs,

+ +		      unsigned int nrecs, int sorted);

+ +

+ +/**

+ + * Filter (intersect) an index set with another.

+ + * @param set          set of index database items

+ + * @param oset         set of entries that should be intersected

+ + * @param sorted       oset is already sorted?

+ + * @return             0 success, 1 failure (no items removed)

+ + */

+ +RPM_GNUC_INTERNAL

+ +int dbiIndexSetFilterSet(dbiIndexSet set, dbiIndexSet oset, int sorted);

+ +

+  /* Count items in index database set. */

+  RPM_GNUC_INTERNAL

+  unsigned int dbiIndexSetCount(dbiIndexSet set);

@@ -0,0 +1,52 @@ 

+ From 21d8190794c962399ef77e522ab7e5b5da06a4ba Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Thu, 3 Aug 2017 13:45:02 +0200

+ Subject: [PATCH 5/7] Change hdrNumCmp to use the tagNum as secondary sort key

+ 

+ This brings rpmdbSortIterator in line with its documentation.

+ 

+ Note that there is a catch: this change also makes the dbiIndexSetPrune

+ function work different! It used to delete all items that had a

+ matching hdrNum, after the change only the one is deleted that also

+ has a matching tagNum. I consider this a bug fix.

+ Note that dbiIndexSetPrune is only used in the db3.c backend to remove

+ index entires, if we really want the old behavior we should add a

+ new dbiIndexSetPruneHdrnum function.

+ 

+ Also remove assertion when trying to sort an empty set.

+ 

+ (cherry picked from commit eb6b13f9a75ba744c88f5a74f183a210554a5c0c)

+ ---

+  lib/backend/dbiset.c | 10 ++++++----

+  1 file changed, 6 insertions(+), 4 deletions(-)

+ 

+ diff --git a/lib/backend/dbiset.c b/lib/backend/dbiset.c

+ index 0ac514582..8fb922ef7 100644

+ --- a/lib/backend/dbiset.c

+ +++ b/lib/backend/dbiset.c

+ @@ -31,11 +31,12 @@ void dbiIndexSetGrow(dbiIndexSet set, unsigned int nrecs)

+      }

+  }

+  

+ -/* XXX assumes hdrNum is first int in dbiIndexItem */

+  static int hdrNumCmp(const void * one, const void * two)

+  {

+ -    const unsigned int * a = one, * b = two;

+ -    return (*a - *b);

+ +    const struct dbiIndexItem_s *a = one, *b = two;

+ +    if (a->hdrNum - b->hdrNum != 0)

+ +	return a->hdrNum - b->hdrNum;

+ +    return a->tagNum - b->tagNum;

+  }

+  

+  void dbiIndexSetSort(dbiIndexSet set)

+ @@ -59,7 +60,8 @@ void dbiIndexSetUniq(dbiIndexSet set, int sorted)

+      unsigned int to = 0;

+      unsigned int num = set->count;

+  

+ -    assert(set->count > 0);

+ +    if (set->count < 2)

+ +	return;

+  

+      if (!sorted)

+  	dbiIndexSetSort(set);

@@ -0,0 +1,53 @@ 

+ From 6f3768b19020b0696f9c8c014cd5c63c317a20c6 Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Thu, 3 Aug 2017 13:53:04 +0200

+ Subject: [PATCH 6/7] Add rpmalLookupTE helper

+ 

+ It returns the index of a transaction element in the available

+ packages list, or (unsigned int)-1 if not fould.

+ 

+ (cherry picked from commit 87b8b19eba9207d6c4d30793bec5a2b8044ecadb)

+ ---

+  lib/rpmal.c | 11 +++++++++++

+  lib/rpmal.h |  9 +++++++++

+  2 files changed, 20 insertions(+)

+ 

+ diff --git a/lib/rpmal.c b/lib/rpmal.c

+ index 8f61c8e64..ca7ab053e 100644

+ --- a/lib/rpmal.c

+ +++ b/lib/rpmal.c

+ @@ -564,3 +564,14 @@ rpmalSatisfiesDepend(const rpmal al, const rpmte te, const rpmds ds)

+      }

+      return best;

+  }

+ +

+ +unsigned int

+ +rpmalLookupTE(const rpmal al, const rpmte te)

+ +{

+ +    rpmalNum pkgNum;

+ +    for (pkgNum=0; pkgNum < al->size; pkgNum++)

+ +	if (al->list[pkgNum].p == te)

+ +	    break;

+ +    return pkgNum < al->size ? pkgNum : (unsigned int)-1;

+ +}

+ +

+ diff --git a/lib/rpmal.h b/lib/rpmal.h

+ index 3c6a833d3..10fe756d4 100644

+ --- a/lib/rpmal.h

+ +++ b/lib/rpmal.h

+ @@ -80,6 +80,15 @@ rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds);

+  RPM_GNUC_INTERNAL

+  rpmte rpmalSatisfiesDepend(const rpmal al, const rpmte te, const rpmds ds);

+  

+ +/**

+ + * Return index of a transaction element  in the available list

+ + * @param al           available list

+ + * @param te           transaction element

+ + * @return             index, (unsigned int)-1 if not found

+ + */

+ +RPM_GNUC_INTERNAL

+ +unsigned int rpmalLookupTE(const rpmal al, const rpmte te);

+ +

+  #ifdef __cplusplus

+  }

+  #endif

@@ -0,0 +1,306 @@ 

+ From c3ec27e58d9eb24919945eb7690fb02c8e5a4b6e Mon Sep 17 00:00:00 2001

+ From: Michael Schroeder <mls@suse.de>

+ Date: Thu, 3 Aug 2017 14:06:33 +0200

+ Subject: [PATCH 7/7] Implement with/without rich dependencies

+ 

+ Unlike the other rich rependencies they work by evaluating package

+ sets. This means, "Requires: (foo with bar)" is only fulfilled

+ by a package that provides both foo and bar. In comparison,

+ "Requires: (foo and bar)" can be fulfilled by two different

+ packages.

+ 

+ Without implements set subtraction, e.g. "Requires: (foo without bar)"

+ is only fulfilled by a package that provides foo but not bar.

+ 

+ (cherry picked from commit dac1c702562f57bd7ab080172d7e228cda25a819)

+ ---

+  lib/depends.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---

+  lib/rpmds.c   | 35 ++++++++++++++++-----

+  lib/rpmds.h   | 12 +++++---

+  3 files changed, 128 insertions(+), 17 deletions(-)

+ 

+ diff --git a/lib/depends.c b/lib/depends.c

+ index fc413a903..c73e64953 100644

+ --- a/lib/depends.c

+ +++ b/lib/depends.c

+ @@ -17,6 +17,8 @@

+  #include "lib/rpmfi_internal.h" /* rpmfiles stuff for now */

+  #include "lib/misc.h"

+  

+ +#include "lib/backend/dbiset.h"

+ +

+  #include "debug.h"

+  

+  const char * const RPMVERSION = VERSION;

+ @@ -510,7 +512,7 @@ int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)

+  }

+  

+  /* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */

+ -static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)

+ +static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep, dbiIndexSet *matches)

+  {

+      const char * Name = rpmdsN(dep);

+      const char * DNEVR = rpmdsDNEVR(dep);

+ @@ -524,7 +526,7 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)

+      unsigned int keyhash = 0;

+  

+      /* See if we already looked this up */

+ -    if (prune) {

+ +    if (prune && !matches) {

+  	keyhash = depCacheKeyHash(dcache, DNEVR);

+  	if (depCacheGetHEntry(dcache, DNEVR, keyhash, &cachedrc, NULL, NULL)) {

+  	    rc = *cachedrc;

+ @@ -533,6 +535,8 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)

+  	}

+      }

+  

+ +    if (matches)

+ +	*matches = dbiIndexSetNew(0);

+      /*

+       * See if a filename dependency is a real file in some package,

+       * taking file state into account: replaced, wrong colored and

+ @@ -547,6 +551,10 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)

+  		if (instance && instance == rpmdsInstance(dep))

+  		    continue;

+  	    }

+ +	    if (matches) {

+ +		dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);

+ +		continue;

+ +	    }

+  	    rpmdsNotify(dep, "(db files)", rc);

+  	    break;

+  	}

+ @@ -577,6 +585,10 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)

+  		    match = 0;

+  	    }

+  	    if (match) {

+ +		if (matches) {

+ +		    dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);

+ +		    continue;

+ +		}

+  		rpmdsNotify(dep, "(db provides)", rc);

+  		break;

+  	    }

+ @@ -585,13 +597,81 @@ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep)

+      }

+      rc = (h != NULL) ? 0 : 1;

+  

+ +    if (matches) {

+ +	dbiIndexSetUniq(*matches, 0);

+ +	rc = dbiIndexSetCount(*matches) ? 0 : 1;

+ +    }

+ +

+      /* Cache the relatively expensive rpmdb lookup results */

+      /* Caching the oddball non-pruned case would mess up other results */

+ -    if (prune)

+ +    if (prune && !matches)

+  	depCacheAddHEntry(dcache, xstrdup(DNEVR), keyhash, rc);

+      return rc;

+  }

+  

+ +static dbiIndexSet unsatisfiedDependSet(rpmts ts, rpmds dep)

+ +{

+ +    dbiIndexSet set1 = NULL, set2 = NULL;

+ +    tsMembers tsmem = rpmtsMembers(ts);

+ +    rpmsenseFlags dsflags = rpmdsFlags(dep);

+ +

+ +    if (dsflags & RPMSENSE_RPMLIB)

+ +	goto exit;

+ +

+ +    if (rpmdsIsRich(dep)) {

+ +	rpmds ds1, ds2; 

+ +	rpmrichOp op;

+ +	char *emsg = 0; 

+ +

+ +	if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {

+ +	    rpmdsNotify(dep, emsg ? emsg : "(parse error)", 1);  

+ +	    _free(emsg);

+ +	    goto exit;

+ +	}

+ +	/* only a subset of ops is supported in set mode */

+ +	if (op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT

+ +            && op != RPMRICHOP_OR && op != RPMRICHOP_SINGLE) {

+ +	    rpmdsNotify(dep, "(unsupported op in set mode)", 1);  

+ +	    goto exit_rich;

+ +	}

+ +

+ +	set1 = unsatisfiedDependSet(ts, ds1);

+ +	if (op == RPMRICHOP_SINGLE)

+ +	    goto exit_rich;

+ +	if (op != RPMRICHOP_OR && dbiIndexSetCount(set1) == 0)

+ +	    goto exit_rich;

+ +	set2 = unsatisfiedDependSet(ts, ds2);

+ +	if (op == RPMRICHOP_WITH) {

+ +	    dbiIndexSetFilterSet(set1, set2, 0);

+ +	} else if (op == RPMRICHOP_WITHOUT) {

+ +	    dbiIndexSetPruneSet(set1, set2, 0);

+ +	} else if (op == RPMRICHOP_OR) {

+ +	    dbiIndexSetAppendSet(set1, set2, 0);

+ +	}

+ +exit_rich:

+ +	ds1 = rpmdsFree(ds1);

+ +	ds2 = rpmdsFree(ds2);

+ +	goto exit;

+ +    }

+ +

+ +    /* match database entries */

+ +    rpmdbProvides(ts, NULL, dep, &set1);

+ +

+ +    /* Pretrans dependencies can't be satisfied by added packages. */

+ +    if (!(dsflags & RPMSENSE_PRETRANS)) {

+ +	rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);

+ +	if (matches) {

+ +	    for (rpmte *p = matches; *p; p++)

+ +		dbiIndexSetAppendOne(set1, rpmalLookupTE(tsmem->addedPackages, *p), 1, 0);

+ +	}

+ +	_free(matches);

+ +    }

+ +

+ +exit:

+ +    set2 = dbiIndexSetFree(set2);

+ +    return set1 ? set1 : dbiIndexSetNew(0);

+ +}

+ +

+  /**

+   * Check dep for an unsatisfied dependency.

+   * @param ts		transaction set

+ @@ -643,6 +723,16 @@ retry:

+  	    _free(emsg);

+  	    goto exit;

+  	}

+ +	if (op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) {

+ +	    /* switch to set mode processing */

+ +	    dbiIndexSet set = unsatisfiedDependSet(ts, dep);

+ +	    rc = dbiIndexSetCount(set) ? 0 : 1;

+ +	    dbiIndexSetFree(set);

+ +	    ds1 = rpmdsFree(ds1);

+ +	    ds2 = rpmdsFree(ds2);

+ +	    rpmdsNotify(dep, "(rich)", rc);

+ +	    goto exit;

+ +	}

+  	if (op == RPMRICHOP_IF) {

+  	    if (rpmdsIsRich(ds2)) {

+  		/* check if this is a IF...ELSE combination */

+ @@ -683,7 +773,7 @@ retry:

+      }

+  

+      /* See if the rpmdb provides it */

+ -    if (rpmdbProvides(ts, dcache, dep) == 0)

+ +    if (rpmdbProvides(ts, dcache, dep, NULL) == 0)

+  	goto exit;

+  

+      /* Search for an unsatisfied dependency. */

+ diff --git a/lib/rpmds.c b/lib/rpmds.c

+ index ba6e24448..be788d7e2 100644

+ --- a/lib/rpmds.c

+ +++ b/lib/rpmds.c

+ @@ -1354,10 +1354,12 @@ static struct RichOpComp {

+      const char * token;

+      rpmrichOp op;

+  } const RichOps[] = { 

+ -    { "and",	RPMRICHOP_AND},

+ -    { "or",	RPMRICHOP_OR},

+ -    { "if",	RPMRICHOP_IF},

+ -    { "else",	RPMRICHOP_ELSE},

+ +    { "and",	 RPMRICHOP_AND},

+ +    { "or",	 RPMRICHOP_OR},

+ +    { "if",	 RPMRICHOP_IF},

+ +    { "else",	 RPMRICHOP_ELSE},

+ +    { "with",	 RPMRICHOP_WITH},

+ +    { "without", RPMRICHOP_WITHOUT},

+      { NULL, 0 },

+  };

+  

+ @@ -1397,6 +1399,10 @@ const char *rpmrichOpStr(rpmrichOp op)

+  	return "if";

+      if (op == RPMRICHOP_ELSE)

+  	return "else";

+ +    if (op == RPMRICHOP_WITH)

+ +	return "with";

+ +    if (op == RPMRICHOP_WITHOUT)

+ +	return "without";

+      return NULL;

+  }

+  

+ @@ -1444,10 +1450,11 @@ static rpmRC parseSimpleDep(const char **dstrp, char **emsg, rpmrichParseFunctio

+      return RPMRC_OK;

+  }

+  

+ -rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)

+ +static rpmRC rpmrichParseInternal(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata, int *nowithp)

+  {

+      const char *p = *dstrp, *pe;

+      rpmrichOp op = RPMRICHOP_SINGLE, chainop = 0;

+ +    int nowith = 0;

+  

+      if (cb(cbdata, RPMRICH_PARSE_ENTER, p, 0, 0, 0, 0, op, emsg) != RPMRC_OK)

+          return RPMRC_FAIL;

+ @@ -1468,7 +1475,7 @@ rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, voi

+              return RPMRC_FAIL;

+          }

+          if (*p == '(') {

+ -            if (rpmrichParse(&p, emsg, cb, cbdata) != RPMRC_OK)

+ +            if (rpmrichParseInternal(&p, emsg, cb, cbdata, &nowith) != RPMRC_OK)

+                  return RPMRC_FAIL;

+          } else {

+              if (parseSimpleDep(&p, emsg, cb, cbdata) != RPMRC_OK)

+ @@ -1492,15 +1499,23 @@ rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, voi

+                  rasprintf(emsg, _("Cannot chain different ops"));

+              return RPMRC_FAIL;

+          }

+ -        if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR) {

+ +        if (chainop && op != RPMRICHOP_AND && op != RPMRICHOP_OR &&

+ +	    op != RPMRICHOP_WITH) {

+              if (emsg)

+ -                rasprintf(emsg, _("Can only chain AND and OR ops"));

+ +                rasprintf(emsg, _("Can only chain and/or/with ops"));

+              return RPMRC_FAIL;

+  	}

+          if (cb(cbdata, RPMRICH_PARSE_OP, p, pe - p, 0, 0, 0, op, emsg) != RPMRC_OK)

+              return RPMRC_FAIL;

+          chainop = op;

+          p = pe;

+ +	if (nowithp && op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT && op != RPMRICHOP_OR)

+ +	    *nowithp = 1;

+ +    }

+ +    if ((op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) && nowith) {

+ +	if (emsg)

+ +	    rasprintf(emsg, _("Illegal ops in with/without"));

+ +	return RPMRC_FAIL;

+      }

+      p++;

+      if (cb(cbdata, RPMRICH_PARSE_LEAVE, *dstrp, p - *dstrp , 0, 0, 0, op, emsg) != RPMRC_OK)

+ @@ -1509,6 +1524,10 @@ rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, voi

+      return RPMRC_OK;

+  }

+  

+ +rpmRC rpmrichParse(const char **dstrp, char **emsg, rpmrichParseFunction cb, void *cbdata)

+ +{

+ +    return rpmrichParseInternal(dstrp, emsg, cb, cbdata, NULL);

+ +}

+  

+  struct rpmdsParseRichDepData {

+      rpmds dep;

+ diff --git a/lib/rpmds.h b/lib/rpmds.h

+ index a113609ae..8f1c0c3ef 100644

+ --- a/lib/rpmds.h

+ +++ b/lib/rpmds.h

+ @@ -464,11 +464,13 @@ int rpmdsRpmlibPool(rpmstrPool pool, rpmds * dsp, const void * tblp);

+  

+  

+  typedef enum rpmrichOp_e {

+ -    RPMRICHOP_SINGLE = 1,

+ -    RPMRICHOP_AND    = 2,

+ -    RPMRICHOP_OR     = 3,

+ -    RPMRICHOP_IF     = 4,

+ -    RPMRICHOP_ELSE   = 5

+ +    RPMRICHOP_SINGLE  = 1,

+ +    RPMRICHOP_AND     = 2,

+ +    RPMRICHOP_OR      = 3,

+ +    RPMRICHOP_IF      = 4,

+ +    RPMRICHOP_ELSE    = 5,

+ +    RPMRICHOP_WITH    = 6,

+ +    RPMRICHOP_WITHOUT = 7

+  } rpmrichOp;

+  

+  typedef enum rpmrichParseType_e {

file modified
+12 -1
@@ -29,7 +29,7 @@ 

  Summary: The RPM package management system

  Name: rpm

  Version: %{rpmver}

- Release: %{?snapver:0.%{snapver}.}2%{?dist}

+ Release: %{?snapver:0.%{snapver}.}3%{?dist}

  Group: System Environment/Base

  Url: http://www.rpm.org/

  Source0: http://rpm.org/releases/%{srcdir}/%{name}-%{srcver}.tar.bz2
@@ -67,6 +67,14 @@ 

  # Upstream PR: https://github.com/rpm-software-management/rpm/pull/154

  # rhbz#1421776

  Patch141: rpm-4.13.x-pythondistdeps.py-fix-processing-wheels.patch

+ # WITH/WITHOUT richop, https://github.com/rpm-software-management/rpm/pull/299

+ Patch151: 0001-Remove-duplicated-code-in-dbiIndexSetAppendSet.patch

+ Patch152: 0002-Add-dbiIndexSetAppendOne-helper.patch

+ Patch153: 0003-Add-dbiIndexSetPruneSet-helper.patch

+ Patch154: 0004-Add-dbiIndexSetFilter-and-dbiIndexSetFilterSet-metho.patch

+ Patch155: 0005-Change-hdrNumCmp-to-use-the-tagNum-as-secondary-sort.patch

+ Patch156: 0006-Add-rpmalLookupTE-helper.patch

+ Patch157: 0007-Implement-with-without-rich-dependencies.patch

  

  # These are not yet upstream

  Patch302: rpm-4.7.1-geode-i686.patch
@@ -564,6 +572,9 @@ 

  %doc doc/librpm/html/*

  

  %changelog

+ * Fri Aug 25 2017 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 4.13.0.1-3

+ - Backport with/without rich operators

+ 

  * Wed Aug 16 2017 Panu Matilainen <pmatilai@redhat.com> - 4.13.0.1-2

  - Really ignore unknown tags in the signature header (#1480492)

  - Fix rpmsign python module import failing (#1462671)