- parser for deltainfo.xml, stores yum-presto xml information into
authorDuncan Mac-Vicar P <dmacvicar@suse.de>
Thu, 8 May 2008 19:59:20 +0000 (19:59 +0000)
committerDuncan Mac-Vicar P <dmacvicar@suse.de>
Thu, 8 May 2008 19:59:20 +0000 (19:59 +0000)
  the extra section of the solv files.
- collects all information, and outputs it.
- only needs to save the struct to the solvfile (one liner?)
- also pending: add support for repo2solv.sh

tools/CMakeLists.txt
tools/deltainfoxml2solv.c [new file with mode: 0644]
tools/repo_deltainfoxml.c [new file with mode: 0644]
tools/repo_deltainfoxml.h [new file with mode: 0644]

index e85b602..d68c4dd 100644 (file)
@@ -33,6 +33,10 @@ SET(updateinfoxml2solv_REPOS updateinfoxml2solv.c repo_updateinfoxml.h repo_upda
 ADD_EXECUTABLE( updateinfoxml2solv ${updateinfoxml2solv_REPOS} )
 TARGET_LINK_LIBRARIES( updateinfoxml2solv satsolver ${EXPAT_LIBRARY})
 
+SET(deltainfoxml2solv_REPOS deltainfoxml2solv.c repo_deltainfoxml.h repo_deltainfoxml.c repo_write.c common_write.c)
+ADD_EXECUTABLE( deltainfoxml2solv ${deltainfoxml2solv_REPOS} )
+TARGET_LINK_LIBRARIES( deltainfoxml2solv satsolver ${EXPAT_LIBRARY})
+
 SET(dumpsolv_REPOS dumpsolv.c)
 ADD_EXECUTABLE( dumpsolv ${dumpsolv_REPOS} )
 TARGET_LINK_LIBRARIES( dumpsolv satsolver)
@@ -51,6 +55,7 @@ install(TARGETS
                 rpmdb2solv
                 rpms2solv
                 updateinfoxml2solv
+                deltainfoxml2solv
    DESTINATION ${BIN_INSTALL_DIR} )
 
 install(PROGRAMS repo2solv.sh DESTINATION ${BIN_INSTALL_DIR} )
diff --git a/tools/deltainfoxml2solv.c b/tools/deltainfoxml2solv.c
new file mode 100644 (file)
index 0000000..a0fe6c2
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_deltainfoxml.h"
+#include "common_write.h"
+
+static void
+usage(const char *err)
+{
+  if (err)
+    fprintf(stderr, "\n** Error:\n  %s\n", err);
+  fprintf(stderr, "\nUsage:\n"
+          "deltainfoxml2solv [-a][-h][-k][-n <attrname>]\n"
+         "  reads a 'deltainfo.xml' file from <stdin> and writes a .solv file to <stdout>\n"
+         "  -h : print help & exit\n"
+         "  -k : don't mix kinds (experimental!)\n"
+         "  -n <name>: save attributes as <name>.attr\n"
+        );
+   exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+  int flags = 0;
+  char *attrname = 0;
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<stdin>");
+
+  argv++;
+  argc--;
+  while (argc--)
+    {
+      const char *s = argv[0];
+      if (*s++ == '-')
+        while (*s)
+          switch (*s++)
+           {
+             case 'h': usage(NULL); break;
+             case 'n':
+               if (argc)
+                 {
+                   attrname = argv[1];
+                   argv++;
+                   argc--;
+                 }
+               else
+                 usage("argument required for '-n'");
+               break;
+             case 'k':
+             break;
+             default : break;
+           }
+      argv++;
+    }
+
+  repo_add_deltainfoxml(repo, stdin, flags);
+  tool_write(repo, 0, 0);
+  pool_free(pool);
+  exit(0);
+}
diff --git a/tools/repo_deltainfoxml.c b/tools/repo_deltainfoxml.c
new file mode 100644 (file)
index 0000000..f2e0c5a
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2007, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define DO_ARRAY 1
+
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <expat.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_updateinfoxml.h"
+#include "tools_util.h"
+/*
+ * <deltainfo>
+ *   <newpackage name="libtool" epoch="0" version="1.5.24" release="6.fc9" arch="i386">
+ *     <delta oldepoch="0" oldversion="1.5.24" oldrelease="3.fc8">
+ *       <filename>DRPMS/libtool-1.5.24-3.fc8_1.5.24-6.fc9.i386.drpm</filename>
+ *       <sequence>libtool-1.5.24-3.fc8-d3571f98b048b1a870e40241bb46c67ab4</sequence>
+ *       <size>22452</size>
+ *       <checksum type="sha">8f05394695dee9399c204614e21e5f6848990ab7</checksum>
+ *     </delta>
+ *     <delta oldepoch="0" oldversion="1.5.22" oldrelease="11.fc7">
+ *       <filename>DRPMS/libtool-1.5.22-11.fc7_1.5.24-6.fc9.i386.drpm</filename>
+ *        <sequence>libtool-1.5.22-11.fc7-e82691677eee1e83b4812572c5c9ce8eb</sequence>
+ *        <size>110362</size>
+ *        <checksum type="sha">326658fee45c0baec1e70231046dbaf560f941ce</checksum>
+ *      </delta>
+ *    </newpackage>
+ *  </deltainfo>
+ */
+
+enum state {
+  STATE_START,
+  STATE_DELTAINFO,      /* 1 */
+  STATE_NEWPACKAGE,     /* 2 */
+  STATE_DELTA,          /* 3 */
+  STATE_FILENAME,       /* 4 */
+  STATE_SEQUENCE,       /* 5 */
+  STATE_SIZE,           /* 6 */
+  STATE_CHECKSUM,       /* 7 */
+  STATE_LOCATION,       /* 8 */
+  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,       "deltainfo",       STATE_DELTAINFO,   0 },
+  /* compatibility with old yum-presto */
+  { STATE_START,       "prestodelta",     STATE_DELTAINFO,   0 },
+  /* allow starting from newpackage directly */
+  { STATE_START,       "newpackage",      STATE_NEWPACKAGE,  0 },
+  { STATE_DELTAINFO,   "newpackage",      STATE_NEWPACKAGE,  0 },
+  { STATE_NEWPACKAGE,  "delta",           STATE_DELTA,       0 },
+  /* compatibility with yum-presto */
+  { STATE_DELTA,       "filename",        STATE_FILENAME,    1 },
+  { STATE_DELTA,       "location",        STATE_LOCATION,    0 },
+  { STATE_DELTA,       "sequence",        STATE_SEQUENCE,    1 },
+  { STATE_DELTA,       "size",            STATE_SIZE,        1 },
+  { STATE_DELTA,       "checksum",        STATE_CHECKSUM,    1 },
+  { NUMSTATES }
+};
+
+/* Cumulated info about the current deltarpm or patchrpm */
+struct deltarpm {
+  Id locdir;
+  Id locname;
+  Id locevr;
+  Id locsuffix;
+  unsigned buildtime;
+  unsigned downloadsize, archivesize;
+  char *filechecksum;
+  
+  /* Baseversion.  deltarpm only has one. */
+  Id *bevr;
+  unsigned nbevr;
+  Id seqname;
+  Id seqevr;
+  char *seqnum;
+};
+
+struct parsedata {
+  int depth;
+  enum state state;
+  int statedepth;
+  char *content;
+  int lcontent;
+  int acontent;
+  int docontent;
+  Pool *pool;
+  Repo *repo;
+  Repodata *data;
+  unsigned int datanum;
+  
+  struct stateswitch *swtab[NUMSTATES];
+  enum state sbtab[NUMSTATES];
+  char *tempstr;
+  int ltemp;
+  int atemp;
+  struct deltarpm delta;
+  Id newpkgevr;
+  Id newpkgname;
+};
+
+/*
+ * find attribute
+ */
+
+static const char *
+find_attr(const char *txt, const char **atts)
+{
+  for (; *atts; atts += 2)
+    {
+      if (!strcmp(*atts, txt))
+        return atts[1];
+    }
+  return 0;
+}
+
+
+/*
+ * create evr (as Id) from 'epoch', 'version' and 'release' attributes
+ */
+
+static Id
+makeevr_atts(Pool *pool, struct parsedata *pd, const char **atts)
+{
+  const char *e, *v, *r, *v2;
+  char *c;
+  int l;
+
+  e = v = r = 0;
+  for (; *atts; atts += 2)
+    {
+      if (!strcmp(*atts, "oldepoch"))
+        e = atts[1];
+      else if (!strcmp(*atts, "epoch"))
+       e = atts[1];
+      else if (!strcmp(*atts, "version"))
+       v = atts[1];
+      else if (!strcmp(*atts, "oldversion"))
+       v = atts[1];
+      else if (!strcmp(*atts, "release"))
+       r = atts[1];
+      else if (!strcmp(*atts, "oldrelease"))
+       r = atts[1];
+    }
+  if (e && !strcmp(e, "0"))
+    e = 0;
+  if (v && !e)
+    {
+      for (v2 = v; *v2 >= '0' && *v2 <= '9'; v2++)
+        ;
+      if (v2 > v && *v2 == ':')
+       e = "0";
+    }
+  l = 1;
+  if (e)
+    l += strlen(e) + 1;
+  if (v)
+    l += strlen(v);
+  if (r)
+    l += strlen(r) + 1;
+  if (l > pd->acontent)
+    {
+      pd->content = realloc(pd->content, l + 256);
+      pd->acontent = l + 256;
+    }
+  c = pd->content;
+  if (e)
+    {
+      strcpy(c, e);
+      c += strlen(c);
+      *c++ = ':';
+    }
+  if (v)
+    {
+      strcpy(c, v);
+      c += strlen(c);
+    }
+  if (r)
+    {
+      *c++ = '-';
+      strcpy(c, r);
+      c += strlen(c);
+    }
+  *c = 0;
+  if (!*pd->content)
+    return 0;
+#if 0
+  fprintf(stderr, "evr: %s\n", pd->content);
+#endif
+  return str2id(pool, pd->content, 1);
+}
+
+static void parse_delta_location( struct parsedata *pd, 
+                                  const char* str )
+{
+    Pool *pool = pd->pool;
+    if (str)
+    {
+        /* Separate the filename into its different parts.
+           rpm/x86_64/alsa-1.0.14-31_31.2.x86_64.delta.rpm
+           --> dir = rpm/x86_64
+           name = alsa
+           evr = 1.0.14-31_31.2
+           suffix = x86_64.delta.rpm.  */
+        char *real_str = strdup(str);
+        char *s = real_str;
+        char *s1, *s2;
+        s1 = strrchr (s, '/');
+        if (s1)
+        {
+            pd->delta.locdir = strn2id(pool, s, s1 - s, 1);
+            s = s1 + 1;
+        }
+        /* Guess suffix.  */
+        s1 = strrchr (s, '.');
+        if (s1)
+        {
+            for (s2 = s1 - 1; s2 > s; s2--)
+                if (*s2 == '.')
+                    break;
+            if (!strcmp (s2, ".delta.rpm") || !strcmp (s2, ".patch.rpm"))
+            {
+                s1 = s2;
+                /* We accept one more item as suffix.  */
+                for (s2 = s1 - 1; s2 > s; s2--)
+                   if (*s2 == '.')
+                        break;
+                s1 = s2;
+                  }
+            if (*s1 == '.')
+                *s1++ = 0;
+            pd->delta.locsuffix = str2id(pool, s1, 1); 
+        }
+        /* Last '-'.  */
+        s1 = strrchr (s, '-');
+        if (s1)
+        {
+                  /* Second to last '-'.  */
+            for (s2 = s1 - 1; s2 > s; s2--)
+                if (*s2 == '-')
+                    break;
+        }
+        else
+            s2 = 0;
+        if (s2 > s && *s2 == '-')
+        {
+            *s2++ = 0;
+            pd->delta.locevr = str2id(pool, s2, 1);
+        }
+        pd->delta.locname = str2id(pool, s, 1);
+        free(real_str);
+    }
+}
+                                 
+static void XMLCALL
+startElement(void *userData, const char *name, const char **atts)
+{
+  struct parsedata *pd = userData;
+  Pool *pool = pd->pool;
+  struct stateswitch *sw;
+  const char *str;
+
+#if 0
+      fprintf(stderr, "start: [%d]%s\n", pd->state, name);
+#endif
+  if (pd->depth != pd->statedepth)
+    {
+      pd->depth++;
+      return;
+    }
+
+  pd->depth++;
+  for (sw = pd->swtab[pd->state]; sw->from == pd->state; sw++)  /* find name in statetable */
+    if (!strcmp(sw->ename, name))
+      break;
+  
+  if (sw->from != pd->state)
+    {
+#if 1
+      fprintf(stderr, "into unknown: [%d]%s (from: %d)\n", sw->to, name, sw->from);
+      exit( 1 );
+#endif
+      return;
+    }
+  pd->state = sw->to;
+  pd->docontent = sw->docontent;
+  pd->statedepth = pd->depth;
+  pd->lcontent = 0;
+  *pd->content = 0;
+
+  switch(pd->state)
+    {
+      case STATE_START:
+          break;
+      case STATE_NEWPACKAGE:
+          if ( (str = find_attr("name", atts)) )
+          {
+              pd->newpkgname = str2id(pool, str, 1);
+          }
+          break;
+          
+      case STATE_DELTA:
+          memset(&pd->delta, 0, sizeof (pd->delta));
+          *pd->tempstr = 0;
+          pd->ltemp = 0;
+          pd->delta.nbevr++;
+          pd->delta.bevr = sat_realloc (pd->delta.bevr, pd->delta.nbevr * sizeof(Id));
+          pd->delta.bevr[pd->delta.nbevr - 1] = makeevr_atts(pool, pd, atts);
+          break;
+      case STATE_FILENAME:
+          break;
+      case STATE_LOCATION:
+          parse_delta_location( pd, find_attr("href", atts));
+          break;
+    case STATE_SIZE:
+      break;
+    case STATE_SEQUENCE:
+      break;
+
+      case NUMSTATES+1:
+        split(NULL, NULL, 0); /* just to keep gcc happy about tools_util.h: static ... split() {...}  Urgs!*/
+      break;
+      default:
+      break;
+    }
+  return;
+}
+
+
+static void XMLCALL
+endElement(void *userData, const char *name)
+{
+  struct parsedata *pd = userData;
+  Pool *pool = pd->pool;
+  const char *str;
+
+#if 0
+      fprintf(stderr, "end: %s\n", name);
+#endif
+  if (pd->depth != pd->statedepth)
+    {
+      pd->depth--;
+#if 1
+      fprintf(stderr, "back from unknown %d %d %d\n", pd->state, pd->depth, pd->statedepth);
+#endif
+      return;
+    }
+
+  pd->depth--;
+  pd->statedepth--;
+  switch (pd->state)
+  {
+      case STATE_START:
+          break;
+      case STATE_NEWPACKAGE:
+          break;
+      case STATE_DELTA:
+      {
+#if DUMPOUT
+          int i;
+          struct deltarpm *d = &pd->delta;
+          fprintf (stderr, "found deltarpm for %s:\n", id2str(pool, pd->newpkgname));
+          fprintf (stderr, "   loc: %s %s %s %s\n", id2str(pool, d->locdir),
+                   id2str(pool, d->locname), id2str(pool, d->locevr),
+                   id2str(pool, d->locsuffix));
+          fprintf (stderr, "  size: %d down\n", d->downloadsize);
+          fprintf (stderr, "  chek: %s\n", d->filechecksum);
+          if (d->seqnum)
+         {
+              fprintf (stderr, "  base: %s\n",
+                       id2str(pool, d->bevr[0]));
+              fprintf (stderr, "            seq: %s\n",
+                       id2str(pool, d->seqname));
+              fprintf (stderr, "                 %s\n",
+                       id2str(pool, d->seqevr));
+              fprintf (stderr, "                 %s\n",
+                       d->seqnum);
+
+              fprintf(stderr, "OK\n");
+              
+              if (d->seqevr != d->bevr[0])
+                  fprintf (stderr, "XXXXX evr\n");
+              /* Name of package ("atom:xxxx") should match the sequence info
+                 name.  */
+              if (strcmp(id2str(pool, d->seqname), id2str(pool, pd->newpkgname) + 5))
+                  fprintf (stderr, "XXXXX name\n");
+         }
+          else
+         {
+              fprintf (stderr, "  base:");
+              for (i = 0; i < d->nbevr; i++)
+                  fprintf (stderr, " %s", id2str(pool, d->bevr[i]));
+              fprintf (stderr, "\n");
+         }
+#endif
+      }
+      free(pd->delta.filechecksum);
+      free(pd->delta.bevr);
+      free(pd->delta.seqnum);
+      break;
+      case STATE_FILENAME:
+          parse_delta_location(pd, pd->content);
+          break;
+      case STATE_CHECKSUM:
+      pd->delta.filechecksum = strdup(pd->content);
+      break;
+      case STATE_SIZE:
+          pd->delta.downloadsize = atoi(pd->content);
+          break;
+      case STATE_SEQUENCE:
+      if ((str = pd->content))
+      {
+         const char *s1, *s2;
+         s1 = strrchr(str, '-');
+         if (s1)
+          {
+             for (s2 = s1 - 1; s2 > str; s2--)
+               if (*s2 == '-')
+                    break;
+             if (*s2 == '-')
+              {
+                 for (s2 = s2 - 1; s2 > str; s2--)
+                      if (*s2 == '-')
+                          break;
+                 if (*s2 == '-')
+                  {
+                     pd->delta.seqevr = strn2id(pool, s2 + 1, s1 - s2 - 1, 1);
+                     pd->delta.seqname = strn2id(pool, str, s2 - str, 1);
+                     str = s1 + 1;
+                  }
+              }
+          }
+         pd->delta.seqnum = strdup(str);
+      }
+      default:
+      break;
+  }
+
+  pd->state = pd->sbtab[pd->state];
+  pd->docontent = 0;
+  
+  return;
+}
+
+
+static void XMLCALL
+characterData(void *userData, const XML_Char *s, int len)
+{
+  struct parsedata *pd = userData;
+  int l;
+  char *c;
+  if (!pd->docontent) {
+#if 0
+    char *dup = strndup( s, len );
+  fprintf(stderr, "Content: [%d]'%s'\n", pd->state, dup );
+  free( dup );
+#endif
+    return;
+  }
+  l = pd->lcontent + len + 1;
+  if (l > pd->acontent)
+    {
+      pd->content = 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
+
+void
+repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  struct parsedata pd;
+  char buf[BUFF_SIZE];
+  int i, l;
+  struct stateswitch *sw;
+
+  memset(&pd, 0, sizeof(pd));
+  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;
+    }
+  pd.pool = pool;
+  pd.repo = repo;
+  pd.data = repo_add_repodata(pd.repo, 0);
+
+  pd.content = malloc(256);
+  pd.acontent = 256;
+  pd.lcontent = 0;
+  pd.tempstr = malloc(256);
+  pd.atemp = 256;
+  pd.ltemp = 0;
+  XML_Parser 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)
+       {
+         fprintf(stderr, "repo_updateinfoxml: %s at line %u:%u\n", XML_ErrorString(XML_GetErrorCode(parser)), (unsigned int)XML_GetCurrentLineNumber(parser), (unsigned int)XML_GetCurrentColumnNumber(parser));
+         exit(1);
+       }
+      if (l == 0)
+       break;
+    }
+  XML_ParserFree(parser);
+
+  if (pd.data)
+    repodata_internalize(pd.data);
+
+  free(pd.content);
+  join_freemem();
+}
+
+/* EOF */
diff --git a/tools/repo_deltainfoxml.h b/tools/repo_deltainfoxml.h
new file mode 100644 (file)
index 0000000..a3a3eea
--- /dev/null
@@ -0,0 +1 @@
+void repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags);