- add support for archlinux packages/repos
authorMichael Schroeder <mls@suse.de>
Fri, 30 Mar 2012 12:12:54 +0000 (14:12 +0200)
committerMichael Schroeder <mls@suse.de>
Fri, 30 Mar 2012 12:12:54 +0000 (14:12 +0200)
CMakeLists.txt
ext/CMakeLists.txt
ext/libsolvext.ver
ext/repo_arch.c [new file with mode: 0644]
ext/repo_arch.h [new file with mode: 0644]
tools/CMakeLists.txt
tools/archpkgs2solv.c [new file with mode: 0644]
tools/archrepo2solv.c [new file with mode: 0644]
tools/mdk2solv.c

index 4540fa6..34829bf 100644 (file)
@@ -19,6 +19,7 @@ OPTION (ENABLE_COMPS "Build with fedora comps support?" OFF)
 OPTION (ENABLE_HELIXREPO "Build with helix repository support?" OFF)
 OPTION (ENABLE_DEBIAN "Build with debian database/repository support?" OFF)
 OPTION (ENABLE_MDKREPO "Build with mandriva/mageia repository support?" OFF)
+OPTION (ENABLE_ARCHREPO "Build with archlinux repository support?" OFF)
 
 OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF)
 
@@ -89,6 +90,7 @@ IF (NOT ENABLE_RPMDB AND
     NOT ENABLE_SUSEREPO AND
     NOT ENABLE_HELIXREPO AND
     NOT ENABLE_MDKREPO AND
+    NOT ENABLE_ARCHREPO AND
     NOT ENABLE_DEBIAN)
     SET (ENABLE_RPMDB ON)
     SET (ENABLE_RPMDB_PUBKEY ON)
@@ -136,7 +138,8 @@ TEST_BIG_ENDIAN (WORDS_BIGENDIAN)
 # should create config.h with #cmakedefine instead...
 FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN
   ENABLE_RPMDB ENABLE_RPMDB_PUBKEY ENABLE_RPMMD ENABLE_SUSEREPO ENABLE_COMPS
-  ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_DEBIAN ENABLE_LZMA_COMPRESSION)
+  ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN
+  ENABLE_LZMA_COMPRESSION)
   IF(${VAR})
     ADD_DEFINITIONS (-D${VAR}=1)
     SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
index 9e4a6f0..025f9cd 100644 (file)
@@ -57,6 +57,13 @@ IF (ENABLE_MDKREPO)
        repo_mdk.h)
 ENDIF (ENABLE_MDKREPO)
 
+IF (ENABLE_ARCHREPO)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       repo_arch.c)
+    SET (libsolvext_HEADERS ${libsolvext_HEADERS}
+       repo_arch.h)
+ENDIF (ENABLE_ARCHREPO)
+
 SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 SET (CMAKE_SHARED_LINKER_FLAGS "${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver")
 
index dadd339..e291f2c 100644 (file)
@@ -1,6 +1,8 @@
 SOLV_1.0 {
        global:
                pool_findfileconflicts;
+               repo_add_arch_pkg;
+               repo_add_arch_repo;
                repo_add_code11_products;
                repo_add_content;
                repo_add_comps;
diff --git a/ext/repo_arch.c b/ext/repo_arch.c
new file mode 100644 (file)
index 0000000..2777225
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "chksum.h"
+#include "solv_xfopen.h"
+#include "repo_arch.h"
+
+static long long parsenum(unsigned char *p, int cnt)
+{
+  long long x = 0;
+  if (!cnt)
+    return -1;
+  if (*p & 0x80)
+    {
+      /* binary format */
+      x = *p & 0x40 ? (-1 << 8 | *p)  : (*p ^ 0x80);
+      while (--cnt > 0)
+       x = (x << 8) | *p++;
+      return x;
+    }
+  while (cnt > 0 && (*p == ' ' || *p == '\t'))
+    cnt--, p++;
+  if (*p == '-')
+    return -1;
+  for (; cnt > 0 && *p >= '0' && *p < '8'; cnt--, p++)
+    x = (x << 3) | (*p - '0');
+  return x;
+}
+
+static int readblock(FILE *fp, unsigned char *blk)
+{
+  int r, l = 0;
+  while (l < 512)
+    {
+      r = fread(blk + l, 1, 512 - l, fp);
+      if (r <= 0)
+       return -1;
+      l += r;
+    }
+  return 0;
+}
+
+struct tarhead {
+  FILE *fp;
+  unsigned char blk[512];
+  int type;
+  long long length;
+  char *path;
+  int eof;
+  int ispax;
+  int off;
+  int end;
+};
+
+static char *getsentry(struct tarhead *th, char *s, int size)
+{
+  char *os = s;
+  if (th->eof || size <= 1)
+    return 0;
+  size--;      /* terminating 0 */
+  for (;;)
+    {
+      int i;
+      for (i = th->off; i < th->end; i++)
+       {
+         *s++ = th->blk[i];
+         size--;
+         if (!size || th->blk[i] == '\n')
+           {
+             th->off = i + 1;
+             *s = 0;
+             return os;
+           }
+       }
+      th->off = i;
+      if (th->length <= 0)
+       return 0;
+      if (readblock(th->fp, th->blk))
+       {
+         th->eof = 1;
+         return 0;
+       }
+      th->off = 0;
+      th->end = th->length > 512 ? 512 : th->length;
+      th->length -= th->end;
+    }
+}
+
+static void skipentry(struct tarhead *th)
+{
+  for (; th->length > 0; th->length -= 512)
+    {
+      if (readblock(th->fp, th->blk))
+       {
+         th->eof = 1;
+         th->length = 0;
+         return;
+       }
+    }
+  th->length = 0;
+  th->off = th->end = 0;
+}
+
+static void inittarhead(struct tarhead *th, FILE *fp)
+{
+  memset(th, 0, sizeof(*th));
+  th->fp = fp;
+}
+
+static void freetarhead(struct tarhead *th)
+{
+  solv_free(th->path);
+}
+
+static int gettarhead(struct tarhead *th)
+{
+  int l, type;
+  long long length;
+
+  th->path = solv_free(th->path);
+  th->ispax = 0;
+  th->type = 0;
+  th->length = 0;
+  th->off = 0;
+  th->end = 0;
+  if (th->eof)
+    return 0;
+  for (;;)
+    {
+      int r = readblock(th->fp, th->blk);
+      if (r)
+       {
+         if (feof(th->fp))
+           {
+             th->eof = 1;
+             return 0;
+           }
+         return -1;
+       }
+      if (th->blk[0] == 0)
+       {
+          th->eof = 1;
+         return 0;
+       }
+      length = parsenum(th->blk + 124, 12);
+      if (length < 0)
+       return -1;
+      type = 0;
+      switch (th->blk[156])
+       {
+       case 'S': case '0':
+         type = 1;     /* file */
+         break;
+       case '1':
+         /* hard link, special length magic... */
+         if (!th->ispax)
+           length = 0;
+         break;
+       case '5':
+         type = 2;     /* dir */
+         break;
+       case '2': case '3': case '4': case '6':
+         length = 0;
+         break;
+       case 'X': case 'x': case 'L':
+         {
+           char *data, *pp;
+           if (length < 1 || length >= 1024 * 1024)
+             return -1;
+           l = length;
+           data = pp = solv_malloc(l + 512);
+           for (; l > 0; l -= 512, pp += 512)
+             if (readblock(th->fp, (unsigned char *)pp))
+               {
+                 solv_free(data);
+                 return -1;
+               }
+           type = 3;           /* extension */
+           if (th->blk[156] == 'L')
+             {
+               solv_free(th->path);
+               th->path = data;
+               length = 0;
+               break;
+             }
+           pp = data;
+           while (length > 0)
+             {
+               int ll = 0;
+               int l;
+               for (l = 0; l < length && pp[l] >= '0' && pp[l] <= '9'; l++)
+                 ll = ll * 10 + (pp[l] - '0');
+               if (l == length || pp[l] != ' ' || ll < 1 || ll > length || pp[ll - 1] != '\n')
+                 {
+                   solv_free(data);
+                   return -1;
+                 }
+               length -= ll;
+               pp += l + 1;
+               ll -= l + 1;
+               pp[ll - 1] = 0;
+               if (!strncmp(pp, "path=", 5))
+                 {
+                   solv_free(th->path);
+                   th->path = solv_strdup(pp + 5);
+                 }
+               pp += ll;
+             }
+           solv_free(data);
+           th->ispax = 1;
+           length = 0;
+           break;
+         }
+       default:
+         type = 3;     /* extension */
+         break;
+       }
+      if ((type == 1 || type == 2) && !th->path)
+       {
+         char path[157];
+         memcpy(path, th->blk, 156);
+         path[156] = 0;
+         if (!memcmp(th->blk + 257, "ustar\0\060\060", 8) && !th->path && th->blk[345])
+           {
+             /* POSIX ustar with prefix */
+             char prefix[156];
+             memcpy(prefix, th->blk + 345, 155);
+             prefix[155] = 0;
+             l = strlen(prefix);
+             if (prefix[l - 1] == '/')
+               prefix[l - 1] = 0;
+             th->path = solv_dupjoin(prefix, "/", path);
+           }
+         else
+           th->path = solv_dupjoin(path, 0, 0);
+       }
+      if (type == 1 || type == 2)
+       {
+         l = strlen(th->path);
+         if (l && th->path[l - 1] == '/')
+           {
+             if (l > 1)
+               th->path[l - 1] = 0;
+             type = 2;
+           }
+       }
+      if (type != 3)
+       break;
+      while (length > 0)
+       {
+         r = readblock(th->fp, th->blk);
+         if (r)
+           return r;
+         length -= 512;
+       }
+    }
+  th->type = type;
+  th->length = length;
+  return 1;
+}
+
+static Offset
+adddep(Repo *repo, Offset olddeps, char *line)
+{
+  Pool *pool = repo->pool;
+  char *p;
+  Id id;
+
+  while (*line == ' ' && *line == '\t')
+    line++;
+  p = line;
+  while (*p && *p != ' ' && *p != '\t' && *p != '<' && *p != '=' && *p != '>')
+    p++;
+  id = pool_strn2id(pool, line, p - line, 1);
+  while (*p == ' ' && *p == '\t')
+    p++;
+  if (*p == '<' || *p == '=' || *p == '>')
+    {
+      int flags = 0;
+      for (;; p++)
+       {  
+         if (*p == '<')
+           flags |= REL_LT;
+         else if (*p == '=')
+           flags |= REL_EQ;
+         else if (*p == '>')
+           flags |= REL_GT;
+         else
+           break;
+       }
+      while (*p == ' ' && *p == '\t')
+        p++;
+      line = p;
+      while (*p && *p != ' ' && *p != '\t')
+       p++;
+      id = pool_rel2id(pool, id, pool_strn2id(pool, line, p - line, 1), flags, 1);
+    }
+  return repo_addid_dep(repo, olddeps, id, 0);
+}
+
+Id
+repo_add_arch_pkg(Repo *repo, const char *fn, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  FILE *fp;
+  struct tarhead th;
+  char line[4096];
+  int ignoreline;
+  Solvable *s;
+  int l, fd;
+  struct stat stb;
+  void *pkgidhandle = 0;
+
+  data = repo_add_repodata(repo, flags);
+  if ((fd = open(fn, O_RDONLY, 0)) < 0)
+    {
+      pool_debug(pool, SOLV_ERROR, "repo_add_arch_pkg: %s: %s\n", fn, strerror(errno));
+      return 0;
+    }
+  if (fstat(fd, &stb))
+    {
+      pool_debug(pool, SOLV_ERROR, "repo_add_arch_pkg: %s: fstat failed\n", fn);
+      close(fd);
+      return 0;
+    }
+  if (!(fp = solv_xfopen_fd(fn, fd, "r")))
+    {
+      pool_debug(pool, SOLV_ERROR, "repo_add_arch_pkg: %s: fdopen failed\n", fn);
+      close(fd);
+      return 0;
+    }
+  s = 0;
+  inittarhead(&th, fp);
+  while (gettarhead(&th) > 0)
+    {
+      if (th.type != 1 || strcmp(th.path, ".PKGINFO") != 0)
+       {
+          skipentry(&th);
+         continue;
+       }
+      ignoreline = 0;
+      s = pool_id2solvable(pool, repo_add_solvable(repo));
+      if (flags & ARCH_ADD_WITH_PKGID)
+       pkgidhandle = solv_chksum_create(REPOKEY_TYPE_MD5);
+      while (getsentry(&th, line, sizeof(line)))
+       {
+         l = strlen(line);
+         if (l == 0)
+           continue;
+         if (pkgidhandle)
+           solv_chksum_add(pkgidhandle, line, l);
+         if (line[l - 1] != '\n')
+           {
+             ignoreline = 1;
+             continue;
+           }
+         if (ignoreline)
+           {
+             ignoreline = 0;
+             continue;
+           }
+         line[--l] = 0;
+         if (l == 0 || line[0] == '#')
+           continue;
+         if (!strncmp(line, "pkgname = ", 10))
+           s->name = pool_str2id(pool, line + 10, 1);
+         else if (!strncmp(line, "pkgver = ", 9))
+           s->evr = pool_str2id(pool, line + 9, 1);
+         else if (!strncmp(line, "pkgdesc = ", 10))
+           {
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 10);
+             repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line + 10);
+           }
+         else if (!strncmp(line, "url = ", 6))
+           repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line + 6);
+         else if (!strncmp(line, "builddate = ", 12))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line + 12, 0, 10));
+         else if (!strncmp(line, "packager = ", 11))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line + 11);
+         else if (!strncmp(line, "size = ", 7))
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line + 7, 0, 10));
+         else if (!strncmp(line, "arch = ", 7))
+           s->arch = pool_str2id(pool, line + 7, 1);
+         else if (!strncmp(line, "license = ", 10))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_LICENSE, line + 10);
+         else if (!strncmp(line, "replaces = ", 11))
+           s->obsoletes = adddep(repo, s->obsoletes, line + 11);
+         else if (!strncmp(line, "group = ", 8))
+           repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_GROUP, line + 8);
+         else if (!strncmp(line, "depend = ", 9))
+           s->requires = adddep(repo, s->requires, line + 9);
+         else if (!strncmp(line, "optdepend = ", 12))
+           {
+             char *p = strchr(line, ':');
+             if (p)
+               *p = 0;
+             s->suggests = adddep(repo, s->suggests, line + 12);
+           }
+         else if (!strncmp(line, "conflict = ", 11))
+           s->conflicts = adddep(repo, s->conflicts, line + 11);
+         else if (!strncmp(line, "provides = ", 11))
+           s->provides = adddep(repo, s->provides, line + 11);
+       }
+      break;
+    }
+  freetarhead(&th);
+  fclose(fp);
+  if (s && !s->name)
+    {
+      repo_free_solvable_block(repo, s - pool->solvables, 1, 1);
+      s = 0;
+    }
+  if (s)
+    {
+      if (!s->arch)
+       s->arch = ARCH_NOARCH;
+      if (!s->evr)
+       s->evr = ID_EMPTY;
+      s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      repodata_set_location(data, s - pool->solvables, 0, 0, fn);
+      repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size);
+      if (pkgidhandle)
+       {
+         unsigned char pkgid[16];
+         solv_chksum_free(pkgidhandle, pkgid);
+         repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
+         pkgidhandle = 0;
+       }
+    }
+  if (pkgidhandle)
+    solv_chksum_free(pkgidhandle, 0);
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return s ? s - pool->solvables : 0;
+}
+
+static char *getsentrynl(struct tarhead *th, char *s, int size)
+{
+  int l;
+  if (!getsentry(th, s, size))
+    {
+      *s = 0;  /* eof */
+      return 0;
+    }
+  l = strlen(s);
+  if (!l)
+    return 0;
+  if (l && s[l - 1] == '\n')
+    {
+      s[l - 1] = 0;
+      return s;
+    }
+  while (getsentry(th, s, size))
+    {
+      l = strlen(s);
+      if (!l || s[l - 1] == '\n')
+       return 0;
+    }
+  *s = 0;      /* eof */
+  return 0;
+}
+
+int
+repo_add_arch_repo(Repo *repo, FILE *fp, int flags)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  data = repo_add_repodata(repo, flags);
+  struct tarhead th;
+  char *lastdn = 0;
+  int l, lastdnlen = 0;
+  char line[4096];
+  Solvable *s = 0;
+  int havesha256 = 0;
+
+  inittarhead(&th, fp);
+  while (gettarhead(&th) > 0)
+    {
+      char *bn;
+      if (th.type != 1)
+       {
+          skipentry(&th);
+         continue;
+       }
+      bn = strrchr(th.path, '/');
+      if (!bn || (strcmp(bn + 1, "desc") != 0 && strcmp(bn + 1, "depends") != 0))
+       {
+          skipentry(&th);
+         continue;
+       }
+      if (!lastdn || (bn - th.path) != lastdnlen || strncmp(lastdn, th.path, lastdnlen) != 0)
+       {
+         if (s)
+           {
+             if (s && !s->name)
+               {
+                 repo_free_solvable_block(repo, s - pool->solvables, 1, 1);
+                 s = 0;
+               }
+             if (s)
+               {
+                 if (!s->arch)
+                   s->arch = ARCH_NOARCH;
+                 if (!s->evr)
+                   s->evr = ID_EMPTY;
+                 s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+               }
+           }
+         solv_free(lastdn);
+         lastdn = solv_strdup(th.path);
+         lastdnlen = bn - th.path;
+         s = pool_id2solvable(pool, repo_add_solvable(repo));
+         havesha256 = 0;
+       }
+      while (getsentry(&th, line, sizeof(line)))
+       {
+         l = strlen(line);
+         if (l == 0 || line[l - 1] != '\n')
+           continue;
+         line[--l] = 0;
+         if (l <= 2 || line[0] != '%' || line[l - 1] != '%')
+           continue;
+         if (!strcmp(line, "%FILENAME%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_location(data, s - pool->solvables, 0, 0, line);
+           }
+         else if (!strcmp(line, "%NAME%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               s->name = pool_str2id(pool, line, 1);
+           }
+         else if (!strcmp(line, "%VERSION%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               s->evr = pool_str2id(pool, line, 1);
+           }
+         else if (!strcmp(line, "%DESC%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               {
+                 repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line);
+                 repodata_set_str(data, s - pool->solvables, SOLVABLE_DESCRIPTION, line);
+               }
+           }
+         else if (!strcmp(line, "%GROUPS%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_GROUP, line);
+           }
+         else if (!strcmp(line, "%CSIZE%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, strtoull(line, 0, 10));
+           }
+         else if (!strcmp(line, "%ISIZE%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, strtoull(line, 0, 10));
+           }
+         else if (!strcmp(line, "%MD5SUM%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)) && !havesha256)
+               repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_MD5, line);
+           }
+         else if (!strcmp(line, "%SHA256SUM%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               {
+                 repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, REPOKEY_TYPE_SHA256, line);
+                 havesha256 = 1;
+               }
+           }
+         else if (!strcmp(line, "%URL%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, line);
+           }
+         else if (!strcmp(line, "%LICENSE%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_str(data, s - pool->solvables, SOLVABLE_LICENSE, line);
+           }
+         else if (!strcmp(line, "%ARCH%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               s->arch = pool_str2id(pool, line, 1);
+           }
+         else if (!strcmp(line, "%BUILDDATE%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, strtoull(line, 0, 10));
+           }
+         else if (!strcmp(line, "%PACKAGER%"))
+           {
+             if (getsentrynl(&th, line, sizeof(line)))
+               repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_PACKAGER, line);
+           }
+         else if (!strcmp(line, "%REPLACES%"))
+           {
+             while (getsentrynl(&th, line, sizeof(line)) && *line)
+               s->obsoletes = adddep(repo, s->obsoletes, line);
+           }
+         else if (!strcmp(line, "%DEPENDS%"))
+           {
+             while (getsentrynl(&th, line, sizeof(line)) && *line)
+               s->requires = adddep(repo, s->requires, line);
+           }
+         else if (!strcmp(line, "%CONFLICTS%"))
+           {
+             while (getsentrynl(&th, line, sizeof(line)) && *line)
+               s->conflicts = adddep(repo, s->conflicts, line);
+           }
+         else if (!strcmp(line, "%PROVIDES%"))
+           {
+             while (getsentrynl(&th, line, sizeof(line)) && *line)
+               s->provides = adddep(repo, s->provides, line);
+           }
+         else if (!strcmp(line, "%OPTDEPENDS%"))
+           {
+             while (getsentrynl(&th, line, sizeof(line)) && *line)
+               {
+                 char *p = strchr(line, ':');
+                 if (p && p > line)
+                   *p = 0;
+                 s->suggests = adddep(repo, s->suggests, line);
+               }
+           }
+         while (*line)
+           getsentrynl(&th, line, sizeof(line));
+       }
+    }
+  if (s)
+    {
+      if (s && !s->name)
+       {
+         repo_free_solvable_block(repo, s - pool->solvables, 1, 1);
+         s = 0;
+       }
+      if (s)
+       {
+         if (!s->arch)
+           s->arch = ARCH_NOARCH;
+         if (!s->evr)
+           s->evr = ID_EMPTY;
+         s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+       }
+    }
+  if (!(flags & REPO_NO_INTERNALIZE))
+    repodata_internalize(data);
+  return 0;
+}
+
diff --git a/ext/repo_arch.h b/ext/repo_arch.h
new file mode 100644 (file)
index 0000000..65be8fe
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#define ARCH_ADD_WITH_PKGID  (1 << 8)
+
+extern Id repo_add_arch_pkg(Repo *repo, const char *fn, int flags);
+extern Id repo_add_arch_repo(Repo *repo, FILE *fp, int flags);
+
index 86f804d..d5173ae 100644 (file)
@@ -69,6 +69,16 @@ TARGET_LINK_LIBRARIES (mdk2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES}
 SET (tools_list ${tools_list} mdk2solv)
 ENDIF (ENABLE_MDKREPO)
 
+IF (ENABLE_ARCHREPO)
+ADD_EXECUTABLE (archpkgs2solv archpkgs2solv.c)
+TARGET_LINK_LIBRARIES (archpkgs2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+ADD_EXECUTABLE (archrepo2solv archrepo2solv.c)
+TARGET_LINK_LIBRARIES (archrepo2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
+SET (tools_list ${tools_list} archpkgs2solv archrepo2solv)
+ENDIF (ENABLE_ARCHREPO)
+
 ADD_EXECUTABLE (installcheck installcheck.c)
 TARGET_LINK_LIBRARIES (installcheck libsolvext libsolv ${SYSTEM_LIBRARIES})
 
diff --git a/tools/archpkgs2solv.c b/tools/archpkgs2solv.c
new file mode 100644 (file)
index 0000000..d2e19c6
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * archpkgs2solv - create a solv file from multiple arch packages
+ * 
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "util.h"
+#include "pool.h"
+#include "repo.h"
+#include "repo_arch.h"
+#include "repo_solv.h"
+#include "common_write.h"
+
+static char *
+fgets0(char *s, int size, FILE *stream)
+{
+  char *p = s;
+  int c;
+
+  while (--size > 0)
+    {
+      c = getc(stream);
+      if (c == EOF)
+       {
+         if (p == s)
+           return 0;
+         c = 0;
+       }
+      *p++ = c;
+      if (!c)
+       return s;
+    }
+  *p = 0;
+  return s;
+}
+
+int
+main(int argc, char **argv)
+{
+  const char **pkgs = 0;
+  char *manifest = 0;
+  int manifest0 = 0;
+  int i, c, npkgs = 0;
+  Pool *pool = pool_create();
+  Repo *repo;
+  FILE *fp;
+  char buf[4096], *p;
+  const char *basefile = 0;
+  int flags = 0;
+
+  while ((c = getopt(argc, argv, "0b:m:i")) >= 0)
+    {
+      switch(c)
+       {
+       case 'b':
+         basefile = optarg;
+         break;
+       case 'm':
+         manifest = optarg;
+         break;
+       case '0':
+         manifest0 = 1;
+         break;
+       case 'i':
+         flags |= ARCH_ADD_WITH_PKGID;
+         break;
+       default:
+         exit(1);
+       }
+    }
+  if (manifest)
+    {
+      if (!strcmp(manifest, "-"))
+        fp = stdin;
+      else if ((fp = fopen(manifest, "r")) == 0)
+       {
+         perror(manifest);
+         exit(1);
+       }
+      for (;;)
+       {
+         if (manifest0)
+           {
+             if (!fgets0(buf, sizeof(buf), fp))
+               break;
+           }
+         else
+           {
+             if (!fgets(buf, sizeof(buf), fp))
+               break;
+             if ((p = strchr(buf, '\n')) != 0)
+               *p = 0;
+           }
+          pkgs = solv_extend(pkgs, npkgs, 1, sizeof(char *), 15);
+         pkgs[npkgs++] = strdup(buf);
+       }
+      if (fp != stdin)
+        fclose(fp);
+    }
+  while (optind < argc)
+    {
+      pkgs = solv_extend(pkgs, npkgs, 1, sizeof(char *), 15);
+      pkgs[npkgs++] = solv_strdup(argv[optind++]);
+    }
+  repo = repo_create(pool, "archpkgs2solv");
+  repo_add_repodata(repo, 0);
+  for (i = 0; i < npkgs; i++)
+    repo_add_arch_pkg(repo, pkgs[i], REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|flags);
+  repo_internalize(repo);
+  tool_write(repo, basefile, 0);
+  pool_free(pool);
+  for (c = 0; c < npkgs; c++)
+    solv_free((char *)pkgs[c]);
+  solv_free(pkgs);
+  exit(0);
+}
+
diff --git a/tools/archrepo2solv.c b/tools/archrepo2solv.c
new file mode 100644 (file)
index 0000000..e671c49
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, Novell Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * archrepo2solv.c
+ *
+ * parse archlinux repo file
+ *
+ * reads from stdin
+ * writes to stdout
+ */
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "repo_arch.h"
+#include "solv_xfopen.h"
+#include "common_write.h"
+
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "archrepo2solv\n"
+          "  reads a repository from <stdin> and writes a .solv file to <stdout>\n"
+          "  -h : print help & exit\n"
+         );
+   exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  Pool *pool;
+  Repo *repo;
+  int c;
+
+  while ((c = getopt(argc, argv, "h")) >= 0)
+    {
+      switch(c)
+       {
+       case 'h':
+         usage(0);
+         break;
+       default:
+         usage(1);
+         break;
+       }
+    }
+  pool = pool_create();
+  repo = repo_create(pool, "<stdin>");
+  repo_add_arch_repo(repo, stdin, 0);
+  tool_write(repo, 0, 0);
+  pool_free(pool);
+  exit(0);
+}
index db6c97b..cec705e 100644 (file)
@@ -49,7 +49,7 @@ main(int argc, char **argv)
   char *infofile;
   int c;
 
-  while ((c = getopt(argc, argv, "i:")) >= 0)
+  while ((c = getopt(argc, argv, "hi:")) >= 0)
     {
       switch(c)
        {