- add repo_mdk_add_info() function to parse the M&M info.xml file
authorMichael Schroeder <mls@suse.de>
Fri, 23 Mar 2012 13:36:24 +0000 (14:36 +0100)
committerMichael Schroeder <mls@suse.de>
Fri, 23 Mar 2012 13:36:24 +0000 (14:36 +0100)
ext/libsolvext.ver
ext/repo_mdk.c
ext/repo_mdk.h
ext/repo_rpmmd.c
tools/mdk2solv.c

index de8a0f8..dadd339 100644 (file)
@@ -11,6 +11,7 @@ SOLV_1.0 {
                repo_add_deltainfoxml;
                repo_add_helix;
                repo_add_mdk;
+               repo_add_mdk_info;
                repo_add_products;
                repo_add_pubkeys;
                repo_add_releasefile_products;
index 6e44c98..c393b50 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <expat.h>
 
 #include "pool.h"
 #include "repo.h"
@@ -252,3 +253,345 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
     repodata_internalize(data);
   return 0;
 }
+
+enum state {
+  STATE_START,
+  STATE_MEDIA_INFO,
+  STATE_INFO,
+  NUMSTATES
+};
+
+struct stateswitch {
+  enum state from;
+  char *ename;
+  enum state to;
+  int docontent;
+};
+
+/* must be sorted by first column */
+static struct stateswitch stateswitches[] = {
+  { STATE_START, "media_info", STATE_MEDIA_INFO, 0 },
+  { STATE_MEDIA_INFO, "info", STATE_INFO, 1 },
+  { NUMSTATES }
+};
+
+struct parsedata {
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  int depth;
+  enum state state;
+  int statedepth;
+  char *content;
+  int lcontent;
+  int acontent;
+  int docontent;
+  struct stateswitch *swtab[NUMSTATES];
+  enum state sbtab[NUMSTATES];
+  Solvable *solvable;
+  Hashtable joinhash;
+  Hashmask joinhashmask;
+};
+
+static inline const char *
+find_attr(const char *txt, const char **atts)
+{
+  for (; *atts; atts += 2)
+    {
+      if (!strcmp(*atts, txt))
+        return atts[1];
+    }
+  return 0;
+}
+
+static Hashtable
+joinhash_init(Repo *repo, Hashmask *hmp)
+{
+  Hashmask hm = mkmask(repo->nsolvables);
+  Hashtable ht = solv_calloc(hm + 1, sizeof(*ht));
+  Hashval h, hh;
+  Solvable *s;
+  int i;
+
+  FOR_REPO_SOLVABLES(repo, i, s)
+    {
+      hh = HASHCHAIN_START;
+      h = s->name & hm;
+      while (ht[h])
+        h = HASHCHAIN_NEXT(h, hh, hm);
+      ht[h] = i;
+    }
+  *hmp = hm;
+  return ht;
+}
+
+static Solvable *
+joinhash_lookup(Repo *repo, Hashtable ht, Hashmask hm, const char *fn, const char *distepoch)
+{
+  Hashval h, hh;
+  const char *p, *vrstart, *vrend;
+  Id name, arch;
+
+  if (!fn || !*fn)
+    return 0;
+  if (distepoch && !*distepoch)
+    distepoch = 0;
+  p = fn + strlen(fn);
+  while (--p > fn)
+    if (*p == '.')
+      break;
+  if (p == fn)
+    return 0;
+  arch = pool_str2id(repo->pool, p + 1, 0);
+  if (!arch)
+    return 0;
+  if (distepoch)
+    {
+      while (--p > fn)
+        if (*p == '-')
+          break;
+      if (p == fn)
+       return 0;
+    }
+  vrend = p;
+  while (--p > fn)
+    if (*p == '-')
+      break;
+  if (p == fn)
+    return 0;
+  while (--p > fn)
+    if (*p == '-')
+      break;
+  if (p == fn)
+    return 0;
+  vrstart = p + 1;
+  name = pool_strn2id(repo->pool, fn, p - fn, 0);
+  if (!name)
+    return 0;
+  hh = HASHCHAIN_START;
+  h = name & hm;
+  while (ht[h])
+    {
+      Solvable *s = repo->pool->solvables + ht[h];
+      if (s->name == name && s->arch == arch)
+       {
+         /* too bad we don't know the epoch... */
+         const char *evr = pool_id2str(repo->pool, s->evr);
+         for (p = evr; *p >= '0' && *p <= '9'; p++)
+           ;
+         if (p > evr && *p == ':')
+           evr = p + 1;
+         if (distepoch)
+           {
+              if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == ':' && !strcmp(distepoch, evr + (vrend - vrstart + 1)))
+               return s;
+           }
+          else if (!strncmp(evr, vrstart, vrend - vrstart) && evr[vrend - vrstart] == 0)
+           return s;
+       }
+      h = HASHCHAIN_NEXT(h, hh, hm);
+    }
+  return 0;
+}
+
+static void
+set_sourcerpm(Repodata *data, Solvable *s, Id handle, const char *sourcerpm)
+{
+  const char *p, *sevr, *sarch, *name, *evr;
+  Pool *pool;
+
+  p = strrchr(sourcerpm, '.');
+  if (!p || strcmp(p, ".rpm") != 0)
+    return;
+  p--;
+  while (p > sourcerpm && *p != '.')
+    p--;
+  if (*p != '.' || p == sourcerpm)
+    return;
+  sarch = p-- + 1;
+  while (p > sourcerpm && *p != '-')
+    p--;
+  if (*p != '-' || p == sourcerpm)
+    return;
+  p--;
+  while (p > sourcerpm && *p != '-')
+    p--;
+  if (*p != '-' || p == sourcerpm)
+    return;
+  sevr = p + 1;
+  pool = s->repo->pool;
+  if (!strcmp(sarch, "src.rpm"))
+    repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_SRC);
+  else if (!strcmp(sarch, "nosrc.rpm"))
+    repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
+  else
+    repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
+  evr = pool_id2str(pool, s->evr);
+  if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
+    repodata_set_void(data, handle, SOLVABLE_SOURCEEVR);
+  else
+    repodata_set_id(data, handle, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
+  name = pool_id2str(pool, s->name);
+  if (name && !strncmp(sourcerpm, name, sevr - sourcerpm - 1) && name[sevr - sourcerpm - 1] == 0)
+    repodata_set_void(data, handle, SOLVABLE_SOURCENAME);
+  else
+    repodata_set_id(data, handle, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcerpm, sevr - sourcerpm - 1, 1));
+}
+
+
+static void XMLCALL
+startElement(void *userData, const char *name, const char **atts)
+{
+  struct parsedata *pd = userData;
+  Pool *pool = pd->pool;
+  struct stateswitch *sw;
+
+  if (pd->depth != pd->statedepth)
+    {
+      pd->depth++;
+      return;
+    }
+  pd->depth++;
+  if (!pd->swtab[pd->state])
+    return;
+  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)
+    if (!strcmp(sw->ename, name))
+      break;
+  if (sw->from != pd->state)
+    return;
+  pd->state = sw->to;
+  pd->docontent = sw->docontent;
+  pd->statedepth = pd->depth;
+  pd->lcontent = 0;
+  *pd->content = 0;
+  switch (pd->state)
+    {
+    case STATE_INFO:
+      {
+       const char *fn = find_attr("fn", atts);
+       const char *distepoch = find_attr("distepoch", atts);
+       const char *str;
+       pd->solvable = joinhash_lookup(pd->repo, pd->joinhash, pd->joinhashmask, fn, distepoch);
+       if (!pd->solvable)
+         break;
+       str = find_attr("url", atts);
+       if (str && *str)
+         repodata_set_str(pd->data, pd->solvable - pool->solvables, SOLVABLE_URL, str);
+       str = find_attr("license", atts);
+       if (str && *str)
+         repodata_set_poolstr(pd->data, pd->solvable - pool->solvables, SOLVABLE_LICENSE, str);
+       str = find_attr("sourcerpm", atts);
+       if (str && *str)
+         set_sourcerpm(pd->data, pd->solvable, pd->solvable - pool->solvables, str);
+        break;
+      }
+    default:
+      break;
+    }
+}
+
+static void XMLCALL
+endElement(void *userData, const char *name)
+{
+  struct parsedata *pd = userData;
+  Solvable *s = pd->solvable;
+  if (pd->depth != pd->statedepth)
+    {
+      pd->depth--;
+      return;
+    }
+  pd->depth--;
+  pd->statedepth--;
+  switch (pd->state)
+    {
+    case STATE_INFO:
+      if (s && *pd->content)
+        repodata_set_str(pd->data, s - pd->pool->solvables, SOLVABLE_DESCRIPTION, pd->content);
+      break;
+    default:
+      break;
+    }
+  pd->state = pd->sbtab[pd->state];
+  pd->docontent = 0;
+}
+
+static void XMLCALL
+characterData(void *userData, const XML_Char *s, int len)
+{
+  struct parsedata *pd = userData;
+  int l;
+  char *c;
+  if (!pd->docontent)
+    return;
+  l = pd->lcontent + len + 1;
+  if (l > pd->acontent)
+    {
+      pd->content = solv_realloc(pd->content, l + 256);
+      pd->acontent = l + 256;
+    }
+  c = pd->content + pd->lcontent;
+  pd->lcontent += len;
+  while (len-- > 0)
+    *c++ = *s++;
+  *c = 0;
+}
+
+#define BUFF_SIZE 8192
+
+int
+repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
+{
+  Repodata *data;
+  struct parsedata pd;
+  char buf[BUFF_SIZE];
+  int i, l;
+  struct stateswitch *sw;
+  XML_Parser parser;
+
+  if (!(flags & REPO_EXTEND_SOLVABLES))
+    {
+      pool_debug(repo->pool, SOLV_ERROR, "repo_add_mdk_info: can only extend existing solvables\n");
+      return -1;
+    }
+
+  data = repo_add_repodata(repo, flags);
+
+  memset(&pd, 0, sizeof(pd));
+  pd.repo = repo;
+  pd.pool = repo->pool;
+  pd.data = data;
+
+  pd.content = solv_malloc(256);
+  pd.acontent = 256;
+
+  pd.joinhash = joinhash_init(repo, &pd.joinhashmask);
+
+  for (i = 0, sw = stateswitches; sw->from != NUMSTATES; i++, sw++)
+    {
+      if (!pd.swtab[sw->from])
+        pd.swtab[sw->from] = sw;
+      pd.sbtab[sw->to] = sw->from;
+    }
+
+  parser = XML_ParserCreate(NULL);
+  XML_SetUserData(parser, &pd);
+  XML_SetElementHandler(parser, startElement, endElement);
+  XML_SetCharacterDataHandler(parser, characterData);
+  for (;;)
+    {
+      l = fread(buf, 1, sizeof(buf), fp);
+      if (XML_Parse(parser, buf, l, l == 0) == XML_STATUS_ERROR)
+        {
+          pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
+          break;
+        }
+      if (l == 0)
+        break;
+    }
+  XML_ParserFree(parser);
+  solv_free(pd.content);
+  solv_free(pd.joinhash);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
index 7a04b38..270c42e 100644 (file)
@@ -6,4 +6,5 @@
  */
 
 extern int repo_add_mdk(Repo *repo, FILE *fp, int flags);
+extern int repo_add_mdk_info(Repo *repo, FILE *fp, int flags);
 
index 43cf2f9..efb134c 100644 (file)
@@ -578,7 +578,7 @@ set_description_author(Repodata *data, Id handle, char *str, struct parsedata *p
  */
 
 static void
-set_sourcerpm(Repodata *data, Solvable *s, Id handle, char *sourcerpm)
+set_sourcerpm(Repodata *data, Solvable *s, Id handle, const char *sourcerpm)
 {
   const char *p, *sevr, *sarch, *name, *evr;
   Pool *pool;
index 769b5ba..db6c97b 100644 (file)
@@ -6,8 +6,8 @@
  */
 
 /*
- * comps2solv.c
- * 
+ * mdk2solv.c
+ *
  * parse Mandriva/Mageie synthesis file
  *
  * reads from stdin
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <getopt.h>
 
 #include "pool.h"
 #include "repo.h"
 #include "repo_mdk.h"
+#include "solv_xfopen.h"
 #include "common_write.h"
 
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "mdk2solv [-i <infoxml>]\n"
+          "  reads a 'synthesis' repository from <stdin> and writes a .solv file to <stdout>\n"
+          "  -i : info.xml file for extra attributes\n"
+          "  -h : print help & exit\n"
+         );
+   exit(status);
+}
+
 int
 main(int argc, char **argv)
 {
-  Pool *pool = pool_create();
-  Repo *repo = repo_create(pool, "<stdin>");
-  repo_add_mdk(repo, stdin, 0);
+  Pool *pool;
+  Repo *repo;
+  char *infofile;
+  int c;
+
+  while ((c = getopt(argc, argv, "i:")) >= 0)
+    {
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       case 'i':
+         infofile = optarg;
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  pool = pool_create();
+  repo = repo_create(pool, "<stdin>");
+  repo_add_mdk(repo, stdin, REPO_NO_INTERNALIZE);
+  if (infofile)
+    {
+      FILE *fp = solv_xfopen(infofile, "r");
+      if (!fp)
+       {
+         perror(infofile);
+         exit(1);
+       }
+      repo_add_mdk_info(repo, fp, REPO_EXTEND_SOLVABLES | REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
+      fclose(fp);
+    }
+  repo_internalize(repo);
   tool_write(repo, 0, 0);
   pool_free(pool);
   exit(0);