update susetags parser for Code11
authorKlaus Kaempf <kkaempf@suse.de>
Fri, 1 Aug 2008 15:44:34 +0000 (15:44 +0000)
committerKlaus Kaempf <kkaempf@suse.de>
Fri, 1 Aug 2008 15:44:34 +0000 (15:44 +0000)
- backwards compatible with Code10
- support updated 'content' format
  (see http://en.opensuse.org/Standards/YaST2_Repository_Metadata/content)
- augment specific package (REFERENCES line in content) with
   - product:name, product:version, product:distribution, product:flavor
   - add 'provides: product()'
   - add 'provides: product(<name>) = <version>'

tools/repo_content.c
tools/repo_susetags.c
tools/repo_susetags.h
tools/susetags2solv.c

index b39b4f7..63299e4 100644 (file)
@@ -1,4 +1,11 @@
 /*
+ * repo_content.c
+ * 
+ * Parses 'content' file into .solv
+ * See http://en.opensuse.org/Standards/YaST2_Repository_Metadata/content for a description
+ * of the syntax
+ * 
+ * 
  * Copyright (c) 2007, Novell Inc.
  *
  * This program is licensed under the BSD license, read LICENSE.BSD
 #include "util.h"
 #include "repo_content.h"
 
+/*
+ * split l into m parts, store to sp[]
+ *  split at whitespace
+ */
+
 static int
 split(char *l, char **sp, int m)
 {
@@ -40,12 +52,14 @@ split(char *l, char **sp, int m)
   return i;
 }
 
+
 struct parsedata {
   Repo *repo;
   char *tmp;
   int tmpl;
 };
 
+
 static Id
 makeevr(Pool *pool, char *s)
 {
@@ -54,6 +68,10 @@ makeevr(Pool *pool, char *s)
   return str2id(pool, s, 1);
 }
 
+/*
+ * dependency relations
+ */
+
 static char *flagtab[] = {
   ">",
   "=",
@@ -63,8 +81,13 @@ static char *flagtab[] = {
   "<="
 };
 
+
+/*
+ * join up to three strings into one
+ */
+
 static char *
-join(struct parsedata *pd, char *s1, char *s2, char *s3)
+join(struct parsedata *pd, const char *s1, const char *s2, const char *s3)
 {
   int l = 1;
   char *p;
@@ -99,6 +122,11 @@ join(struct parsedata *pd, char *s1, char *s2, char *s3)
   return pd->tmp;
 }
 
+
+/*
+ * add dependency to pool
+ */
+
 static unsigned int
 adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id marker)
 {
@@ -154,6 +182,11 @@ adddep(Pool *pool, struct parsedata *pd, unsigned int olddeps, char *line, Id ma
   return olddeps;
 }
 
+
+/*
+ * split value and add to pool
+ */
+
 static void
 add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
 {
@@ -170,6 +203,12 @@ add_multiple_strings(Repodata *data, Id handle, Id name, char *value)
     }
 }
 
+
+/*
+ * add 'content' to repo
+ *
+ */
+
 void
 repo_add_content(Repo *repo, FILE *fp)
 {
@@ -180,7 +219,10 @@ repo_add_content(Repo *repo, FILE *fp)
   struct parsedata pd;
   Repodata *data;
   Id handle = 0;
-
+  int contentstyle = 0;
+  char *product_name = 0;
+  char *product_version = 0;
+  
   memset(&pd, 0, sizeof(pd));
   line = sat_malloc(1024);
   aline = 1024;
@@ -198,6 +240,8 @@ repo_add_content(Repo *repo, FILE *fp)
   for (;;)
     {
       char *fields[2];
+      
+      /* read line into big-enough buffer */
       if (linep - line + 16 > aline)
        {
          aline = linep - line;
@@ -212,6 +256,8 @@ repo_add_content(Repo *repo, FILE *fp)
         continue;
       *--linep = 0;
       linep = line;
+      
+      /* expect "key value" lines */
       if (split (line, fields, 2) == 2)
         {
          char *key = fields[0];
@@ -220,8 +266,50 @@ repo_add_content(Repo *repo, FILE *fp)
          fprintf (stderr, "key %s, value %s\n", key, fields[1]);
 #endif
 
-#define istag(x) !strcmp (key, x)
-         if (istag ("PRODUCT"))
+#define istag(x) (!strcmp (key, x))
+#define code10 (contentstyle == 10)
+#define code11 (contentstyle == 11)
+         
+         if (contentstyle == 0) 
+           {
+             if (istag ("CONTENTSTYLE"))
+               {
+                 contentstyle = atoi(value);
+                 continue;
+               }
+             else
+               contentstyle = 10;
+           }
+
+         if (code11 && istag ("REFERENCES"))
+           {
+             char *vals[3];
+             Id nameid;
+             Id evrid = 0;
+             
+             if (split(value, vals, 3) == 3)
+               {
+                 if (!strcmp(vals[1], "=")) 
+                   {
+                     nameid = str2id(pool, vals[0], 1);
+                     evrid = str2id(pool, vals[2], 1);
+                 
+                     s = pool_id2solvable(pool, repo_add_solvable(repo));
+                     repodata_extend(data, s - pool->solvables);
+                     handle = repodata_get_handle(data, s - pool->solvables - repo->start);
+
+                     s->name = nameid;
+                     s->evr = evrid;
+                     s->provides = adddep(pool, &pd, s->provides, "product()", 0);
+
+                     continue;
+                   }
+               }
+             fprintf(stderr, "REFERENCES must be 'name = evr'\n");
+             break;
+           }
+         
+         if (code10 && istag ("PRODUCT"))
            {
              /* Finish old solvable, but only if it wasn't created
                 on demand without seeing a PRODUCT entry.  */
@@ -250,60 +338,88 @@ repo_add_content(Repo *repo, FILE *fp)
              handle = repodata_get_handle(data, s - pool->solvables - repo->start);
            }
          if (istag ("VERSION"))
-           /* without a release? but that's like zypp implements it */
-           s->evr = makeevr(pool, value);
-         else if (istag ("DISTPRODUCT"))
+           {
+             if (code11)
+               {
+                 repo_set_str(repo, s - pool->solvables, PRODUCT_VERSION, value);
+                 product_version = strdup(value);
+               }
+             else
+               /* without a release? but that's like zypp implements it */
+               s->evr = makeevr(pool, value);
+           }
+         else if (code11 && istag ("NAME"))
+           {
+             repo_set_str(repo, s - pool->solvables, PRODUCT_NAME, value);
+             product_name = strdup(value);
+           }
+         else if (code11 && istag ("DISTRIBUTION"))
+           repo_set_str(repo, s - pool->solvables, PRODUCT_DISTRIBUTION, value);
+         else if (code11 && istag ("FLAVOR"))
+           repo_set_str(repo, s - pool->solvables, PRODUCT_FLAVOR, value);
+         else if (istag ("DATADIR"))
+           repo_set_str(repo, s - pool->solvables, SUSETAGS_DATADIR, value);
+         else if (istag ("UPDATEURLS"))
+           add_multiple_strings(data, handle, PRODUCT_UPDATEURLS, value);
+         else if (istag ("EXTRAURLS"))
+           add_multiple_strings(data, handle, PRODUCT_EXTRAURLS, value);
+         else if (istag ("OPTIONALURLS"))
+           add_multiple_strings(data, handle, PRODUCT_OPTIONALURLS, value);
+         else if (istag ("SHORTLABEL"))
+           repo_set_str(repo, s - pool->solvables, PRODUCT_SHORTLABEL, value);
+         else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
+           repo_set_str(repo, s - pool->solvables, SOLVABLE_SUMMARY, value);
+         else if (!strncmp (key, "LABEL.", 6))
+           repo_set_str(repo, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
+         else if (istag ("FLAGS"))
+           add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
+         else if (istag ("RELNOTESURL"))
+           repodata_add_poolstr_array(data, handle, PRODUCT_RELNOTESURL, value);
+         else if (istag ("VENDOR"))
+           {
+             if (code11)
+               repo_set_str(repo, s - pool->solvables, PRODUCT_VENDOR, value);
+             else
+               s->vendor = str2id(pool, value, 1);
+           }
+         
+         /*
+          * Every tag below is Code10 only
+          * 
+          */
+         
+         else if (code10 && istag ("DISTPRODUCT"))
            /* DISTPRODUCT is for registration and Yast, not for the solver. */
            repo_set_str(repo, s - pool->solvables, PRODUCT_DISTPRODUCT, value);
-         else if (istag ("DISTVERSION"))
+         else if (code10 && istag ("DISTVERSION"))
            /* DISTVERSION is for registration and Yast, not for the solver. */
            repo_set_str(repo, s - pool->solvables, PRODUCT_DISTVERSION, value);
-         else if (istag ("VENDOR"))
-           s->vendor = str2id(pool, value, 1);
-         else if (istag ("ARCH"))
+         else if (code10 && istag ("ARCH"))
            /* Theoretically we want to have the best arch of the given
               modifiers which still is compatible with the system
               arch.  We don't know the latter here, though.  */
            s->arch = ARCH_NOARCH;
-         else if (istag ("PREREQUIRES"))
+         else if (code10 && istag ("PREREQUIRES"))
            s->requires = adddep(pool, &pd, s->requires, value, SOLVABLE_PREREQMARKER);
-         else if (istag ("REQUIRES"))
+         else if (code10 && istag ("REQUIRES"))
            s->requires = adddep(pool, &pd, s->requires, value, -SOLVABLE_PREREQMARKER);
-         else if (istag ("PROVIDES"))
+         else if (code10 && istag ("PROVIDES"))
            s->provides = adddep(pool, &pd, s->provides, value, 0);
-         else if (istag ("CONFLICTS"))
+         else if (code10 && istag ("CONFLICTS"))
            s->conflicts = adddep(pool, &pd, s->conflicts, value, 0);
-         else if (istag ("OBSOLETES"))
+         else if (code10 && istag ("OBSOLETES"))
            s->obsoletes = adddep(pool, &pd, s->obsoletes, value, 0);
-         else if (istag ("RECOMMENDS"))
+         else if (code10 && istag ("RECOMMENDS"))
            s->recommends = adddep(pool, &pd, s->recommends, value, 0);
-         else if (istag ("SUGGESTS"))
+         else if (code10 && istag ("SUGGESTS"))
            s->suggests = adddep(pool, &pd, s->suggests, value, 0);
-         else if (istag ("SUPPLEMENTS"))
+         else if (code10 && istag ("SUPPLEMENTS"))
            s->supplements = adddep(pool, &pd, s->supplements, value, 0);
-         else if (istag ("ENHANCES"))
+         else if (code10 && istag ("ENHANCES"))
            s->enhances = adddep(pool, &pd, s->enhances, value, 0);
-         else if (istag ("DATADIR"))
-           repo_set_str(repo, s - pool->solvables, SUSETAGS_DATADIR, value);
          /* FRESHENS doesn't seem to exist.  */
-         else if (istag ("TYPE"))
+         else if (code10 && istag ("TYPE"))
            repo_set_str(repo, s - pool->solvables, PRODUCT_TYPE, value);
-         else if (istag ("RELNOTESURL"))
-           repodata_add_poolstr_array(data, handle, PRODUCT_RELNOTESURL, value);
-         else if (istag ("UPDATEURLS"))
-           add_multiple_strings(data, handle, PRODUCT_UPDATEURLS, value);
-         else if (istag ("EXTRAURLS"))
-           add_multiple_strings(data, handle, PRODUCT_EXTRAURLS, value);
-         else if (istag ("OPTIONALURLS"))
-           add_multiple_strings(data, handle, PRODUCT_OPTIONALURLS, value);
-         else if (istag ("SHORTLABEL"))
-           repo_set_str(repo, s - pool->solvables, PRODUCT_SHORTLABEL, value);
-         else if (istag ("LABEL")) /* LABEL is the products SUMMARY. */
-           repo_set_str(repo, s - pool->solvables, SOLVABLE_SUMMARY, value);
-         else if (!strncmp (key, "LABEL.", 6))
-           repo_set_str(repo, s - pool->solvables, pool_id2langid(pool, SOLVABLE_SUMMARY, key + 6, 1), value);
-         else if (istag ("FLAGS"))
-           add_multiple_strings(data, handle, PRODUCT_FLAGS, value);
 
          /* XXX do something about LINGUAS and ARCH?
           * <ma>: Don't think so. zypp does not use or propagate them.
@@ -314,13 +430,38 @@ repo_add_content(Repo *repo, FILE *fp)
        fprintf (stderr, "malformed line: %s\n", line);
     }
 
-  if (!s->arch)
-    s->arch = ARCH_NOARCH;
-  if (s && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-    s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-  if (s)
-    s->supplements = repo_fix_legacy(repo, s->provides, s->supplements, 0);
+  if (!s)
+    {
+      fprintf(stderr, "No product solvable created !\n");
+      exit(1);
+    }
+  if (code11)
+    {
+      if (!product_name) 
+        {
+         fprintf(stderr, "Product must have a name !\n");
+         exit(1);
+       }
+      if (!product_version) 
+        {
+         fprintf(stderr, "Product must have a version !\n");
+         exit(1);
+       }
+      const char *product = join(&pd, "product(", product_name, ")");
+      s->provides = adddep(pool, &pd, s->provides, join(&pd, product, " = ", product_version), 0);
+      free(product_version);
+      free(product_name);
+    }
 
+  if (code10)
+    {
+      if (!s->arch)
+       s->arch = ARCH_NOARCH;
+      if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+       s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      s->supplements = repo_fix_legacy(repo, s->provides, s->supplements, 0);
+    }
+  
   if (pd.tmp)
     sat_free(pd.tmp);
   sat_free(line);
index edbbcc5..261c628 100644 (file)
@@ -454,8 +454,18 @@ finish_solvable(struct parsedata *pd, Solvable *s, int handle, Offset freshens)
     commit_diskusage (pd, handle);
 }
 
+
+/*
+ * parse susetags
+ * 
+ * fp: file to read from
+ * product: solvable representing the product (0 if none)
+ * language: current language (0 if none)
+ * flags: flags
+ */
+
 void
-repo_add_susetags(Repo *repo, FILE *fp, Id vendor, const char *language, int flags)
+repo_add_susetags(Repo *repo, FILE *fp, Id product, const char *language, int flags)
 {
   Pool *pool = repo->pool;
   char *line, *linep;
@@ -471,7 +481,8 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, const char *language, int fla
   Repodata *data = 0;
   Id blanr = -1;
   Id handle = 0;
-
+  Id vendor = 0;
+  
   if ((flags & SUSETAGS_EXTEND) && repo->nrepodata)
     indesc = 1;
   if (repo->nrepodata)
@@ -480,6 +491,14 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, const char *language, int fla
   else
     data = repo_add_repodata(repo, 0);
 
+  if (product)
+    {
+      if (!strncmp (id2str(pool, pool->solvables[product].name), "product:", 8))
+        vendor = pool->solvables[product].vendor;
+      else
+        vendor = str2id(pool, repo_lookup_str(pool->solvables + product, PRODUCT_VENDOR), 0);
+    }
+  
   memset(&pd, 0, sizeof(pd));
   line = malloc(1024);
   aline = 1024;
@@ -659,30 +678,43 @@ repo_add_susetags(Repo *repo, FILE *fp, Id vendor, const char *language, int fla
          /* Now see if we know this solvable already.  If we found neither
             the name nor the arch at all in this repo
             there's no chance of finding the exact solvable either.  */
-         if (indesc >= 2 && name && arch)
+         if (name && arch)
            {
-             int n, nn;
-             /* Now look for a solvable with the given name,evr,arch.
-                Our input is structured so, that the second set of =Pkg
-                lines comes in roughly the same order as the first set, so we 
-                have a hint at where to start our search, namely were we found
-                the last entry.  */
-             for (n = repo->start, nn = n + last_found_pack; n < repo->end; n++, nn++)
-               {
-                 if (nn >= repo->end)
-                   nn = repo->start;
-                 s = pool->solvables + nn;
-                 if (s->repo == repo && s->name == name && s->evr == evr && s->arch == arch)
-                   break;
-               }
-             if (n == repo->end)
-               s = 0;
-             else
+             if (product && (name == pool->solvables[product].name))
                {
-                 last_found_pack = nn - repo->start;
-                 handle = repodata_get_handle(data, last_found_pack);
+                 s = pool->solvables + product;
+                 s->vendor = vendor;
+                 s->arch = arch;
+                 s->evr = evr;
+                 handle = repodata_get_handle(data, s - pool->solvables - repo->start);
+                 last_found_pack = (s - pool->solvables) - repo->start;
+               }
+             else if (indesc >= 2)
+               {
+                 int n, nn;
+                 /* Now look for a solvable with the given name,evr,arch.
+                  Our input is structured so, that the second set of =Pkg
+                  lines comes in roughly the same order as the first set, so we 
+                  have a hint at where to start our search, namely were we found
+                  the last entry.  */
+                 for (n = repo->start, nn = n + last_found_pack; n < repo->end; n++, nn++)
+                   {
+                     if (nn >= repo->end)
+                       nn = repo->start;
+                     s = pool->solvables + nn;
+                     if (s->repo == repo && s->name == name && s->evr == evr && s->arch == arch)
+                       break;
+                   }
+                 if (n == repo->end)
+                   s = 0;
+                 else
+                   {
+                     last_found_pack = nn - repo->start;
+                     handle = repodata_get_handle(data, last_found_pack);
+                   }
                }
            }
+         
 
          /* And if we still don't have a solvable, create a new one.  */
          if (!s)
index 880844a..8030d0f 100644 (file)
@@ -12,4 +12,4 @@
 #define SUSETAGS_KINDS_SEPARATELY 1
 #define SUSETAGS_EXTEND 2
 
-extern void repo_add_susetags(Repo *repo, FILE *fp, Id vendor, const char *language, int flags);
+extern void repo_add_susetags(Repo *repo, FILE *fp, Id product, const char *language, int flags);
index 3932e44..7a48354 100644 (file)
@@ -79,7 +79,7 @@ main(int argc, char **argv)
   const char *attrname = 0;
   const char *descrdir = 0;
   const char *basefile = 0;
-  Id vendor = 0;
+  Id product = 0;
   int flags = 0;
   int c;
 
@@ -121,8 +121,8 @@ main(int argc, char **argv)
          exit(1);
        }
       repo_add_content(repo, fp);
-      if (!strncmp (id2str(pool, pool->solvables[repo->start].name), "product:", 8))
-        vendor = pool->solvables[repo->start].vendor;
+      product = repo->start;
+
       fclose (fp);
     }
   if (attrname)
@@ -139,6 +139,10 @@ main(int argc, char **argv)
       }
     }
 
+  /*
+   * descrdir path given, open files and read from there
+   */
+  
   if (descrdir)
     {
       char *fnp;
@@ -185,7 +189,7 @@ main(int argc, char **argv)
                  perror(fn);
                  exit(1);
                }
-             repo_add_susetags(repo, fp, vendor, 0, flags);
+             repo_add_susetags(repo, fp, product, 0, flags);
              fclose(fp);
            }
          else if (!strcmp(fn, "packages.DU") || !strcmp(fn, "packages.DU.gz"))
@@ -197,7 +201,7 @@ main(int argc, char **argv)
                  perror(fn);
                  exit(1);
                }
-             repo_add_susetags(repo, fp, vendor, 0, flags | SUSETAGS_EXTEND);
+             repo_add_susetags(repo, fp, product, 0, flags | SUSETAGS_EXTEND);
              fclose(fp);
            }
          else if (!strcmp(fn, "packages.FL") || !strcmp(fn, "packages.FL.gz"))
@@ -210,7 +214,7 @@ main(int argc, char **argv)
                  perror(fn);
                  exit(1);
                }
-             repo_add_susetags(repo, fp, vendor, 0, flags | SUSETAGS_EXTEND);
+             repo_add_susetags(repo, fp, product, 0, flags | SUSETAGS_EXTEND);
              fclose(fp);
 #else
              /* ignore for now. reactivate when filters work */
@@ -238,7 +242,7 @@ main(int argc, char **argv)
                  perror(fn);
                  exit(1);
                }
-             repo_add_susetags(repo, fp, vendor, lang, flags | SUSETAGS_EXTEND);
+             repo_add_susetags(repo, fp, product, lang, flags | SUSETAGS_EXTEND);
              fclose(fp);
            }
        }
@@ -248,7 +252,8 @@ main(int argc, char **argv)
       free(fnp);
     }
   else
-    repo_add_susetags(repo, stdin, vendor, 0, flags);
+    /* read data from stdin */
+    repo_add_susetags(repo, stdin, product, 0, flags);
 
   tool_write(repo, basefile, attrname);
   pool_free(pool);