From: Michael Schroeder Date: Thu, 21 Mar 2019 14:28:24 +0000 (+0100) Subject: Add DISTTYPE_CONDA and implement version comparison X-Git-Tag: 0.7.4~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=67d113f336327f3e1adc384bee2990951b2b13c1;p=thirdparty%2Flibsolv.git Add DISTTYPE_CONDA and implement version comparison --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 1deef57d..6edc4861 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ OPTION (ENABLE_MDKREPO "Build with mandriva/mageia repository support?" OFF) OPTION (ENABLE_ARCHREPO "Build with archlinux repository support?" OFF) OPTION (ENABLE_CUDFREPO "Build with cudf repository support?" OFF) OPTION (ENABLE_HAIKU "Build with Haiku package support?" OFF) +OPTION (ENABLE_CONDA "Build with conda dependency support?" OFF) OPTION (ENABLE_APPDATA "Build with AppStream appdata support?" OFF) OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OFF) @@ -202,6 +203,10 @@ PKG_CHECK_MODULES (RPM REQUIRED rpm) INCLUDE_DIRECTORIES (${RPM_INCLUDE_DIRS}) ENDIF (RPM5) +IF (ENABLE_CONDA) +SET (MULTI_SEMANTICS ON) +ENDIF (ENABLE_CONDA) + IF (MULTI_SEMANTICS) MESSAGE (STATUS "Enabling multi dist support") ENDIF (MULTI_SEMANTICS) @@ -285,7 +290,7 @@ FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN ENDFOREACH (VAR) FOREACH (VAR - ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS) + ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS ENABLE_CONDA) IF(${VAR}) ADD_DEFINITIONS (-D${VAR}=1) SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR}) diff --git a/ext/testcase.c b/ext/testcase.c index dad65039..4654bcb9 100644 --- a/ext/testcase.c +++ b/ext/testcase.c @@ -153,6 +153,7 @@ static struct disttype2str { { DISTTYPE_DEB, "deb" }, { DISTTYPE_ARCH, "arch" }, { DISTTYPE_HAIKU, "haiku" }, + { DISTTYPE_CONDA, "conda" }, { 0, 0 } }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2e32968e..be487a78 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,11 @@ SET (libsolv_HEADERS strpool.h dirpool.h knownid.h transaction.h rules.h problems.h chksum.h dataiterator.h ${CMAKE_BINARY_DIR}/src/solvversion.h) +IF (ENABLE_CONDA) + SET (libsolv_SRCS ${libsolv_SRCS} conda.c) +ENDIF (ENABLE_CONDA) + + SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") IF (HAVE_LINKER_VERSION_SCRIPT) SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver") diff --git a/src/conda.c b/src/conda.c new file mode 100644 index 00000000..dd53754e --- /dev/null +++ b/src/conda.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2019, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * conda.c + * + * evr comparison and package matching for conda + */ + +#include +#include +#include +#include +#include + +#include "pool.h" +#include "conda.h" + +static const char * +endseg(const char *seg, const char *end) +{ + for (; seg < end; seg++) + if (*seg == '.' || *seg == '-' || *seg == '_') + break; + return seg; +} + +static const char * +endpart(const char *seg, const char *end) +{ + if (seg == end) + return seg; + if (*seg >= '0' && *seg <= '9') + { + for (seg++; seg < end; seg++) + if (!(*seg >= '0' && *seg <= '9')) + break; + } + else if (*seg == '*') + { + for (seg++; seg < end; seg++) + if (*seg != '*') + break; + } + else + { + for (seg++; seg < end; seg++) + if ((*seg >= '0' && *seg <= '9') || *seg == '*') + break; + } + return seg; +} + +/* C implementation of the version comparison code in conda/models/version.py */ +static int +solv_vercmp_conda(const char *s1, const char *q1, const char *s2, const char *q2) +{ + const char *s1p, *s2p; + const char *s1e, *s2e; + int r, isfirst; + + for (;;) + { + while (s1 < q1 && (*s1 == '.' || *s1 == '-' || *s1 == '_')) + s1++; + while (s2 < q2 && (*s2 == '.' || *s2 == '-' || *s2 == '_')) + s2++; + if (s1 == q1 && s2 == q2) + return 0; + /* find end of component */ + s1e = endseg(s1, q1); + s2e = endseg(s2, q2); + + for (isfirst = 1; ; isfirst = 0) + { + if (s1 == s1e && s2 == s2e) + break; + s1p = endpart(s1, s1e); + s2p = endpart(s2, s2e); + /* prepend 0 if not numeric */ + if (isfirst) + { + if (s1p != s1 && !(*s1 >= '0' && *s1 <= '9')) + s1p = s1; + if (s2p != s2 && !(*s2 >= '0' && *s2 <= '9')) + s2p = s2; + } + /* special case "post" */ + if (s1p - s1 == 4 && !strncasecmp(s1, "post", 4)) + { + if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4)) + { + s1 = s1p; + s2 = s2p; + continue; + } + return 1; + } + if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4)) + return -1; + + if (isfirst || ((s1 == s1p || (*s1 >= '0' && *s1 <= '9')) && (s2 == s2p || (*s2 >= '0' && *s2 <= '9')))) + { + /* compare numbers */ + while (s1 < s1p && *s1 == '0') + s1++; + while (s2 < s2p && *s2 == '0') + s2++; + if (s1p - s1 < s2p - s2) + return -1; + if (s1p - s1 > s2p - s2) + return 1; + r = s1p - s1 ? strncmp(s1, s2, s1p - s1) : 0; + if (r) + return r; + } + else if (s1 == s1p || (*s1 >= '0' && *s1 <= '9')) + return 1; + else if (s2 == s2p || (*s2 >= '0' && *s2 <= '9')) + return -1; + else + { + /* special case "dev" */ + if (*s2 != '*' && s1p - s1 == 3 && !strncasecmp(s1, "dev", 3)) + { + if (s2p - s2 == 3 && !strncasecmp(s2, "dev", 3)) + { + s1 = s1p; + s2 = s2p; + continue; + } + return -1; + } + if (*s1 != '*' && s2p - s2 == 3 && !strncasecmp(s2, "dev", 3)) + return 1; + /* compare strings */ + r = s2p - s2 > s1p - s1 ? s1p - s1 : s2p - s2; + if (r) + r = strncasecmp(s1, s2, r); + if (r) + return r; + if (s1p - s1 < s2p - s2) + return -1; + if (s1p - s1 > s2p - s2) + return 1; + } + s1 = s1p; + s2 = s2p; + } + } +} + +int +pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode) +{ + static char zero[2] = {'0', 0}; + int r; + const char *s1, *s2; + const char *r1, *r2; + + if (evr1 == evr2) + return 0; + + /* split and compare epoch */ + for (s1 = evr1; *s1 >= '0' && *s1 <= '9'; s1++) + ; + for (s2 = evr2; *s2 >= '0' && *s2 <= '9'; s2++) + ; + if (s1 == evr1 || *s1 != '!') + s1 = 0; + if (s2 == evr1 || *s2 != '!') + s2 = 0; + if (s1 || s2) + { + r = solv_vercmp_conda(s1 ? evr1 : zero, s1 ? s1 : zero + 1, + s2 ? evr2 : zero, s2 ? s2 : zero + 1); + if (r) + return r; + if (s1) + evr1 = s1 + 1; + if (s2) + evr2 = s2 + 1; + } + /* split into version/localversion */ + for (s1 = evr1, r1 = 0; *s1; s1++) + if (*s1 == '+') + r1 = s1; + for (s2 = evr2, r2 = 0; *s2; s2++) + if (*s2 == '+') + r2 = s2; + r = solv_vercmp_conda(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2); + if (r) + return r; + if (!r1 && !r2) + return 0; + if (!r1 && r2) + return -1; + if (r1 && !r2) + return 1; + return solv_vercmp_conda(r1 + 1, s1, r2 + 1, s2); +} + diff --git a/src/conda.h b/src/conda.h new file mode 100644 index 00000000..e92557c2 --- /dev/null +++ b/src/conda.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019, SUSE LLC + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* + * conda.h + * + */ + +#ifndef LIBSOLV_CONDA_H +#define LIBSOLV_CONDA_H + +int pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode); + +#endif /* LIBSOLV_CONDA_H */ + diff --git a/src/evr.c b/src/evr.c index c63878e1..afd5fc51 100644 --- a/src/evr.c +++ b/src/evr.c @@ -17,6 +17,9 @@ #include "evr.h" #include "pool.h" +#ifdef ENABLE_CONDA +#include "conda.h" +#endif #if defined(DEBIAN) || defined(MULTI_SEMANTICS) @@ -322,7 +325,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_HAIKU ? &solv_vercmp_haiku : \ &solv_ver##cmp_rpm)) #elif defined(DEBIAN) # define solv_vercmp solv_vercmp_deb @@ -345,6 +348,11 @@ pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode) if (evr1 == evr2) return 0; +#ifdef ENABLE_CONDA + if (pool->disttype == DISTTYPE_CONDA) + return pool_evrcmp_conda(pool, evr1, evr2, mode); +#endif + #if 0 POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode); #endif diff --git a/src/pool.c b/src/pool.c index e5bf24e0..cc96664b 100644 --- a/src/pool.c +++ b/src/pool.c @@ -158,6 +158,9 @@ pool_setdisttype(Pool *pool, int disttype) case DISTTYPE_HAIKU: pool->noarchid = ARCH_ANY; break; + case DISTTYPE_CONDA: + pool->noarchid = ARCH_ANY; + break; default: return -1; } diff --git a/src/pool.h b/src/pool.h index 57b3da2a..d7a91f45 100644 --- a/src/pool.h +++ b/src/pool.h @@ -173,6 +173,7 @@ struct s_Pool { #define DISTTYPE_DEB 1 #define DISTTYPE_ARCH 2 #define DISTTYPE_HAIKU 3 +#define DISTTYPE_CONDA 4 #define SOLV_FATAL (1<<0) #define SOLV_ERROR (1<<1) diff --git a/src/solvversion.h.in b/src/solvversion.h.in index 4caba471..11e4aa35 100644 --- a/src/solvversion.h.in +++ b/src/solvversion.h.in @@ -27,6 +27,7 @@ extern int solv_version_patch; #cmakedefine LIBSOLV_FEATURE_LINKED_PKGS #cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS #cmakedefine LIBSOLV_FEATURE_MULTI_SEMANTICS +#cmakedefine LIBSOLV_FEATURE_CONDA #cmakedefine LIBSOLVEXT_FEATURE_RPMPKG #cmakedefine LIBSOLVEXT_FEATURE_RPMDB