]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Add support for DISTTYPE_APK to the libsolv core
authorMichael Schroeder <mls@suse.de>
Thu, 28 Nov 2024 12:31:02 +0000 (13:31 +0100)
committerMichael Schroeder <mls@suse.de>
Thu, 28 Nov 2024 12:33:08 +0000 (13:33 +0100)
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
ext/testcase.c
src/CMakeLists.txt
src/apk.c [new file with mode: 0644]
src/evr.c
src/pool.c
src/pool.h
src/poolid.c

index 0648d80474d8896592aa07f7f7fa285b4736320c..3b61ab04b7c8cae54bb5f69694db44a02c60b0ea 100644 (file)
@@ -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();
index 1640ad7ad7586d943b65d5361636dcd9508eb0cf..3be2a11b23034e2c50985acf173b4c56b4a97dec 100644 (file)
@@ -172,6 +172,7 @@ static struct disttype2str {
   { DISTTYPE_ARCH, "arch" },
   { DISTTYPE_HAIKU, "haiku" },
   { DISTTYPE_CONDA, "conda" },
+  { DISTTYPE_APK, "apk" },
   { 0, 0 }
 };
 
index ca04b3911710950638cdce5983eee612c76b610b..25ad09be3688049b825ae5fd09f0124a106a1a77 100644 (file)
@@ -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 (file)
index 0000000..7eab6e7
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+
+#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
index afd5fc51da2faabbd2459cc496a919cabc77c095..9ccce1596a0847d9cb4e51bd3c1f9d20093ea85e 100644 (file)
--- 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;
index 35b16d0d0bc6d0dad81c75314175110f1f3ed95a..14511deffcd6b6b4ef758452e4c6aae222811ae9 100644 (file)
@@ -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:
index df4011fa28287c023bc88fd1dcd0dcddda139d71..d8c938e8823cea1c3240c484d41a15fe3a284d79 100644 (file)
@@ -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)
index bda648fc75c71db48ed7efdc7a80927dc7c28f8d..b55317e81be45eca96f585732eb4b2e5b7fdc73b 100644 (file)
@@ -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;
     }