]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
More conda work
authorMichael Schroeder <mls@suse.de>
Wed, 3 Apr 2019 13:02:02 +0000 (15:02 +0200)
committerMichael Schroeder <mls@suse.de>
Wed, 3 Apr 2019 13:02:02 +0000 (15:02 +0200)
- add pool_conda_matchspec() to create a REL_CONDA dep from a string
- add name globbing for REL_CONDA
- support build flavor matching

ext/testcase.c
src/conda.c
src/conda.h
src/knownid.h
src/libsolv.ver
src/pool.c
src/selection.c
src/solvable.c

index 5c54bbf918caa1bd98667934fe340c27064e72bb..57919067724e096f3c2752959cd143cd9840693a 100644 (file)
@@ -1258,7 +1258,7 @@ testcase_write_testtags(Repo *repo, FILE *fp)
     {
       name = pool_id2str(pool, s->name);
       evr = pool_id2str(pool, s->evr);
-      arch = pool_id2str(pool, s->arch);
+      arch = s->arch ? pool_id2str(pool, s->arch) : "-";
       release = strrchr(evr, '-');
       if (!release)
        release = evr + strlen(evr);
@@ -1284,6 +1284,12 @@ testcase_write_testtags(Repo *repo, FILE *fp)
        }
       if (s->vendor)
        fprintf(fp, "=Vnd: %s\n", pool_id2str(pool, s->vendor));
+      if (solvable_lookup_idarray(s, SOLVABLE_BUILDFLAVOR, &q))
+       {
+         int i;
+         for (i = 0; i < q.count; i++)
+           fprintf(fp, "=Flv: %s\n", pool_id2str(pool, q.elements[i]));
+       }
       ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
       if (ti)
        fprintf(fp, "=Tim: %u\n", ti);
@@ -1412,7 +1418,7 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags)
          if (sp[2] && !(sp[2][0] == '-' && !sp[2][1]))
            sp[2][-1] = '-';
          s->evr = makeevr(pool, sp[1]);
-         s->arch = pool_str2id(pool, sp[3], 1);
+         s->arch = strcmp(sp[3], "-") ? pool_str2id(pool, sp[3], 1) : 0;
          continue;
        default:
          break;
@@ -1502,6 +1508,9 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags)
            repodata_add_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, id);
            break;
          }
+       case 'F' << 16 | 'l' << 8 | 'v':
+         repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_BUILDFLAVOR, line + 6);
+         break;
         default:
          break;
         }
@@ -2239,7 +2248,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
          lowscore = pool->id2arch[i];
        }
     }
-  cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "unset", 0);
+  cmd = pool_tmpjoin(pool, "system ", pool->lastarch ? pool_id2str(pool, arch) : "-", 0);
   for (i = 0; disttype2str[i].str != 0; i++)
     if (pool->disttype == disttype2str[i].type)
       break;
@@ -2721,7 +2730,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
                  missing_features = 1;
                }
            }
-         if (strcmp(pieces[1], "unset") == 0)
+         if (strcmp(pieces[1], "unset") == 0 || strcmp(pieces[1], "-") == 0)
            pool_setarch(pool, 0);
          else if (pieces[1][0] == ':')
            pool_setarchpolicy(pool, pieces[1] + 1);
index 5b134dd4eec3d4d857870378c98651ab416bdc05..63da8f87a490b255865d99871a3eab0631ba2976 100644 (file)
@@ -226,7 +226,7 @@ pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode
 }
 
 static int
-regexmatch(const char *evr, const char *version, size_t versionlen)
+regexmatch(const char *evr, const char *version, size_t versionlen, int icase)
 {
   regex_t reg;
   char *buf = solv_malloc(versionlen + 1);
@@ -234,7 +234,7 @@ regexmatch(const char *evr, const char *version, size_t versionlen)
 
   memcpy(buf, version, versionlen);
   buf[versionlen] = 0;
-  if (regcomp(&reg, buf, REG_EXTENDED | REG_NOSUB))
+  if (regcomp(&reg, buf, REG_EXTENDED | REG_NOSUB | (icase ? REG_ICASE : 0)))
     return 0;
   r = regexec(&reg, evr, 0, NULL, 0);
   regfree(&reg);
@@ -242,7 +242,7 @@ regexmatch(const char *evr, const char *version, size_t versionlen)
 }
 
 static int
-globmatch(const char *evr, const char *version, size_t versionlen)
+globmatch(const char *evr, const char *version, size_t versionlen, int icase)
 {
   regex_t reg;
   char *buf = solv_malloc(2 * versionlen + 3);
@@ -259,7 +259,7 @@ globmatch(const char *evr, const char *version, size_t versionlen)
     }
   buf[j++] = '$';
   buf[j] = 0;
-  if (regcomp(&reg, buf, REG_EXTENDED | REG_NOSUB))
+  if (regcomp(&reg, buf, REG_EXTENDED | REG_NOSUB | (icase ? REG_ICASE : 0)))
     return 0;
   r = regexec(&reg, evr, 0, NULL, 0);
   regfree(&reg);
@@ -279,7 +279,7 @@ solvable_conda_matchversion_single(Solvable *s, const char *version, size_t vers
     return 1;  /* matches every version */
   evr = pool_id2str(s->repo->pool, s->evr);
   if (versionlen >= 2 && version[0] == '^' && version[versionlen - 1] == '$')
-    return regexmatch(evr, version, versionlen);
+    return regexmatch(evr, version, versionlen, 0);
   if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
     {
       int flags = 0;
@@ -361,7 +361,7 @@ solvable_conda_matchversion_single(Solvable *s, const char *version, size_t vers
           if (version[i] != '*')
            break;
        if (i < versionlen)
-         return globmatch(evr, version, versionlen);
+         return globmatch(evr, version, versionlen, 1);
       }
 
   if (versionlen > 1 && version[versionlen - 1] == '*')
@@ -430,6 +430,26 @@ solvable_conda_matchversion_rec(Solvable *s, const char **versionp, const char *
     }
 }
 
+static int
+solvable_conda_matchbuild(Solvable *s, const char *build, const char *buildend)
+{
+  const char *bp;
+  const char *flavor = solvable_lookup_str(s, SOLVABLE_BUILDFLAVOR);
+
+  if (!flavor)
+    flavor = "";
+  if (build == buildend)
+    return *flavor ? 0 : 1;
+  if (build + 1 == buildend && *build == '*')
+    return 1;
+  if (*build == '^' && buildend[-1] == '$')
+    return regexmatch(flavor, build, buildend - build, 0);
+  for (bp = build; bp < buildend; bp++)
+    if (*bp == '*')
+      return globmatch(flavor, build, buildend - build, 0);
+  return strncmp(flavor, build, buildend - build) == 0 && flavor[buildend - build] == 0 ? 1 : 0;
+}
+
 /* return true if solvable s matches the version */
 /* see conda/models/match_spec.py */
 int
@@ -449,6 +469,189 @@ solvable_conda_matchversion(Solvable *s, const char *version)
   r = solvable_conda_matchversion_rec(s, &version, versionend);
   if (r != 1 || version != versionend)
     return 0;
+  if (build && !solvable_conda_matchbuild(s, build, build + strlen(build)))
+    return 0;
   return r;
 }
 
+static Id
+pool_addrelproviders_conda_slow(Pool *pool, const char *namestr, Id evr, Queue *plist, int mode)
+{
+  size_t namestrlen = strlen(namestr);
+  const char *evrstr = evr == 0 || evr == 1 ? 0 : pool_id2str(pool, evr);
+  Id p;
+
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (!pool_installable(pool, s))
+       continue;
+      if (mode == 1 && !globmatch(pool_id2str(pool, s->name), namestr, namestrlen, 1))
+       continue;
+      if (mode == 2 && !regexmatch(pool_id2str(pool, s->name), namestr, namestrlen, 1))
+       continue;
+      if (!evrstr || solvable_conda_matchversion(s, evrstr))
+       queue_push(plist, p);
+    }
+  return 0;
+}
+
+/* called from pool_addrelproviders, plist is an empty queue
+ * it can either return an offset into the whatprovides array
+ * or fill the plist queue and return zero */
+Id
+pool_addrelproviders_conda(Pool *pool, Id name, Id evr, Queue *plist)
+{
+  const char *namestr = pool_id2str(pool, name), *np;
+  size_t l, nuc = 0;
+  Id wp, p, *pp;
+
+  /* is this a regex? */
+  if (*namestr && *namestr == '^')
+    {
+      l = strlen(namestr);
+      if (namestr[l - 1] == '$')
+       return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 2);
+    }
+  /* is this '*'? */
+  if (*namestr && *namestr == '*' && namestr[1] == 0)
+    return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 0);
+  /* does the string contain '*' or uppercase? */
+  for (np = namestr; *np; np++)
+    {
+      if (*np == '*')
+       return pool_addrelproviders_conda_slow(pool, namestr, evr, plist, 1);
+      else if (*np >= 'A' && *np <= 'Z')
+        nuc++;
+    }
+  if (nuc)
+    {
+      char *nbuf = solv_strdup(namestr), *nbufp;
+      for (nbufp = nbuf; *nbufp; nbufp++)
+       *nbufp = *nbufp >= 'A' && *nbufp <= 'Z' ? *nbufp + ('a' - 'A') : *nbufp;
+      name = pool_str2id(pool, nbuf, 0);
+      wp = name ? pool_whatprovides(pool, name) : 0;
+      solv_free(nbuf);
+    }
+  else
+    wp = pool_whatprovides(pool, name);
+  if (wp && evr && evr != 1)
+    {
+      const char *evrstr = pool_id2str(pool, evr);
+      pp = pool->whatprovidesdata + wp;
+      while ((p = *pp++) != 0)
+       {
+         if (solvable_conda_matchversion(pool->solvables + p, evrstr))
+           queue_push(plist, p);
+         else
+           wp = 0; 
+       }
+    }
+  return wp;
+}
+
+/* create a CONDA_REL relation from a matchspec */
+Id
+pool_conda_matchspec(Pool *pool, const char *name)
+{
+  const char *p2;
+  char *name2;
+  char *p, *pp;
+  char *build, *buildend, *version, *versionend;
+  Id nameid, evrid = 1;
+
+  /* ignore channel and namespace for now */
+  if ((p2 = strrchr(name, ':')))
+    name = p2 + 1;
+  name2 = solv_strdup(name);
+  /* find end of name */
+  for (p = name2; *p && *p != ' ' && *p != '=' && *p != '<' && *p != '>' && *p != '!' && *p != '~'; p++)
+    if (*p >= 'A' && *p <= 'Z')
+      *(char *)p += 'a' - 'A';         /* lower case the name */
+  if (p == name2)
+    {
+      solv_free(name2);
+      return 0;        /* error: no package name */
+    }
+  nameid = pool_strn2id(pool, name2, p - name2, 1);
+  while (*p == ' ')
+    p++;
+  if (!*p)
+    {
+      solv_free(name2);
+      return pool_rel2id(pool, nameid, evrid, REL_CONDA, 1);
+    }
+  /* have version */
+  version = p;
+  versionend = p + strlen(p);
+  while (versionend > version && versionend[-1] == ' ')
+    versionend--;
+  build = buildend = 0;
+  /* split of build */
+  p = versionend;
+  for (;;)
+    {
+      while (p > version && p[-1] != ' ' && p[-1] != '-' && p[-1] != '=' && p[-1] != ',' && p[-1] != '|' && p[-1] != '<' && p[-1] != '>' && p[-1] != '~')
+       p--;
+      if (p <= version + 1 || (p[-1] != ' ' && p[-1] != '='))
+       break;          /* no build */
+      /* check char before delimiter */
+      if (p[-2] == '=' || p[-2] == '!' || p[-2] == '|' || p[-2] == ',' || p[-2] == '<' || p[-2] == '>' || p[-2] == '~')
+       {
+         /* illegal combination */
+         if (p[-1] == ' ')
+           {
+             p--;
+             continue; /* special case space: it may be in the build */
+           }
+         break;        /* no build */
+       }
+      if (p < versionend)
+       {
+         build = p;
+         buildend = versionend;
+         versionend = p - 1;
+       }
+      break;
+    }
+  /* do weird version translation */
+  if (versionend > version && version[0] == '=')
+    {
+      if (versionend - version >= 2 && version[1] == '=')
+       {
+         if (!build)
+           version += 2;
+       }
+      else if (build)
+       version += 1;
+      else
+       {
+         for (p = version + 1; p < versionend; p++)
+           if (*p == '=' || *p == ',' || *p == '|')
+             break;
+         if (p == versionend)
+           {
+             memmove(version, version + 1, versionend - version - 1);
+             versionend[-1] = '*';
+           }
+       }
+    }
+#if 0
+  printf("version: >%.*s<\n", (int)(versionend - version), version);
+  if (build) printf("build: >%.*s<\n", (int)(buildend - build), build);
+#endif
+  /* strip spaces from version */
+  for (p = pp = version; pp < versionend; pp++)
+    if (*pp != ' ')
+      *p++ = *pp;
+  if (build)
+    {
+      *p++ = ' ';
+      memcpy(p, build, buildend - build);
+      p += buildend - build;
+    }
+  evrid = pool_strn2id(pool, version, p - version, 1);
+  solv_free(name2);
+  return pool_rel2id(pool, nameid, evrid, REL_CONDA, 1);
+}
+
index 7233f17bfd25971084e0bd3825a05560c9f15f65..3bcfa2d19065bf7b76f86df551328773d0575152 100644 (file)
@@ -15,6 +15,8 @@
 
 int pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode);
 int solvable_conda_matchversion(Solvable *s, const char *version);
+Id pool_addrelproviders_conda(Pool *pool, Id name, Id evr, Queue *plist);
+Id pool_conda_matchspec(Pool *pool, const char *name);
 
 #endif /* LIBSOLV_CONDA_H */
 
index b5b41d6a83c6f25db1ac5a882b783b6fca7d0bfd..9d7f157ee6fe0a0a00d98b4a802e14705b0069d2 100644 (file)
@@ -251,12 +251,15 @@ KNOWNID(SIGNATURE_EXPIRES,                "signature:expires"),
 KNOWNID(SIGNATURE_DATA,                        "signature:data"),
 
 /* 'content' of patch, usually list of modules */
-KNOWNID(UPDATE_MODULE,                  "update:module"),              /*  "name stream version context arch" */
-KNOWNID(UPDATE_MODULE_NAME,             "update:module:name"),         /*   name */
-KNOWNID(UPDATE_MODULE_STREAM,           "update:module:stream"),       /*   stream */
-KNOWNID(UPDATE_MODULE_VERSION,          "update:module:version"),      /*   version */
-KNOWNID(UPDATE_MODULE_CONTEXT,          "update:module:context"),      /*   context */
-KNOWNID(UPDATE_MODULE_ARCH,             "update:module:arch"),         /*   architecture */
+KNOWNID(UPDATE_MODULE,                 "update:module"),               /* "name stream version context arch" */
+KNOWNID(UPDATE_MODULE_NAME,            "update:module:name"),          /* name */
+KNOWNID(UPDATE_MODULE_STREAM,          "update:module:stream"),        /* stream */
+KNOWNID(UPDATE_MODULE_VERSION,         "update:module:version"),       /* version */
+KNOWNID(UPDATE_MODULE_CONTEXT,         "update:module:context"),       /* context */
+KNOWNID(UPDATE_MODULE_ARCH,            "update:module:arch"),          /* architecture */
+
+KNOWNID(SOLVABLE_BUILDVERSION,         "solvable:buildversion"),       /* conda */
+KNOWNID(SOLVABLE_BUILDFLAVOR,          "solvable:buildflavor"),        /* conda */
 
 KNOWNID(ID_NUM_INTERNAL,               0)
 
index 58bc957ec2a3ac1a1d55d9e423f8be436e53cfc2..d983b5410ed9de783731150a726073e61bc72f85 100644 (file)
@@ -291,7 +291,6 @@ SOLV_1.0 {
                solv_realloc;
                solv_realloc2;
                solv_replacebadutf8;
-               solv_setcloexec;
                solv_sort;
                solv_strdup;
                solv_timems;
@@ -449,4 +448,5 @@ SOLV_1.2 {
 
 SOLV_1.3 {
                repodata_set_kv;
+               solv_setcloexec;
 } SOLV_1.2;
index 09354ef69ff41294ba7820546049e8a2c23f727b..a263e9cfe075a1844b942e02f96427f39ed6cf32 100644 (file)
@@ -1289,19 +1289,7 @@ pool_addrelproviders(Pool *pool, Id d)
          break;
 #ifdef ENABLE_CONDA
        case REL_CONDA:
-         wp = pool_whatprovides(pool, name);
-         if (evr)
-           {
-             const char *evrstr = pool_id2str(pool, evr);
-             pp = pool->whatprovidesdata + wp;
-             while ((p = *pp++) != 0)
-               {
-                 if (solvable_conda_matchversion(pool->solvables + p, evrstr))
-                   queue_push(&plist, p);
-                 else
-                   wp = 0;
-               }
-           }
+          wp = pool_addrelproviders_conda(pool, name, evr, &plist);
          break;
 #endif
        default:
index a160122a06d02041027f6ea0d806ba2c686305c3..ef5c1f8a89e1ebae8ba14530c9acbefe6e077456 100644 (file)
@@ -21,6 +21,9 @@
 #include "selection.h"
 #include "solver.h"
 #include "evr.h"
+#ifdef ENABLE_CONDA
+#include "conda.h"
+#endif
 
 
 static int
@@ -1149,6 +1152,19 @@ selection_canon(Pool *pool, Queue *selection, const char *name, int flags)
   flags |= SELECTION_NAME;
   flags &= ~SELECTION_PROVIDES;
 
+#ifdef ENABLE_CONDA
+  if (pool->disttype == DISTTYPE_CONDA)
+    {
+      Id *wp, id = pool_conda_matchspec(pool, name);
+      if (!id)
+       return 0;
+      wp = pool_whatprovides_ptr(pool, id);         /* check if there is a match */
+      if (!wp || !*wp)
+       return 0;
+      queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+      return SELECTION_CANON;
+    }
+#endif
   if (pool->disttype == DISTTYPE_DEB)
     {
       if ((r = strchr(name, '_')) == 0)
index 331f290f333c01c80b7c7be2ed79936ded67d6b0..3c4e0bff2beecb6e0990dcef0c218097830c9676 100644 (file)
@@ -126,7 +126,7 @@ solvable_lookup_str(Solvable *s, Id keyname)
   if (!s->repo)
     return 0;
   str = repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
-  if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP))
+  if (!str && (keyname == SOLVABLE_LICENSE || keyname == SOLVABLE_GROUP || keyname == SOLVABLE_BUILDFLAVOR))
     str = solvable_lookup_str_joinarray(s, keyname, ", ");
   return str;
 }