Imported Upstream version 0.7.18
[platform/upstream/libsolv.git] / ext / repo_conda.c
index 9352b71..c35dc62 100644 (file)
@@ -22,6 +22,9 @@ struct parsedata {
   Pool *pool;
   Repo *repo;
   Repodata *data;
+
+  Stringpool fnpool;
+  Queue fndata;
 };
 
 static int
@@ -61,17 +64,91 @@ parse_otherdeps(struct parsedata *pd, struct solv_jsonparser *jp, Id handle, Id
 }
 
 static int
+parse_trackfeatures_array(struct parsedata *pd, struct solv_jsonparser *jp, Id handle)
+{
+  int type = JP_ARRAY;
+  while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_ARRAY_END)
+    {
+      if (type == JP_STRING)
+       {
+         char *p = jp->value, *pe;
+         while (*p == ' ' || *p == '\t')
+           p++;
+         if (!*p)
+           continue;
+         for (pe = p + strlen(p) - 1; pe > p; pe--)
+           if (*pe != ' ' && *pe != '\t')
+             break;
+         repodata_add_idarray(pd->data, handle, SOLVABLE_TRACK_FEATURES, pool_strn2id(pd->pool, p, pe - p + 1, 1));
+       }
+      else
+       type = jsonparser_skip(jp, type);
+    }
+  return type;
+}
+
+static void
+parse_trackfeatures_string(struct parsedata *pd, const char *p, Id handle)
+{
+  const char *pe;
+  for (; *p; p++)
+    {
+      if (*p == ' ' || *p == '\t' || *p == ',')
+       continue;
+      pe = p + 1;
+      while (*pe && *pe != ' ' && *pe != '\t' && *pe != ',')
+       pe++;
+      repodata_add_idarray(pd->data, handle, SOLVABLE_TRACK_FEATURES, pool_strn2id(pd->pool, p, pe - p, 1));
+      p = pe - 1;
+    }
+}
+
+static void 
+swap_solvables(Pool *pool, Repodata *data, Id pa, Id pb)
+{
+  Solvable tmp; 
+
+  tmp = pool->solvables[pa];
+  pool->solvables[pa] = pool->solvables[pb];
+  pool->solvables[pb] = tmp; 
+  repodata_swap_attrs(data, pa, pb); 
+}
+
+static Id *
+fn2data(struct parsedata *pd, const char *fn, Id *fntypep, int create)
+{
+  size_t l = strlen(fn), extl = 0;
+  Id fnid;
+  if (l > 6 && !strcmp(fn + l - 6, ".conda"))
+    extl = 6;
+  else if (l > 8 && !strcmp(fn + l - 8, ".tar.bz2"))
+    extl = 8;
+  else
+    return 0;
+  fnid = stringpool_strn2id(&pd->fnpool, fn, l - extl, create);
+  if (!fnid)
+    return 0;
+  if (fnid * 2 + 2 > pd->fndata.count)
+    queue_insertn(&pd->fndata, pd->fndata.count, fnid * 2 + 2 - pd->fndata.count, 0);
+  if (fntypep)
+    *fntypep = extl == 8 ? 1 : 2;      /* 1: legacy .tar.bz2  2: .conda */
+  return pd->fndata.elements + 2 * fnid;
+}
+
+static int
 parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn)
 {
   int type = JP_OBJECT;
   Pool *pool= pd->pool;
   Repodata *data = pd->data;
   Solvable *s;
-  Id handle = repo_add_solvable(pd->repo);
-  s = pool_id2solvable(pool, handle);
+  Id handle;
   char *fn = 0;
   char *subdir = 0;
+  Id *fndata = 0, fntype = 0;
 
+  handle = repo_add_solvable(pd->repo);
+  s = pool_id2solvable(pool, handle);
   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
     {
       if (type == JP_STRING && !strcmp(jp->key, "build"))
@@ -107,17 +184,44 @@ parse_package(struct parsedata *pd, struct solv_jsonparser *jp, char *kfn)
            ts /= 1000;
          repodata_set_num(data, handle, SOLVABLE_BUILDTIME, ts);
        }
+      else if (type == JP_STRING && !strcmp(jp->key, "track_features"))
+       parse_trackfeatures_string(pd, jp->value, handle);
+      else if (type == JP_ARRAY && !strcmp(jp->key, "track_features"))
+       type = parse_trackfeatures_array(pd, jp, handle);
       else
        type = jsonparser_skip(jp, type);
     }
   if (fn || kfn)
-    repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn);
+    {
+      repodata_set_location(data, handle, 0, subdir, fn ? fn : kfn);
+      fndata = fn2data(pd, fn ? fn : kfn, &fntype, 1);
+    }
   solv_free(fn);
   solv_free(subdir);
   if (!s->evr)
     s->evr = 1;
   if (s->name)
     s->provides = repo_addid_dep(pd->repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+
+  if (fndata)
+    {
+      /* deal with legacy package entries */
+      if (fndata[0] && fndata[0] > fntype)
+       {
+         /* ignore this package */
+         repo_free_solvable(pd->repo, handle, 1);
+         return type;
+       }
+      if (fndata[0] && fndata[0] < fntype)
+       {
+         /* replace old package */
+         swap_solvables(pool, data, handle, fndata[1]);
+         repo_free_solvable(pd->repo, handle, 1);
+         handle = fndata[1];
+       }
+      fndata[0] = fntype;
+      fndata[1] = handle;
+    }
   return type;
 }
 
@@ -154,14 +258,18 @@ parse_packages2(struct parsedata *pd, struct solv_jsonparser *jp)
 }
 
 static int
-parse_main(struct parsedata *pd, struct solv_jsonparser *jp)
+parse_main(struct parsedata *pd, struct solv_jsonparser *jp, int flags)
 {
   int type = JP_OBJECT;
   while (type > 0 && (type = jsonparser_parse(jp)) > 0 && type != JP_OBJECT_END)
     {
       if (type == JP_OBJECT && !strcmp("packages", jp->key))
        type = parse_packages(pd, jp);
-      if (type == JP_ARRAY && !strcmp("packages", jp->key))
+      else if (type == JP_ARRAY && !strcmp("packages", jp->key))
+       type = parse_packages2(pd, jp);
+      else if (type == JP_OBJECT && !strcmp("packages.conda", jp->key) && !(flags & CONDA_ADD_USE_ONLY_TAR_BZ2))
+       type = parse_packages(pd, jp);
+      else if (type == JP_ARRAY && !strcmp("packages.conda", jp->key) && !(flags & CONDA_ADD_USE_ONLY_TAR_BZ2))
        type = parse_packages2(pd, jp);
       else
        type = jsonparser_skip(jp, type);
@@ -184,14 +292,18 @@ repo_add_conda(Repo *repo, FILE *fp, int flags)
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
+  stringpool_init_empty(&pd.fnpool);
+  queue_init(&pd.fndata);
 
   jsonparser_init(&jp, fp);
   if ((type = jsonparser_parse(&jp)) != JP_OBJECT)
     ret = pool_error(pool, -1, "repository does not start with an object");
-  else if ((type = parse_main(&pd, &jp)) != JP_OBJECT_END)
+  else if ((type = parse_main(&pd, &jp, flags)) != JP_OBJECT_END)
     ret = pool_error(pool, -1, "parse error line %d", jp.line);
   jsonparser_free(&jp);
 
+  queue_free(&pd.fndata);
+  stringpool_free(&pd.fnpool);
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);