]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Add DISTTYPE_CONDA and implement version comparison
authorMichael Schroeder <mls@suse.de>
Thu, 21 Mar 2019 14:28:24 +0000 (15:28 +0100)
committerMichael Schroeder <mls@suse.de>
Thu, 21 Mar 2019 14:28:24 +0000 (15:28 +0100)
CMakeLists.txt
ext/testcase.c
src/CMakeLists.txt
src/conda.c [new file with mode: 0644]
src/conda.h [new file with mode: 0644]
src/evr.c
src/pool.c
src/pool.h
src/solvversion.h.in

index 1deef57d28137e94bfa805e9d0209ef17e4db395..6edc486173cc69d1776088e1bbfb1986f9dbd38b 100644 (file)
@@ -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})
index dad6503960acb7446b9c441466f872afa1cbce7f..4654bcb9e035b618c8ed536ca42beb451b97a332 100644 (file)
@@ -153,6 +153,7 @@ static struct disttype2str {
   { DISTTYPE_DEB,  "deb" },
   { DISTTYPE_ARCH, "arch" },
   { DISTTYPE_HAIKU, "haiku" },
+  { DISTTYPE_CONDA, "conda" },
   { 0, 0 }
 };
 
index 2e32968e3a1a2a3e8093c653ca80326c20301c32..be487a7855848b22ab33c9ec2327428991284a9a 100644 (file)
@@ -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 (file)
index 0000000..dd53754
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+
+#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 (file)
index 0000000..e92557c
--- /dev/null
@@ -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 */
+
index c63878e14b5c3bdc501daa9838c0e2fd0009acff..afd5fc51da2faabbd2459cc496a919cabc77c095 100644 (file)
--- 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
index e5bf24e0d4f3c782990be0167df04cd42b0241a7..cc96664b4d417ac47178f7e9d15d4c60d55f1361 100644 (file)
@@ -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;
     }
index 57b3da2a583c1f30b7610a6df9e40f5a9b48de13..d7a91f45fa10841a2672f7b77213c4b07bcfc46c 100644 (file)
@@ -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)
index 4caba471556d98291f3f36b84e38e00720c87e10..11e4aa35451cc8ac699907580ac0fc5ade234305 100644 (file)
@@ -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