commit:     b811b9afd740e8f4cc73f096e8c162d5d332aed2
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Sun Nov 17 15:01:00 2019 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Sun Nov 17 15:01:00 2019 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=b811b9af

libq/tree: add support for binpgks and Packages file

This allows to foreach binpkgs (without Packages file index) as well as
use the Packages file to loop over them.

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/tree.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 libq/tree.h |  13 +++-
 2 files changed, 251 insertions(+), 16 deletions(-)

diff --git a/libq/tree.c b/libq/tree.c
index b0d0b5b..427281f 100644
--- a/libq/tree.c
+++ b/libq/tree.c
@@ -21,6 +21,7 @@
 #include "scandirat.h"
 #include "set.h"
 #include "tree.h"
+#include "xpak.h"
 
 #include <ctype.h>
 #include <xalloc.h>
@@ -30,7 +31,7 @@ static int tree_pkg_compar(const void *l, const void *r);
 static tree_ctx *
 tree_open_int(const char *sroot, const char *tdir, bool quiet)
 {
-       tree_ctx *ctx = xmalloc(sizeof(*ctx));
+       tree_ctx *ctx = xzalloc(sizeof(*ctx));
 
        ctx->portroot_fd = open(sroot, O_RDONLY | O_CLOEXEC | O_PATH);
        if (ctx->portroot_fd == -1) {
@@ -56,12 +57,8 @@ tree_open_int(const char *sroot, const char *tdir, bool 
quiet)
                goto cv_error;
 
        ctx->do_sort = false;
-       ctx->cat_de = NULL;
        ctx->catsortfunc = alphasort;
        ctx->pkgsortfunc = tree_pkg_compar;
-       ctx->repo = NULL;
-       ctx->ebuilddir_ctx = NULL;
-       ctx->ebuilddir_pkg_ctx = NULL;
        return ctx;
 
  cv_error:
@@ -130,6 +127,24 @@ tree_open_vdb(const char *sroot, const char *svdb)
        return ret;
 }
 
+static const char binpkg_packages[]  = "Packages";
+tree_ctx *
+tree_open_binpkg(const char *sroot, const char *spkg)
+{
+       tree_ctx *ret = tree_open_int(sroot, spkg, true);
+       char buf[_Q_PATH_MAX];
+
+       if (ret != NULL) {
+               ret->cachetype = CACHE_BINPKGS;
+
+               snprintf(buf, sizeof(buf), "%s%s/%s", sroot, spkg, 
binpkg_packages);
+               if (eat_file(buf, &ret->pkgs, &ret->pkgslen))
+                       ret->cachetype = CACHE_PACKAGES;
+       }
+
+       return ret;
+}
+
 void
 tree_close(tree_ctx *ctx)
 {
@@ -141,6 +156,8 @@ tree_close(tree_ctx *ctx)
                scandir_free(ctx->cat_de, ctx->cat_cnt);
        if (ctx->repo != NULL)
                free(ctx->repo);
+       if (ctx->pkgs != NULL)
+               free(ctx->pkgs);
        if (ctx->ebuilddir_ctx != NULL)
                free(ctx->ebuilddir_ctx);
        free(ctx);
@@ -443,6 +460,13 @@ tree_next_pkg(tree_cat_ctx *cat_ctx)
                                }
                        }
                } while (ret == NULL);
+       } else if (ctx->cachetype == CACHE_BINPKGS) {
+               char *p = NULL;
+               do {
+                       ret = tree_next_pkg_int(cat_ctx);
+               } while (ret != NULL && (p = strstr(ret->name, ".tbz2")) == 
NULL);
+               if (p != NULL)
+                       *p = '\0';
        } else {
                ret = tree_next_pkg_int(cat_ctx);
        }
@@ -805,22 +829,96 @@ err:
        return NULL;
 }
 
+static void
+tree_read_file_binpkg_xpak_cb(
+       void *ctx,
+       char *pathname,
+       int pathname_len,
+       int data_offset,
+       int data_len,
+       char *data)
+{
+       tree_pkg_meta *m = (tree_pkg_meta *)ctx;
+       char **key;
+       size_t pos;
+       size_t len;
+
+#define match_path(K) \
+       else if (pathname_len == (sizeof(#K) - 1) && strcmp(pathname, #K) == 0) 
\
+               key = &m->K
+       if (1 == 0); /* dummy for syntax */
+       match_path(DEPEND);
+       match_path(RDEPEND);
+       match_path(SLOT);
+       match_path(SRC_URI);
+       match_path(RESTRICT);
+       match_path(HOMEPAGE);
+       match_path(DESCRIPTION);
+       match_path(KEYWORDS);
+       match_path(INHERITED);
+       match_path(IUSE);
+       match_path(CDEPEND);
+       match_path(PDEPEND);
+       match_path(PROVIDE);
+       match_path(EAPI);
+       match_path(PROPERTIES);
+       match_path(DEFINED_PHASES);
+       match_path(REQUIRED_USE);
+       match_path(BDEPEND);
+       match_path(CONTENTS);
+       match_path(USE);
+       match_path(repository);
+       else
+               return;
+#undef match_path
+
+       /* hijack unused members */
+       pos = (size_t)m->_eclasses_;
+       len = (size_t)m->_md5_;
+
+       /* trim whitespace (mostly trailing newline) */
+       while (isspace((int)data[data_offset + data_len - 1]))
+               data_len--;
+
+       if (len - pos < (size_t)data_len) {
+               len += (((data_len + 1) / BUFSIZ) + 1) * BUFSIZ;
+               m->_data = xrealloc(m->_data, len);
+               m->_md5_ = (char *)len;
+       }
+
+       *key = m->_data + pos;
+       snprintf(*key, len - pos, "%.*s", data_len, data + data_offset);
+       pos += data_len + 1;
+       m->_eclasses_ = (char *)pos;
+}
+
+static tree_pkg_meta *
+tree_read_file_binpkg(tree_pkg_ctx *pkg_ctx)
+{
+       tree_pkg_meta *m = xzalloc(sizeof(tree_pkg_meta));
+
+       xpak_process_fd(pkg_ctx->fd, true, m, tree_read_file_binpkg_xpak_cb);
+       pkg_ctx->fd = -1;  /* closed by xpak_process_fd */
+
+       return m;
+}
+
 tree_pkg_meta *
 tree_pkg_read(tree_pkg_ctx *pkg_ctx)
 {
        tree_ctx *ctx = pkg_ctx->cat_ctx->ctx;
 
        if (pkg_ctx->fd == -1) {
-               if (ctx->cachetype != CACHE_EBUILD) {
-                       pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, 
pkg_ctx->name,
-                                       O_RDONLY | O_CLOEXEC);
-               } else {
+               if (ctx->cachetype == CACHE_EBUILD || ctx->cachetype == 
CACHE_BINPKGS) {
                        char *p = (char *)pkg_ctx->name;
                        p += strlen(p);
                        *p = '.';
                        pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, 
pkg_ctx->name,
                                        O_RDONLY | O_CLOEXEC);
                        *p = '\0';
+               } else {
+                       pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, 
pkg_ctx->name,
+                                       O_RDONLY | O_CLOEXEC);
                }
                if (pkg_ctx->fd == -1)
                        return NULL;
@@ -832,6 +930,10 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx)
                return tree_read_file_pms(pkg_ctx);
        } else if (ctx->cachetype == CACHE_EBUILD) {
                return tree_read_file_ebuild(pkg_ctx);
+       } else if (ctx->cachetype == CACHE_BINPKGS) {
+               return tree_read_file_binpkg(pkg_ctx);
+       } else if (ctx->cachetype == CACHE_PACKAGES) {
+               return (tree_pkg_meta *)pkg_ctx->cat_ctx->ctx->pkgs;
        }
 
        warn("Unknown metadata cache type!");
@@ -841,8 +943,10 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx)
 void
 tree_close_meta(tree_pkg_meta *cache)
 {
-       if (!cache)
+       if (cache == NULL)
                errf("Cache is empty !");
+       if (cache->_data != NULL)
+               free(cache->_data);
        free(cache);
 }
 
@@ -952,6 +1056,112 @@ tree_close_pkg(tree_pkg_ctx *pkg_ctx)
        free(pkg_ctx);
 }
 
+static int
+tree_foreach_packages(tree_ctx *ctx, tree_pkg_cb callback, void *priv)
+{
+       char *p = ctx->pkgs;
+       char *q;
+       char *c;
+       size_t len = ctx->pkgslen;
+       int ret = 0;
+
+       /* reused for every entry */
+       tree_cat_ctx *cat = xzalloc(sizeof(tree_cat_ctx));
+       tree_pkg_ctx *pkg = xzalloc(sizeof(tree_pkg_ctx));
+       tree_pkg_meta *meta = xzalloc(sizeof(tree_pkg_meta));
+       depend_atom *atom = NULL;
+
+       cat->ctx = ctx;
+       pkg->cat_ctx = cat;
+
+       do {
+               /* find next line */
+               c = NULL;
+               for (q = p; len > 0 && *q != '\n'; q++, len--)
+                       if (c == NULL && *q == ':')
+                               c = q;
+
+               if (len == 0)
+                       break;
+
+               /* empty line, end of a block */
+               if (p == q) {
+                       /* make callback with populated atom */
+                       if (atom != NULL) {
+                               /* store meta ptr in repo->pkgs, such that 
get_pkg_meta
+                                * can grab it from there (for free) */
+                               ctx->pkgs = (char *)meta;
+
+                               cat->name = atom->CATEGORY;
+                               pkg->name = atom->PN;
+                               pkg->slot = meta->SLOT == NULL ? "0" : 
meta->SLOT;
+                               pkg->repo = ctx->repo;
+                               pkg->atom = atom;
+
+                               /* do call callback with pkg_atom (populate cat 
and pkg) */
+                               ret |= callback(pkg, priv);
+
+                               atom_implode(atom);
+                       }
+
+                       memset(meta, 0, sizeof(meta[0]));
+                       atom = NULL;
+                       if (len > 0) {  /* hop over \n */
+                               p++;
+                               len--;
+                       }
+                       continue;
+               }
+
+               /* skip invalid lines */
+               if (c == NULL || q - c < 3 || c[1] != ' ')
+                       continue;
+
+               /* NULL-terminate p and c, file should end with \n */
+               *q = '\0';
+               *c = '\0';
+               c += 2;         /* hop over ": " */
+               if (len > 0) {  /* hop over \n */
+                       q++;
+                       len--;
+               }
+
+               if (strcmp(p, "REPO") == 0) { /* from global section in older 
files */
+                       ctx->repo = c;
+               } else if (strcmp(p, "CPV") == 0) {
+                       if (atom != NULL)
+                               atom_implode(atom);
+                       atom = atom_explode(c);
+#define match_key(X) match_key2(X,X)
+#define match_key2(X,Y) \
+               } else if (strcmp(p, #X) == 0) { \
+                       meta->Y = c
+               match_key(DEFINED_PHASES);
+               match_key(DEPEND);
+               match_key2(DESC, DESCRIPTION);
+               match_key(EAPI);
+               match_key(IUSE);
+               match_key(KEYWORDS);
+               match_key(LICENSE);
+               match_key2(MD5, _md5_);
+               match_key2(SHA1, _eclasses_);
+               match_key(RDEPEND);
+               match_key(SLOT);
+               match_key(USE);
+               match_key(PDEPEND);
+#undef match_key
+#undef match_key2
+               }
+
+               p = q;
+       } while (len > 0);
+
+       /* ensure we don't free a garbage pointer */
+       ctx->repo = NULL;
+
+       return ret;
+}
+
 int
 tree_foreach_pkg(tree_ctx *ctx,
                tree_pkg_cb callback, void *priv, tree_cat_filter filter,
@@ -964,6 +1174,10 @@ tree_foreach_pkg(tree_ctx *ctx,
        if (ctx == NULL)
                return EXIT_FAILURE;
 
+       /* handle Packages (binpkgs index) file separately */
+       if (ctx->cachetype == CACHE_PACKAGES)
+               return tree_foreach_packages(ctx, callback, priv);
+
        ctx->do_sort = sort;
        if (catsortfunc != NULL)
                ctx->catsortfunc = catsortfunc;
@@ -1009,23 +1223,35 @@ tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete)
                                                        &pkg_ctx->repo, 
&pkg_ctx->repo_len);
                                pkg_ctx->atom->REPO = pkg_ctx->repo;
                        }
-               } else { /* metadata or ebuild */
+               } else { /* metadata, ebuild, binpkg or Packages */
+                       tree_pkg_meta *meta = NULL;
                        if (pkg_ctx->atom->SLOT == NULL) {
                                if (pkg_ctx->slot == NULL) {
-                                       tree_pkg_meta *meta = 
tree_pkg_read(pkg_ctx);
+                                       meta = tree_pkg_read(pkg_ctx);
                                        if (meta != NULL) {
                                                if (meta->SLOT != NULL) {
                                                        pkg_ctx->slot = 
xstrdup(meta->SLOT);
                                                        pkg_ctx->slot_len = 
strlen(pkg_ctx->slot);
                                                }
-                                               tree_close_meta(meta);
                                        }
                                }
                                pkg_ctx->atom->SLOT = pkg_ctx->slot;
                        }
                        /* repo is set from the tree, when found */
-                       if (pkg_ctx->atom->REPO == NULL)
+                       if (pkg_ctx->atom->REPO == NULL) {
+                               if (pkg_ctx->repo == NULL && ctx->cachetype == 
CACHE_BINPKGS) {
+                                       if (meta == NULL)
+                                               meta = tree_pkg_read(pkg_ctx);
+                                       if (meta != NULL && meta->repository != 
NULL) {
+                                               pkg_ctx->repo = 
xstrdup(meta->repository);
+                                               pkg_ctx->repo_len = 
strlen(pkg_ctx->repo);
+                                       }
+                               }
                                pkg_ctx->atom->REPO = pkg_ctx->repo;
+                       }
+
+                       if (meta != NULL)
+                               tree_close_meta(meta);
                }
 
                /* this is a bit atom territory, but since we pulled in SLOT we

diff --git a/libq/tree.h b/libq/tree.h
index c2a30f1..d769b7b 100644
--- a/libq/tree.h
+++ b/libq/tree.h
@@ -18,7 +18,7 @@ typedef struct tree_pkg_ctx      tree_pkg_ctx;
 typedef struct tree_pkg_meta     tree_pkg_meta;
 typedef struct tree_metadata_xml tree_metadata_xml;
 
-/* VDB context */
+/* tree context */
 struct tree_ctx {
        int portroot_fd;
        int tree_fd;
@@ -35,11 +35,15 @@ struct tree_ctx {
                CACHE_METADATA_PMS,
                CACHE_EBUILD,
                CACHE_VDB,
+               CACHE_PACKAGES,
+               CACHE_BINPKGS,
        } cachetype:3;
        tree_pkg_ctx *ebuilddir_pkg_ctx;
        tree_cat_ctx *ebuilddir_cat_ctx;
        tree_ctx *ebuilddir_ctx;
        char *repo;
+       char *pkgs;
+       size_t pkgslen;
 };
 
 /* Category context */
@@ -90,6 +94,10 @@ struct tree_pkg_meta {
        char *BDEPEND;
        char *_eclasses_;
        char *_md5_;
+       /* binpkgs/vdb */
+       char *CONTENTS;
+       char *USE;
+       char *repository;
 };
 
 /* Metadata.xml */
@@ -104,8 +112,9 @@ struct tree_metadata_xml {
 typedef int (tree_pkg_cb)(tree_pkg_ctx *, void *priv);
 typedef int (tree_cat_filter)(tree_cat_ctx *, void *priv);
 
-tree_ctx *tree_open_vdb(const char *sroot, const char *svdb);
 tree_ctx *tree_open(const char *sroot, const char *portdir);
+tree_ctx *tree_open_vdb(const char *sroot, const char *svdb);
+tree_ctx *tree_open_binpkg(const char *sroot, const char *spkg);
 void tree_close(tree_ctx *ctx);
 int tree_filter_cat(const struct dirent *de);
 tree_cat_ctx *tree_open_cat(tree_ctx *ctx, const char *name);

Reply via email to