From fbbf2565c19f7c72351c6967f8ad3d6c929e551f Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Thu, 28 Nov 2024 13:31:02 +0100 Subject: [PATCH] Add support for DISTTYPE_APK to the libsolv core This is mostly the apk version comparison. We also do not add spaces around the comparison ops for apk and shorten =~ to ~. This is currenly bould to MULTI_SEMANTICS as we do not have an "alpine" target yet. --- bindings/solv.i | 1 + ext/testcase.c | 1 + src/CMakeLists.txt | 4 + src/apk.c | 205 +++++++++++++++++++++++++++++++++++++++++++++ src/evr.c | 18 +++- src/pool.c | 1 + src/pool.h | 1 + src/poolid.c | 22 +++++ 8 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/apk.c diff --git a/bindings/solv.i b/bindings/solv.i index 0648d804..3b61ab04 100644 --- a/bindings/solv.i +++ b/bindings/solv.i @@ -1950,6 +1950,7 @@ returnself(matchsolvable) static const int DISTTYPE_ARCH = DISTTYPE_ARCH; static const int DISTTYPE_HAIKU = DISTTYPE_HAIKU; static const int DISTTYPE_CONDA = DISTTYPE_CONDA; + static const int DISTTYPE_APK = DISTTYPE_APK; Pool() { Pool *pool = pool_create(); diff --git a/ext/testcase.c b/ext/testcase.c index 1640ad7a..3be2a11b 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -172,6 +172,7 @@ static struct disttype2str { { DISTTYPE_ARCH, "arch" }, { DISTTYPE_HAIKU, "haiku" }, { DISTTYPE_CONDA, "conda" }, + { DISTTYPE_APK, "apk" }, { 0, 0 } }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca04b391..25ad09be 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,10 @@ IF (ENABLE_CONDA) SET (libsolv_HEADERS ${libsolv_HEADERS} conda.h) ENDIF (ENABLE_CONDA) +IF (MULTI_SEMANTICS) + SET (libsolv_SRCS ${libsolv_SRCS} apk.c) +ENDIF (MULTI_SEMANTICS) + IF (NOT MSVC) SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") ENDIF (NOT MSVC) diff --git a/src/apk.c b/src/apk.c new file mode 100644 index 00000000..7eab6e75 --- /dev/null +++ b/src/apk.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2024, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * apk.c + * + * evr comparison for apk + */ + +#include +#include +#include +#include +#include +#include + +#include "pool.h" +#include "repo.h" +#include "util.h" +#include "apk.h" + +static const char suffixlist[] = "\005alpha\004beta\003pre\002rc\003cvs\003svn\003git\002hg\001p"; +static const char classorder[] = ".X_~-$!"; + +static inline int +suffixclass(const char *evr, size_t l) +{ + const char *sp = suffixlist; + int i; + for (i = 1; *sp; sp += *sp + 1, i++) + if (l == *sp && !strncmp(sp + 1, evr, l)) + return i; + return 0; +} + +static inline int +is_release_suffix(const char *p, const char *pe) +{ + int cl; + size_t l = 0; + while (p < pe && *p >= 'a' && *p <= 'z') + p++, l++; + cl = suffixclass(p - l, l); + return cl && cl < 5 ? 1 : 0; +} + +static int +classify_part(int initial, const char *evr, const char *evre, const char **part, const char **parte) +{ + int c; + *part = *parte = evr; + if (evr >= evre) + return '$'; + c = *evr++; + if (c >= 'a' && c <= 'z') + { + *parte = evr; + return 'X'; + } + if (initial && c >= '0' && c <= '9') + { + c = '.'; + evr--; + } + if (evr >= evre) + return '!'; + *part = evr; + if (c == '.' && *evr >= '0' && *evr <= '9') + ; + else if (c == '_' && *evr >= 'a' && *evr <= 'z') + { + while (evr < evre && *evr >= 'a' && *evr <= 'z') + evr++; + } + else if (c == '-' && *evr == 'r' && evr + 1 < evre && (evr[1] >= '0' && evr[2] <= '9')) + evr++; + else if (c == '~' && ((*evr >= '0' && *evr <= '9') || (*evr >= 'a' && *evr <= 'f'))) + { + while (evr < evre && ((*evr >= '0' && *evr <= '9') || (*evr >= 'a' && *evr <= 'f'))) + evr++; + *parte = evr; + return c; + } + else + { + *part = *parte; + return '!'; + } + while (evr < evre && *evr >= '0' && *evr <= '9') + evr++; + *parte = evr; + return c; +} + +int +solv_vercmp_apk(const char *evr1, const char *evr1e, const char *evr2, const char *evr2e) +{ + const char *p1, *p1e, *p2, *p2e; + int c1, c2, initial, r; + int fuzzy1 = 0, fuzzy2 = 0; + + if (evr1 < evr1e && *evr1 == '~') + { + fuzzy1 = 1; + evr1++; + } + if (evr2 < evr2e && *evr2 == '~') + { + fuzzy2 = 1; + evr2++; + } + for (initial = 1;; initial = 0) + { + c1 = classify_part(initial, evr1, evr1e, &p1, &p1e); + c2 = classify_part(initial, evr2, evr2e, &p2, &p2e); +#if 0 + printf("C1: %c >%.*s<\n", c1, (int)(p1e - p1), p1); + printf("C2: %c >%.*s<\n", c2, (int)(p2e - p2), p2); +#endif + if (c1 != c2 || c1 == '!' || c1 == '$') + break; + evr1 = p1e; + evr2 = p2e; + if (p1e - p1 == p2e - p2 && !strncmp(p1, p2, p1e - p1)) + continue; + if (c1 == '-') + { + if (p1 < p1e && *p1 == 'r') + p1++; + if (p2 < p2e && *p2 == 'r') + p2++; + } + else if (c1 == '_') + { + size_t l1 = 0, l2 = 0; + while (p1 < p1e && *p1 >= 'a' && *p1 <= 'z') + p1++, l1++; + while (p2 < p2e && *p2 >= 'a' && *p2 <= 'z') + p2++, l2++; + c1 = suffixclass(p1 - l1, l1); + c2 = suffixclass(p2 - l2, l2); + if (c1 != c2) + return c1 < c2 ? -1 : 1; + c1 = '_'; + } + if ((c1 == '.' && (initial || (*p1 != '0' && *p2 != '0'))) || c1 == '_' || c1 == '-') + { + while (p1 < p1e && *p1 == '0') + p1++; + while (p2 < p2e && *p2 == '0') + p2++; + if (p1e - p1 != p2e - p2) + return p1e - p1 < p2e - p2 ? -1 : 1; + } + r = strncmp(p1, p2, p1e - p1 > p2e - p2 ? p2e - p2 : p1e - p1); + if (r) + return r < 0 ? -1 : 1; + if (p1e - p1 != p2e - p2) + return p1e - p1 < p2e - p2 ? -1 : 1; + } + if (c1 == c2) + return 0; + if ((fuzzy1 && c1 == '$') || (fuzzy2 && c2 == '$')) + return 0; + if (c1 == '_' && is_release_suffix(p1, p1e)) + return -1; + if (c2 == '_' && is_release_suffix(p2, p2e)) + return 1; + /* handle most likely cases first */ + if (c1 == '.' || c2 == '!') + return 1; + if (c2 == '.' || c1 == '!' || c1 == '$') + return -1; + if (c2 == '$') + return 1; + p1 = strchr(classorder, c1); + p2 = strchr(classorder, c2); + if (p1 && p2 && p1 != p2) + return p1 > p2 ? -1 : 1; + return 0; +} + +int +pool_evrcmp_apk(const Pool *pool, const char *evr1, const char *evr2, int mode) +{ + if (evr1 == evr2) + return 0; + return solv_vercmp_apk(evr1, evr1 + strlen(evr1), evr2, evr2 + strlen(evr2)); +} + +#if 0 +int +main(int argc, char **argv) +{ + char *p1 = argv[1]; + char *p2 = argv[2]; + int r = solv_vercmp_apk(p1, p1 + strlen(p1), p2, p2 + strlen(p2)); + printf("-> %d\n", r); + return 0; +} +#endif diff --git a/src/evr.c b/src/evr.c index afd5fc51..9ccce159 100644 --- a/src/evr.c +++ b/src/evr.c @@ -20,7 +20,9 @@ #ifdef ENABLE_CONDA #include "conda.h" #endif - +#ifdef MULTI_SEMANTICS +#include "apk.h" +#endif #if defined(DEBIAN) || defined(MULTI_SEMANTICS) @@ -326,6 +328,7 @@ solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2) #if defined(MULTI_SEMANTICS) # define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \ pool->disttype == DISTTYPE_HAIKU ? &solv_vercmp_haiku : \ + pool->disttype == DISTTYPE_APK ? &solv_vercmp_apk : \ &solv_ver##cmp_rpm)) #elif defined(DEBIAN) # define solv_vercmp solv_vercmp_deb @@ -352,6 +355,10 @@ pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode) if (pool->disttype == DISTTYPE_CONDA) return pool_evrcmp_conda(pool, evr1, evr2, mode); #endif +#ifdef MULTI_SEMANTICS + if (pool->disttype == DISTTYPE_APK) + return pool_evrcmp_apk(pool, evr1, evr2, mode); +#endif #if 0 POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode); @@ -520,6 +527,15 @@ pool_evrmatch(const Pool *pool, Id evrid, const char *epoch, const char *version { if (!r1) return -1; +#ifdef MULTI_SEMANTICS + if (pool->disttype == DISTTYPE_APK) + { + if (r1[1] == 'r') + r1++; + if (release[0] == 'r') + release++; + } +#endif r = solv_vercmp(r1 + 1, s1, release, release + strlen(release)); if (r) return r; diff --git a/src/pool.c b/src/pool.c index 35b16d0d..14511def 100644 --- a/src/pool.c +++ b/src/pool.c @@ -153,6 +153,7 @@ pool_setdisttype(Pool *pool, int disttype) switch(disttype) { case DISTTYPE_RPM: + case DISTTYPE_APK: pool->noarchid = ARCH_NOARCH; break; case DISTTYPE_DEB: diff --git a/src/pool.h b/src/pool.h index df4011fa..d8c938e8 100644 --- a/src/pool.h +++ b/src/pool.h @@ -175,6 +175,7 @@ struct s_Pool { #define DISTTYPE_ARCH 2 #define DISTTYPE_HAIKU 3 #define DISTTYPE_CONDA 4 +#define DISTTYPE_APK 5 #define SOLV_FATAL (1<<0) #define SOLV_ERROR (1<<1) diff --git a/src/poolid.c b/src/poolid.c index bda648fc..b55317e8 100644 --- a/src/poolid.c +++ b/src/poolid.c @@ -163,6 +163,19 @@ static const char *rels[] = { " <=> " }; +#if defined(MULTI_SEMANTICS) +static const char *rels_nospace[] = { + "!", + ">", + "=", + ">=", + "<", + "<>", + "<=", + "<=>" +}; +#endif + /* get operator for RelId */ const char * @@ -173,6 +186,11 @@ pool_id2rel(const Pool *pool, Id id) return ""; rd = GETRELDEP(pool, id); +#if defined(MULTI_SEMANTICS) + if (pool->disttype == DISTTYPE_APK && rd->flags >= 1 && rd->flags <= 7) + return rels_nospace[rd->flags]; +#endif + switch (rd->flags) { /* debian special cases < and > */ @@ -306,6 +324,10 @@ dep2strcpy(const Pool *pool, char *p, Id id, int oldrel) } strcpy(p, pool_id2rel(pool, id)); p += strlen(p); +#if defined(MULTI_SEMANTICS) + if (pool->disttype == DISTTYPE_APK && (rd->flags == 2 || rd->flags == 3 || rd->flags == 6) && !ISRELDEP(rd->evr) && pool->ss.stringspace[pool->ss.strings[rd->evr]] == '~') + p--; +#endif id = rd->evr; oldrel = rd->flags; } -- 2.47.3