From: Michael Schroeder Date: Tue, 29 Jul 2025 13:34:09 +0000 (+0200) Subject: Move dependency matching from pool.c to pooldep.c X-Git-Tag: 0.7.35~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ab5d8e3f1f8535af3ad0d016818cf980fec6d7dc;p=thirdparty%2Flibsolv.git Move dependency matching from pool.c to pooldep.c --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f11d555a..812abe6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,7 +14,7 @@ ENDIF (HAVE___QSORT_R) ADD_DEFINITIONS (-DLIBSOLV_INTERNAL=1) SET (libsolv_SRCS - bitmap.c poolarch.c poolvendor.c poolid.c + bitmap.c poolarch.c poolvendor.c poolid.c pooldep.c poolwhatprovides.c pool.c strpool.c dirpool.c solver.c solverdebug.c repo_solv.c repo_write.c evr.c queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c diff --git a/src/pool.c b/src/pool.c index 4c4c4625..a82b1500 100644 --- a/src/pool.c +++ b/src/pool.c @@ -27,9 +27,6 @@ #include "util.h" #include "bitmap.h" #include "evr.h" -#ifdef ENABLE_CONDA -#include "conda.h" -#endif #define SOLVABLE_BLOCK 255 @@ -295,7 +292,6 @@ pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids) memset(pool->solvables + start, 0, sizeof(Solvable) * count); } - void pool_set_installed(Pool *pool, Repo *installed) { @@ -305,336 +301,6 @@ pool_set_installed(Pool *pool, Repo *installed) pool_freewhatprovides(pool); } - -/*************************************************************************/ - -#if defined(HAIKU) || defined(MULTI_SEMANTICS) -/* forward declaration */ -static int pool_intersect_evrs_rel_compat(Pool *pool, Reldep *range, int flags, int evr); -#endif - -#if defined(MULTI_SEMANTICS) -# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE) -#elif defined(DEBIAN) -# define EVRCMP_DEPCMP EVRCMP_COMPARE -#else -# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE -#endif - -/* match (flags, evr) against provider (pflags, pevr) */ -/* note that this code is also in poolwhatprovides */ -int -pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr) -{ - if (!pflags || !flags || pflags >= 8 || flags >= 8) - return 0; - if (flags == 7 || pflags == 7) - return 1; /* rel provides every version */ - if ((pflags & flags & (REL_LT | REL_GT)) != 0) - return 1; /* both rels show in the same direction */ - if (pevr == evr) - return (flags & pflags & REL_EQ) ? 1 : 0; -#if defined(HAIKU) || defined(MULTI_SEMANTICS) - if (ISRELDEP(pevr)) - { - Reldep *rd = GETRELDEP(pool, pevr); - if (rd->flags == REL_COMPAT) - return pool_intersect_evrs_rel_compat(pool, rd, flags, evr); - } -#endif - switch (pool_evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)) - { - case -2: - return (pflags & REL_EQ) ? 1 : 0; - case -1: - return (flags & REL_LT) || (pflags & REL_GT) ? 1 : 0; - case 0: - return (flags & pflags & REL_EQ) ? 1 : 0; - case 1: - return (flags & REL_GT) || (pflags & REL_LT) ? 1 : 0; - case 2: - return (flags & REL_EQ) ? 1 : 0; - default: - break; - } - return 0; -} - -#if defined(HAIKU) || defined(MULTI_SEMANTICS) -static int -pool_intersect_evrs_rel_compat(Pool *pool, Reldep *range, int flags, int evr) -{ - /* range->name is the actual version, range->evr the backwards compatibility - version. If flags are '>=' or '>', we match the compatibility version - as well, otherwise only the actual version. */ - if (!(flags & REL_GT) || (flags & REL_LT)) - return pool_intersect_evrs(pool, REL_EQ, range->name, flags, evr); - return pool_intersect_evrs(pool, REL_LT | REL_EQ, range->name, flags, evr) && - pool_intersect_evrs(pool, REL_GT | REL_EQ, range->evr, REL_EQ, evr); -} -#endif - -/* check if a package's nevr matches a dependency */ -/* semi-private, called from public pool_match_nevr */ -int -pool_match_nevr_rel(Pool *pool, Solvable *s, Id d) -{ - Reldep *rd = GETRELDEP(pool, d); - Id name = rd->name; - Id evr = rd->evr; - int flags = rd->flags; - - if (flags > 7) - { - switch (flags) - { - case REL_ARCH: - if (s->arch != evr) - { - if (evr != ARCH_SRC || s->arch != ARCH_NOSRC) - return 0; - } - return pool_match_nevr(pool, s, name); - case REL_OR: - if (pool_match_nevr(pool, s, name)) - return 1; - return pool_match_nevr(pool, s, evr); - case REL_AND: - case REL_WITH: - if (!pool_match_nevr(pool, s, name)) - return 0; - return pool_match_nevr(pool, s, evr); - case REL_WITHOUT: - if (!pool_match_nevr(pool, s, name)) - return 0; - return !pool_match_nevr(pool, s, evr); - case REL_MULTIARCH: - if (evr != ARCH_ANY) - return 0; - /* XXX : need to check for Multi-Arch: allowed! */ - return pool_match_nevr(pool, s, name); - default: - return 0; - } - } - if (!pool_match_nevr(pool, s, name)) - return 0; - if (evr == s->evr) - return (flags & REL_EQ) ? 1 : 0; - if (!flags) - return 0; - if (flags == 7) - return 1; - switch (pool_evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP)) - { - case -2: - return 1; - case -1: - return (flags & REL_LT) ? 1 : 0; - case 0: - return (flags & REL_EQ) ? 1 : 0; - case 1: - return (flags & REL_GT) ? 1 : 0; - case 2: - return (flags & REL_EQ) ? 1 : 0; - default: - break; - } - return 0; -} - -static int -is_interval_dep(Pool *pool, Id d1, Id d2) -{ - Reldep *rd1, *rd2; - if (!ISRELDEP(d1) || !ISRELDEP(d2)) - return 0; - rd1 = GETRELDEP(pool, d1); - rd2 = GETRELDEP(pool, d2); - if (rd1->name != rd2->name || rd1->flags >= 8 || rd2->flags >= 8) - return 0; - if (((rd1->flags ^ rd2->flags) & (REL_LT|REL_GT)) != (REL_LT|REL_GT)) - return 0; - return 1; -} - - -/* match two dependencies (d1 = provider) */ - -int -pool_match_dep(Pool *pool, Id d1, Id d2) -{ - Reldep *rd1, *rd2; - - if (d1 == d2) - return 1; - - if (ISRELDEP(d1)) - { - /* we use potentially matches for complex deps */ - rd1 = GETRELDEP(pool, d1); - if (rd1->flags == REL_AND || rd1->flags == REL_OR || rd1->flags == REL_WITH || rd1->flags == REL_WITHOUT || rd1->flags == REL_COND || rd1->flags == REL_UNLESS) - { - if (rd1->flags == REL_WITH && is_interval_dep(pool, rd1->name, rd1->evr)) - return pool_match_dep(pool, rd1->name, d2) && pool_match_dep(pool, rd1->evr, d2); - if (pool_match_dep(pool, rd1->name, d2)) - return 1; - if ((rd1->flags == REL_COND || rd1->flags == REL_UNLESS) && ISRELDEP(rd1->evr)) - { - rd1 = GETRELDEP(pool, rd1->evr); - if (rd1->flags != REL_ELSE) - return 0; - } - if (rd1->flags != REL_COND && rd1->flags != REL_UNLESS && rd1->flags != REL_WITHOUT && pool_match_dep(pool, rd1->evr, d2)) - return 1; - return 0; - } - } - if (ISRELDEP(d2)) - { - /* we use potentially matches for complex deps */ - rd2 = GETRELDEP(pool, d2); - if (rd2->flags == REL_AND || rd2->flags == REL_OR || rd2->flags == REL_WITH || rd2->flags == REL_WITHOUT || rd2->flags == REL_COND || rd2->flags == REL_UNLESS) - { - if (rd2->flags == REL_WITH && is_interval_dep(pool, rd2->name, rd2->evr)) - return pool_match_dep(pool, d1, rd2->name) && pool_match_dep(pool, d1, rd2->evr); - if (pool_match_dep(pool, d1, rd2->name)) - return 1; - if ((rd2->flags == REL_COND || rd2->flags == REL_UNLESS) && ISRELDEP(rd2->evr)) - { - rd2 = GETRELDEP(pool, rd2->evr); - if (rd2->flags != REL_ELSE) - return 0; - } - if (rd2->flags != REL_COND && rd2->flags != REL_UNLESS && rd2->flags != REL_WITHOUT && pool_match_dep(pool, d1, rd2->evr)) - return 1; - return 0; - } - } - if (!ISRELDEP(d1)) - { - if (!ISRELDEP(d2)) - return 0; /* cannot match as d1 != d2 */ - rd2 = GETRELDEP(pool, d2); - return pool_match_dep(pool, d1, rd2->name); - } - rd1 = GETRELDEP(pool, d1); - if (!ISRELDEP(d2)) - { - return pool_match_dep(pool, rd1->name, d2); - } - rd2 = GETRELDEP(pool, d2); - /* first match name */ - if (!pool_match_dep(pool, rd1->name, rd2->name)) - return 0; - /* name matches, check flags and evr */ - return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr); -} - - -/* intersect dependencies in keyname with dep, return list of matching packages */ -void -pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker) -{ - Id p; - Queue qq; - int i; - - queue_empty(q); - if (keyname == SOLVABLE_NAME) - { - Id pp; - FOR_PROVIDES(p, pp, dep) - if (pool_match_nevr(pool, pool->solvables + p, dep)) - queue_push(q, p); - return; - } - queue_init(&qq); - FOR_POOL_SOLVABLES(p) - { - Solvable *s = pool->solvables + p; - if (s->repo->disabled) - continue; - if (s->repo != pool->installed && !pool_installable(pool, s)) - continue; - if (qq.count) - queue_empty(&qq); - solvable_lookup_deparray(s, keyname, &qq, marker); - for (i = 0; i < qq.count; i++) - if (pool_match_dep(pool, qq.elements[i], dep)) - { - queue_push(q, p); - break; - } - } - queue_free(&qq); -} - -/* check if keyname contains dep, return list of matching packages */ -void -pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker) -{ - Id p; - Queue qq; - int i; - - queue_empty(q); - if (!dep) - return; - queue_init(&qq); - FOR_POOL_SOLVABLES(p) - { - Solvable *s = pool->solvables + p; - if (s->repo->disabled) - continue; - if (s->repo != pool->installed && !pool_installable(pool, s)) - continue; - if (qq.count) - queue_empty(&qq); - solvable_lookup_deparray(s, keyname, &qq, marker); - for (i = 0; i < qq.count; i++) - if (qq.elements[i] == dep) - { - queue_push(q, p); - break; - } - } - queue_free(&qq); -} - -/* intersect dependencies in keyname with all provides of solvable solvid, - * return list of matching packages */ -/* this currently only works for installable packages */ -void -pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker) -{ - Id p; - Queue qq; - Map missc; /* cache for misses */ - int reloff; - - queue_empty(q); - queue_init(&qq); - reloff = pool->ss.nstrings; - map_init(&missc, reloff + pool->nrels); - FOR_POOL_SOLVABLES(p) - { - Solvable *s = pool->solvables + p; - if (p == solvid) - continue; /* filter out self-matches */ - if (s->repo->disabled) - continue; - if (s->repo != pool->installed && !pool_installable(pool, s)) - continue; - if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff, 0)) - queue_push(q, p); - } - map_free(&missc); - queue_free(&qq); -} - -/*************************************************************************/ - void pool_debug(Pool *pool, int type, const char *format, ...) { diff --git a/src/pooldep.c b/src/pooldep.c new file mode 100644 index 00000000..d397c28d --- /dev/null +++ b/src/pooldep.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2025, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * pooldep.c + * + * dependency matching and searching + */ + +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "evr.h" + + +#if defined(MULTI_SEMANTICS) +# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE) +#elif defined(DEBIAN) +# define EVRCMP_DEPCMP EVRCMP_COMPARE +#else +# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE +#endif + + +#if defined(HAIKU) || defined(MULTI_SEMANTICS) +static int +pool_intersect_evrs_rel_compat(Pool *pool, Reldep *range, int flags, int evr) +{ + /* range->name is the actual version, range->evr the backwards compatibility + version. If flags are '>=' or '>', we match the compatibility version + as well, otherwise only the actual version. */ + if (!(flags & REL_GT) || (flags & REL_LT)) + return pool_intersect_evrs(pool, REL_EQ, range->name, flags, evr); + return pool_intersect_evrs(pool, REL_LT | REL_EQ, range->name, flags, evr) && + pool_intersect_evrs(pool, REL_GT | REL_EQ, range->evr, REL_EQ, evr); +} +#endif + +/* match (flags, evr) against provider (pflags, pevr) */ +/* note that this code is also in poolwhatprovides */ +int +pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr) +{ + if (!pflags || !flags || pflags >= 8 || flags >= 8) + return 0; + if (flags == 7 || pflags == 7) + return 1; /* rel provides every version */ + if ((pflags & flags & (REL_LT | REL_GT)) != 0) + return 1; /* both rels show in the same direction */ + if (pevr == evr) + return (flags & pflags & REL_EQ) ? 1 : 0; +#if defined(HAIKU) || defined(MULTI_SEMANTICS) + if (ISRELDEP(pevr)) + { + Reldep *rd = GETRELDEP(pool, pevr); + if (rd->flags == REL_COMPAT) + return pool_intersect_evrs_rel_compat(pool, rd, flags, evr); + } +#endif + switch (pool_evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)) + { + case -2: + return (pflags & REL_EQ) ? 1 : 0; + case -1: + return (flags & REL_LT) || (pflags & REL_GT) ? 1 : 0; + case 0: + return (flags & pflags & REL_EQ) ? 1 : 0; + case 1: + return (flags & REL_GT) || (pflags & REL_LT) ? 1 : 0; + case 2: + return (flags & REL_EQ) ? 1 : 0; + default: + break; + } + return 0; +} + +/* check if a package's nevr matches a dependency */ +/* semi-private, called from public pool_match_nevr */ +int +pool_match_nevr_rel(Pool *pool, Solvable *s, Id d) +{ + Reldep *rd = GETRELDEP(pool, d); + Id name = rd->name; + Id evr = rd->evr; + int flags = rd->flags; + + if (flags > 7) + { + switch (flags) + { + case REL_ARCH: + if (s->arch != evr) + { + if (evr != ARCH_SRC || s->arch != ARCH_NOSRC) + return 0; + } + return pool_match_nevr(pool, s, name); + case REL_OR: + if (pool_match_nevr(pool, s, name)) + return 1; + return pool_match_nevr(pool, s, evr); + case REL_AND: + case REL_WITH: + if (!pool_match_nevr(pool, s, name)) + return 0; + return pool_match_nevr(pool, s, evr); + case REL_WITHOUT: + if (!pool_match_nevr(pool, s, name)) + return 0; + return !pool_match_nevr(pool, s, evr); + case REL_MULTIARCH: + if (evr != ARCH_ANY) + return 0; + /* XXX : need to check for Multi-Arch: allowed! */ + return pool_match_nevr(pool, s, name); + default: + return 0; + } + } + if (!pool_match_nevr(pool, s, name)) + return 0; + if (evr == s->evr) + return (flags & REL_EQ) ? 1 : 0; + if (!flags) + return 0; + if (flags == 7) + return 1; + switch (pool_evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP)) + { + case -2: + return 1; + case -1: + return (flags & REL_LT) ? 1 : 0; + case 0: + return (flags & REL_EQ) ? 1 : 0; + case 1: + return (flags & REL_GT) ? 1 : 0; + case 2: + return (flags & REL_EQ) ? 1 : 0; + default: + break; + } + return 0; +} + +static int +is_interval_dep(Pool *pool, Id d1, Id d2) +{ + Reldep *rd1, *rd2; + if (!ISRELDEP(d1) || !ISRELDEP(d2)) + return 0; + rd1 = GETRELDEP(pool, d1); + rd2 = GETRELDEP(pool, d2); + if (rd1->name != rd2->name || rd1->flags >= 8 || rd2->flags >= 8) + return 0; + if (((rd1->flags ^ rd2->flags) & (REL_LT|REL_GT)) != (REL_LT|REL_GT)) + return 0; + return 1; +} + + +/* match two dependencies (d1 = provider) */ + +int +pool_match_dep(Pool *pool, Id d1, Id d2) +{ + Reldep *rd1, *rd2; + + if (d1 == d2) + return 1; + + if (ISRELDEP(d1)) + { + /* we use potentially matches for complex deps */ + rd1 = GETRELDEP(pool, d1); + if (rd1->flags == REL_AND || rd1->flags == REL_OR || rd1->flags == REL_WITH || rd1->flags == REL_WITHOUT || rd1->flags == REL_COND || rd1->flags == REL_UNLESS) + { + if (rd1->flags == REL_WITH && is_interval_dep(pool, rd1->name, rd1->evr)) + return pool_match_dep(pool, rd1->name, d2) && pool_match_dep(pool, rd1->evr, d2); + if (pool_match_dep(pool, rd1->name, d2)) + return 1; + if ((rd1->flags == REL_COND || rd1->flags == REL_UNLESS) && ISRELDEP(rd1->evr)) + { + rd1 = GETRELDEP(pool, rd1->evr); + if (rd1->flags != REL_ELSE) + return 0; + } + if (rd1->flags != REL_COND && rd1->flags != REL_UNLESS && rd1->flags != REL_WITHOUT && pool_match_dep(pool, rd1->evr, d2)) + return 1; + return 0; + } + } + if (ISRELDEP(d2)) + { + /* we use potentially matches for complex deps */ + rd2 = GETRELDEP(pool, d2); + if (rd2->flags == REL_AND || rd2->flags == REL_OR || rd2->flags == REL_WITH || rd2->flags == REL_WITHOUT || rd2->flags == REL_COND || rd2->flags == REL_UNLESS) + { + if (rd2->flags == REL_WITH && is_interval_dep(pool, rd2->name, rd2->evr)) + return pool_match_dep(pool, d1, rd2->name) && pool_match_dep(pool, d1, rd2->evr); + if (pool_match_dep(pool, d1, rd2->name)) + return 1; + if ((rd2->flags == REL_COND || rd2->flags == REL_UNLESS) && ISRELDEP(rd2->evr)) + { + rd2 = GETRELDEP(pool, rd2->evr); + if (rd2->flags != REL_ELSE) + return 0; + } + if (rd2->flags != REL_COND && rd2->flags != REL_UNLESS && rd2->flags != REL_WITHOUT && pool_match_dep(pool, d1, rd2->evr)) + return 1; + return 0; + } + } + if (!ISRELDEP(d1)) + { + if (!ISRELDEP(d2)) + return 0; /* cannot match as d1 != d2 */ + rd2 = GETRELDEP(pool, d2); + return pool_match_dep(pool, d1, rd2->name); + } + rd1 = GETRELDEP(pool, d1); + if (!ISRELDEP(d2)) + { + return pool_match_dep(pool, rd1->name, d2); + } + rd2 = GETRELDEP(pool, d2); + /* first match name */ + if (!pool_match_dep(pool, rd1->name, rd2->name)) + return 0; + /* name matches, check flags and evr */ + return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr); +} + + +/* intersect dependencies in keyname with dep, return list of matching packages */ +void +pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker) +{ + Id p; + Queue qq; + int i; + + queue_empty(q); + if (keyname == SOLVABLE_NAME) + { + Id pp; + FOR_PROVIDES(p, pp, dep) + if (pool_match_nevr(pool, pool->solvables + p, dep)) + queue_push(q, p); + return; + } + queue_init(&qq); + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (s->repo->disabled) + continue; + if (s->repo != pool->installed && !pool_installable(pool, s)) + continue; + if (qq.count) + queue_empty(&qq); + solvable_lookup_deparray(s, keyname, &qq, marker); + for (i = 0; i < qq.count; i++) + if (pool_match_dep(pool, qq.elements[i], dep)) + { + queue_push(q, p); + break; + } + } + queue_free(&qq); +} + +/* check if keyname contains dep, return list of matching packages */ +void +pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker) +{ + Id p; + Queue qq; + int i; + + queue_empty(q); + if (!dep) + return; + queue_init(&qq); + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (s->repo->disabled) + continue; + if (s->repo != pool->installed && !pool_installable(pool, s)) + continue; + if (qq.count) + queue_empty(&qq); + solvable_lookup_deparray(s, keyname, &qq, marker); + for (i = 0; i < qq.count; i++) + if (qq.elements[i] == dep) + { + queue_push(q, p); + break; + } + } + queue_free(&qq); +} + +/* intersect dependencies in keyname with all provides of solvable solvid, + * return list of matching packages */ +/* this currently only works for installable packages */ +void +pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker) +{ + Id p; + Queue qq; + Map missc; /* cache for misses */ + int reloff; + + queue_empty(q); + queue_init(&qq); + reloff = pool->ss.nstrings; + map_init(&missc, reloff + pool->nrels); + FOR_POOL_SOLVABLES(p) + { + Solvable *s = pool->solvables + p; + if (p == solvid) + continue; /* filter out self-matches */ + if (s->repo->disabled) + continue; + if (s->repo != pool->installed && !pool_installable(pool, s)) + continue; + if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff, 0)) + queue_push(q, p); + } + map_free(&missc); + queue_free(&qq); +} + +/* EOF */