implement SOLVER_FLAG_BREAK_ORPHANS
[platform/upstream/libsolv.git] / ext / repo_susetags.c
index 98b85ce..440e2d5 100644 (file)
@@ -26,6 +26,7 @@ struct datashare {
 };
 
 struct parsedata {
+  int ret;
   Pool *pool;
   Repo *repo;
   Repodata *data;
@@ -91,8 +92,8 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id ma
       i = split(line + 6, sp, 4); /* name, <op>, evr, ? */
       if (i != 1 && i != 3) /* expect either 'name' or 'name' <op> 'evr' */
         {
-         pool_debug(pool, SOLV_FATAL, "susetags: bad dependency line: %d: %s\n", pd->lineno, line);
-          exit(1);
+         pd->ret = pool_error(pool, -1, "susetags: line %d: bad dependency: '%s'\n", pd->lineno, line);
+          return olddeps;
         }
       if (kind)
         id = pool_str2id(pool, join2(&pd->jd, kind, ":", sp[0]), 1);
@@ -106,8 +107,13 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id ma
               break;
           if (flags == 6)
             {
-             pool_debug(pool, SOLV_FATAL, "susetags: unknown relation in %d: '%s'\n", pd->lineno, sp[1]);
-              exit(1);
+             if (!strcmp(sp[1], "<>"))
+               flags = 4;
+             else
+               {
+                 pd->ret = pool_error(pool, -1, "susetags: line %d: unknown relation: '%s'\n", pd->lineno, sp[1]);
+                 return olddeps;
+               }
             }
           id = pool_rel2id(pool, id, evrid, flags + 1, 1);
         }
@@ -124,31 +130,39 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id ma
 static void
 add_source(struct parsedata *pd, char *line, Solvable *s, Id handle)
 {
-  Repo *repo = s->repo;
-  Pool *pool = repo->pool;
+  Pool *pool = s->repo->pool;
   char *sp[5];
   Id name;
-  Id evr;
   Id arch;
+  const char *evr, *sevr;
 
   if (split(line, sp, 5) != 4)
     {
-      pool_debug(pool, SOLV_FATAL, "susetags: bad source line: %d: %s\n", pd->lineno, line);
-      exit(1);
+      pd->ret = pool_error(pool, -1, "susetags: line %d: bad source line '%s'\n", pd->lineno, line);
+      return;
     }
 
   name = pool_str2id(pool, sp[0], 1);
-  evr = makeevr(pool, join2(&pd->jd, sp[1], "-", sp[2]));
-  arch = pool_str2id(pool, sp[3], 1);
-  /* XXX: could record a dep here, depends on where we want to store the data */
+  arch = pool_str2id(pool, sp[3], 1);  /* do this before id2str */
+  evr = join2(&pd->jd, sp[1], "-", sp[2]);
+  sevr = pool_id2str(pool, s->evr);
+  if (sevr)
+    {
+      /* strip epoch */
+      const char *p;
+      for (p = sevr; *p >= '0' && *p <= '9'; p++)
+       ;
+      if (p != sevr && *p == ':' && p[1])
+       sevr = p;
+    }
   if (name == s->name)
     repodata_set_void(pd->data, handle, SOLVABLE_SOURCENAME);
   else
     repodata_set_id(pd->data, handle, SOLVABLE_SOURCENAME, name);
-  if (evr == s->evr)
+  if (sevr && !strcmp(sevr, evr))
     repodata_set_void(pd->data, handle, SOLVABLE_SOURCEEVR);
   else
-    repodata_set_id(pd->data, handle, SOLVABLE_SOURCEEVR, evr);
+    repodata_set_id(pd->data, handle, SOLVABLE_SOURCEEVR, pool_str2id(pool, evr, 1));
   repodata_set_constantid(pd->data, handle, SOLVABLE_SOURCEARCH, arch);
 }
 
@@ -164,7 +178,7 @@ add_dirline(struct parsedata *pd, char *line)
   char *sp[6];
   long filesz;
   long filenum;
-  unsigned dirid;
+  Id dirid;
   if (split(line, sp, 6) != 5)
     return;
   pd->dirs = solv_extend(pd->dirs, pd->ndirs, 1, sizeof(pd->dirs[0]), 31);
@@ -192,84 +206,23 @@ set_checksum(struct parsedata *pd, Repodata *data, Id handle, Id keyname, char *
   Id type;
   if (split(line, sp, 3) != 2)
     {
-      pool_debug(pd->repo->pool, SOLV_FATAL, "susetags: bad checksum line: %d: %s\n", pd->lineno, line);
-      exit(1);
+      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: bad checksum line '%s'\n", pd->lineno, line);
+      return;
     }
   type = solv_chksum_str2type(sp[0]);
   if (!type)
     {
-      pool_debug(pd->repo->pool, SOLV_FATAL, "susetags: unknown checksum type: %d: %s\n", pd->lineno, sp[0]);
-      exit(1);
+      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: unknown checksum type: '%s'\n", pd->lineno, sp[0]);
+      return;
     }
   if (strlen(sp[1]) != 2 * solv_chksum_len(type))
     {
-      pool_debug(pd->repo->pool, SOLV_FATAL, "susetags: bad checksum length: %d: for %s: %s\n", pd->lineno, sp[0], sp[1]);
-      exit(1);
+      pd->ret = pool_error(pd->pool, -1, "susetags: line %d: bad checksum length for type %s: '%s'\n", pd->lineno, sp[0], sp[1]);
+      return;
     }
   repodata_set_checksum(data, handle, keyname, type, sp[1]);
 }
 
-static void
-set_delta_location(Repodata *data, Id handle, int medianr, char *dir, char *file)
-{
-  Pool *pool = data->repo->pool;
-  int l = 0; 
-  char *p, *op;
-
-  if (!dir)
-    {    
-      if ((dir = strrchr(file, '/')) != 0)
-        {
-          l = dir - file;
-          dir = file;
-          file = dir + l + 1; 
-          if (!l) 
-            l++;
-        }
-    }    
-  else 
-    l = strlen(dir);
-  if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
-    {    
-      dir += 2;
-      l -= 2;
-    }    
-  if (l == 1 && dir[0] == '.') 
-    l = 0; 
-  if (dir && l)
-    repodata_set_id(data, handle, DELTA_LOCATION_DIR, pool_strn2id(pool, dir, l, 1));
-  if ((p = strrchr(file, '.')) != 0)
-    {
-      *p = 0;
-      if ((op = strrchr(file, '.')) != 0)
-       {
-         *p = '.';
-         p = op;
-         *p = 0;
-         if (!strcmp(p + 1, "delta.rpm") && (op = strrchr(file, '.')) != 0)
-           {
-             *p = '.';
-             p = op;
-             *p = 0;
-           }
-       }
-      repodata_set_id(data, handle, DELTA_LOCATION_SUFFIX, pool_str2id(pool, p + 1, 1));
-    }
-  if ((p = strrchr(file, '-')) != 0)
-    {
-      *p = 0;
-      if ((op = strrchr(file, '-')) != 0)
-       {
-         *p = '-';
-         p = op;
-         *p = 0;
-       }
-      repodata_set_id(data, handle, DELTA_LOCATION_EVR, pool_str2id(pool, p + 1, 1));
-    }
-  repodata_set_id(data, handle, DELTA_LOCATION_NAME, pool_str2id(pool, file, 1));
-}
-
-
 
 /*
  * id3_cmp
@@ -294,7 +247,7 @@ id3_cmp(const void *v1, const void *v2, void *dp)
 static void
 commit_diskusage(struct parsedata *pd, Id handle)
 {
-  unsigned i;
+  int i;
   Dirpool *dp = &pd->data->dirpool;
   /* Now sort in dirid order.  This ensures that parents come before
      their children.  */
@@ -306,14 +259,14 @@ commit_diskusage(struct parsedata *pd, Id handle)
      the array moving to the start, hence seeing leafs before parents.  */
   for (i = pd->ndirs; i--;)
     {
-      unsigned p = dirpool_parent(dp, pd->dirs[i][0]);
-      unsigned j = i;
+      Id p = dirpool_parent(dp, pd->dirs[i][0]);
+      int j = i;
       for (; p; p = dirpool_parent(dp, p))
         {
           for (; j--;)
            if (pd->dirs[j][0] == p)
              break;
-         if (j < pd->ndirs)
+         if (j >= 0)
            {
              if (pd->dirs[j][1] < pd->dirs[i][1])
                pd->dirs[j][1] = 0;
@@ -395,9 +348,10 @@ tag_from_string(char *cs)
  */
 
 static void
-finish_solvable(struct parsedata *pd, Solvable *s, Id handle, Offset freshens)
+finish_solvable(struct parsedata *pd, Solvable *s, Offset freshens)
 {
   Pool *pool = pd->repo->pool;
+  Id handle = s - pool->solvables;
 
   if (pd->nfilelist)
     {
@@ -431,9 +385,9 @@ finish_solvable(struct parsedata *pd, Solvable *s, Id handle, Offset freshens)
 }
 
 static Hashtable
-joinhash_init(Repo *repo, Hashmask *hmp)
+joinhash_init(Repo *repo, Hashval *hmp)
 {
-  Hashmask hm = mkmask(repo->nsolvables);
+  Hashval hm = mkmask(repo->nsolvables);
   Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
   Hashval h, hh;
   Solvable *s;
@@ -452,7 +406,7 @@ joinhash_init(Repo *repo, Hashmask *hmp)
 }
 
 static Solvable *
-joinhash_lookup(Repo *repo, Hashtable ht, Hashmask hm, Id name, Id evr, Id arch)
+joinhash_lookup(Repo *repo, Hashtable ht, Hashval hm, Id name, Id evr, Id arch, Id start)
 {
   Hashval h, hh;
 
@@ -463,7 +417,7 @@ joinhash_lookup(Repo *repo, Hashtable ht, Hashmask hm, Id name, Id evr, Id arch)
   while (ht[h])
     {
       Solvable *s = repo->pool->solvables + ht[h];
-      if (s->name == name && s->evr == evr && s->arch == arch)
+      if (ht[h] >= start && s->name == name && s->evr == evr && s->arch == arch)
        return s;
       h = HASHCHAIN_NEXT(h, hh, hm);
     }
@@ -483,22 +437,8 @@ lookup_shared_id(Repodata *data, Id p, Id keyname, Id voidid, int uninternalized
       if (r)
        return r;
     }
-  if (uninternalized && data->attrs)
-    {
-      Id *ap = data->attrs[p - data->start];
-      if (ap)
-       {
-         for (; *ap; ap += 2)
-           {
-             if (data->keys[*ap].name != keyname)
-               continue;
-             if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
-               return voidid;
-             if (data->keys[*ap].type == REPOKEY_TYPE_ID)
-               return ap[1];
-           }
-       }
-    }
+  if (uninternalized)
+    return repodata_lookup_id_uninternalized(data, p, keyname, voidid);
   return 0;
 }
 
@@ -532,12 +472,13 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
   int indesc = 0;
   int indelta = 0;
   int last_found_pack = 0;
+  Id first_new_pkg = 0;
   char *sp[5];
   struct parsedata pd;
   Repodata *data = 0;
   Id handle = 0;
   Hashtable joinhash = 0;
-  Hashmask joinhashm = 0;
+  Hashval joinhashm = 0;
   int createdpkgs = 0;
 
   if ((flags & (SUSETAGS_EXTEND|REPO_EXTEND_SOLVABLES)) != 0 && repo->nrepodata)
@@ -567,7 +508,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
     {
       Repodata *sdata;
       int i;
-      
+
       FOR_REPODATAS(repo, i, sdata)
        {
          int p;
@@ -597,7 +538,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
            }
        }
     }
-  
+
   /*
    * read complete file
    *
@@ -611,6 +552,9 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
       char *olinep; /* old line pointer */
       char line_lang[6];
       int keylen = 3;
+
+      if (pd.ret)
+       break;
       if (linep - line + 16 > aline)              /* (re-)alloc buffer */
        {
          aline = linep - line;
@@ -671,8 +615,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
          char *tagend = strchr(line, ':');
          if (!tagend)
            {
-             pool_debug(pool, SOLV_FATAL, "susetags: bad line: %d: %s\n", pd.lineno, line);
-             exit(1);
+             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
+             break;
            }
          intag = tagend - (line + 1);
          cummulate = 0;
@@ -747,15 +691,15 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
                int i = split(line + 6, sp, 3);
                if (i != 2 && i != 3)
                  {
-                   pool_debug(pool, SOLV_FATAL, "susetags: bad location line: %d: %s\n", pd.lineno, line);
-                   exit(1);
+                   pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line);
+                   continue;
                  }
-               set_delta_location(data, handle, atoi(sp[0]), i == 3 ? sp[2] : 0, sp[1]);
+               repodata_set_deltalocation(data, handle, atoi(sp[0]), i == 3 ? sp[2] : 0, sp[1]);
                continue;
              }
            case CTAG('=', 'S', 'i', 'z'):
              if (split(line + 6, sp, 3) == 2)
-               repodata_set_num(data, handle, DELTA_DOWNLOADSIZE, (unsigned int)(atoi(sp[0]) + 1023) / 1024);
+               repodata_set_num(data, handle, DELTA_DOWNLOADSIZE, strtoull(sp[0], 0, 10));
              continue;
            case CTAG('=', 'P', 'k', 'g'):
            case CTAG('=', 'P', 'a', 't'):
@@ -778,13 +722,13 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
       if (tag == CTAG('=', 'D', 'l', 't'))
        {
          if (s)
-           finish_solvable(&pd, s, handle, freshens);
+           finish_solvable(&pd, s, freshens);
          s = 0;
          pd.kind = 0;
           if (split(line + 5, sp, 5) != 4)
            {
-             pool_debug(pool, SOLV_FATAL, "susetags: bad line: %d: %s\n", pd.lineno, line);
-             exit(1);
+             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
+             break;
            }
          handle = repodata_new_handle(data);
          repodata_set_id(data, handle, DELTA_PACKAGE_NAME, pool_str2id(pool, sp[0], 1));
@@ -800,7 +744,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
          /* If we have an old solvable, complete it by filling in some
             default stuff.  */
          if (s)
-           finish_solvable(&pd, s, handle, freshens);
+           finish_solvable(&pd, s, freshens);
 
          /*
           * define kind
@@ -816,8 +760,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
 
           if (split(line + 5, sp, 5) != 4)
            {
-             pool_debug(pool, SOLV_FATAL, "susetags: bad line: %d: %s\n", pd.lineno, line);
-             exit(1);
+             pd.ret = pool_error(pool, -1, "susetags: line %d: bad line '%s'\n", pd.lineno, line);
+             break;
            }
          s = 0;
           freshens = 0;
@@ -836,15 +780,17 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
              arch = pool_str2id(pool, sp[3], 0);
              if (name && arch)
                {
-                 if (repo->start + last_found_pack + 1 < repo->end)
+                 Id start = (flags & REPO_EXTEND_SOLVABLES) ? 0 : first_new_pkg;
+                 if (repo->start + last_found_pack + 1 >= start && repo->start + last_found_pack + 1 < repo->end)
                    {
                      s = pool->solvables + repo->start + last_found_pack + 1;
                      if (s->repo != repo || s->name != name || s->evr != evr || s->arch != arch)
                        s = 0;
                    }
                  if (!s)
-                   s = joinhash_lookup(repo, joinhash, joinhashm, name, evr, arch);
+                   s = joinhash_lookup(repo, joinhash, joinhashm, name, evr, arch, start);
                }
+             /* do not create new packages in EXTEND_SOLVABLES mode */
              if (!s && (flags & REPO_EXTEND_SOLVABLES) != 0)
                continue;
              /* fallthrough to package creation */
@@ -860,6 +806,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
              s->evr = toevr(pool, &pd, sp[1], sp[2]);
              s->arch = pool_str2id(pool, sp[3], 1);
              s->vendor = defvendor;
+             if (!first_new_pkg)
+               first_new_pkg = s - pool->solvables;
              createdpkgs = 1;
            }
          last_found_pack = (s - pool->solvables) - repo->start;
@@ -982,8 +930,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
              int i = split(line + 6, sp, 3);
              if (i != 2 && i != 3)
                {
-                 pool_debug(pool, SOLV_FATAL, "susetags: bad location line: %d: %s\n", pd.lineno, line);
-                 exit(1);
+                 pd.ret = pool_error(pool, -1, "susetags: line %d: bad location line '%s'\n", pd.lineno, line);
+                 continue;
                }
              repodata_set_location(data, handle, atoi(sp[0]), i == 3 ? sp[2] : pool_id2str(pool, s->arch), sp[1]);
            }
@@ -994,8 +942,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
           case CTAG('=', 'S', 'i', 'z'):
            if (split(line + 6, sp, 3) == 2)
              {
-               repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, (unsigned int)(atoi(sp[0]) + 1023) / 1024);
-               repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, (unsigned int)(atoi(sp[1]) + 1023) / 1024);
+               repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, strtoull(sp[0], 0, 10));
+               repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, strtoull(sp[1], 0, 10));
              }
            continue;
           case CTAG('=', 'T', 'i', 'm'):
@@ -1029,7 +977,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
           case CTAG('=', 'V', 'i', 's'):
            {
              /* Accept numbers and textual bools.  */
-             unsigned k;
+             int k;
              k = atoi(line + 6);
              if (k || !strcasecmp(line + 6, "true"))
                repodata_set_void(data, handle, SOLVABLE_ISVISIBLE);
@@ -1040,8 +988,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
              Id name, evr, arch;
              if (split(line + 6, sp, 5) != 4)
                {
-                 pool_debug(pool, SOLV_FATAL, "susetags: bad =Shr line: %s\n", line + 6);
-                 exit(1);
+                 pd.ret = pool_error(pool, -1, "susetags: line %d: bad =Shr line '%s'\n", pd.lineno, line);
+                 continue;
                }
              name = pool_str2id(pool, sp[0], 1);
              evr = toevr(pool, &pd, sp[1], sp[2]);
@@ -1143,14 +1091,16 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
            break;
 
          default:
-           pool_debug(pool, SOLV_ERROR, "susetags: unknown line: %d: %s\n", pd.lineno, line);
+#if 0
+           pool_debug(pool, SOLV_WARN, "susetags: unknown line: %d: %s\n", pd.lineno, line);
+#endif
            break;
        }
 
-    } /* for(;;) */
+    }
 
   if (s)
-    finish_solvable(&pd, s, handle, freshens);
+    finish_solvable(&pd, s, freshens);
   solv_free(pd.filelist);
 
   /* Shared attributes
@@ -1182,7 +1132,7 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
       last_found = 0;
       for (i = 0; i < pd.nshare; i++)
        {
-         unsigned n, nn;
+         unsigned int n, nn;
          Solvable *found = 0;
           if (!pd.share_with[i].name)
            continue;
@@ -1208,11 +1158,12 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
     }
 
   solv_free(joinhash);
+  repodata_free_dircache(data);
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
 
   solv_free(pd.language);
   solv_free(line);
   join_freemem(&pd.jd);
-  return 0;
+  return pd.ret;
 }