From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 26B1C13835A for ; Mon, 25 May 2020 10:44:03 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 3948BE083E; Mon, 25 May 2020 10:44:01 +0000 (UTC) Received: from smtp.gentoo.org (mail.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 004B4E083E for ; Mon, 25 May 2020 10:44:00 +0000 (UTC) Received: from oystercatcher.gentoo.org (unknown [IPv6:2a01:4f8:202:4333:225:90ff:fed9:fc84]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 1825434F024 for ; Mon, 25 May 2020 10:43:59 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id A987226A for ; Mon, 25 May 2020 10:43:56 +0000 (UTC) From: "Fabian Groffen" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Fabian Groffen" Message-ID: <1590402894.553eb9afd1a57bbe56bdddd77ddf0bb450ee32b8.grobian@gentoo> Subject: [gentoo-commits] proj/portage-utils:master commit in: libq/ X-VCS-Repository: proj/portage-utils X-VCS-Files: libq/tree.c libq/tree.h X-VCS-Directories: libq/ X-VCS-Committer: grobian X-VCS-Committer-Name: Fabian Groffen X-VCS-Revision: 553eb9afd1a57bbe56bdddd77ddf0bb450ee32b8 X-VCS-Branch: master Date: Mon, 25 May 2020 10:43:56 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 4729f81d-8b27-46bf-bb52-7feb37270b5c X-Archives-Hash: 9a652d596abf6dceba2f3b8e7a869b62 commit: 553eb9afd1a57bbe56bdddd77ddf0bb450ee32b8 Author: Fabian Groffen gentoo org> AuthorDate: Mon May 25 10:34:54 2020 +0000 Commit: Fabian Groffen gentoo org> CommitDate: Mon May 25 10:34:54 2020 +0000 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=553eb9af libq/tree: rework tree_match_atom to return a list of results Major change is that multiple results are returned, somewhat controlled by flags, and that the results are valid until the tree is closed. Each match result needs to be closed individually though. This required some hoops to make it work with Packages file or binpkg repos. The latter are largely simulated now, and do not really benefit from the cheaper point and lookup approach that tree_match_atom tries to provide. Signed-off-by: Fabian Groffen gentoo.org> libq/tree.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------- libq/tree.h | 21 ++++++- 2 files changed, 177 insertions(+), 25 deletions(-) diff --git a/libq/tree.c b/libq/tree.c index 4b9109e..d313f3b 100644 --- a/libq/tree.c +++ b/libq/tree.c @@ -388,14 +388,11 @@ tree_filter_pkg(const struct dirent *de) tree_pkg_ctx * tree_open_pkg(tree_cat_ctx *cat_ctx, const char *name) { - tree_pkg_ctx *pkg_ctx = xmalloc(sizeof(*pkg_ctx)); + tree_pkg_ctx *pkg_ctx = xzalloc(sizeof(*pkg_ctx)); pkg_ctx->name = name; - pkg_ctx->slot = NULL; pkg_ctx->repo = cat_ctx->ctx->repo; pkg_ctx->fd = -1; pkg_ctx->cat_ctx = cat_ctx; - pkg_ctx->atom = NULL; - pkg_ctx->meta = NULL; /* see if this pkg matches the query, here we can finally check * version conditions like >=, etc. */ @@ -1405,12 +1402,14 @@ tree_foreach_packages(tree_ctx *ctx, tree_pkg_cb callback, void *priv) match_key(IUSE); match_key(KEYWORDS); match_key(LICENSE); - match_key2(MD5, _md5_); - match_key2(SHA1, _eclasses_); + match_key(MD5); + match_key(SHA1); match_key(RDEPEND); match_key(SLOT); match_key(USE); match_key(PDEPEND); + match_key2(REPO, repository); + match_key(SIZE); #undef match_key #undef match_key2 } @@ -1430,6 +1429,7 @@ tree_foreach_packages(tree_ctx *ctx, tree_pkg_cb callback, void *priv) /* ensure we don't free a garbage pointer */ ctx->repo = NULL; ctx->do_sort = false; + ctx->pkgs[0] = '\0'; return ret; } @@ -1580,34 +1580,167 @@ tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms) return state.cpf; } -tree_pkg_ctx * -tree_match_atom(tree_ctx *ctx, depend_atom *a) +struct tree_match_pkgs_cb_ctx { + int flags; + tree_match_ctx *ret; +}; + +static int +tree_match_atom_packages_cb(tree_pkg_ctx *ctx, void *priv) +{ + struct tree_match_pkgs_cb_ctx *rctx = priv; + depend_atom *a; + tree_match_ctx *n; + + /* skip anything after finding first match */ + if (rctx->flags & TREE_MATCH_FIRST && rctx->ret != NULL) + return 1; + + a = tree_get_atom(ctx, rctx->flags & TREE_MATCH_FULL_ATOM); + + /* skip virtual category if not requested */ + if (!(rctx->flags & TREE_MATCH_VIRTUAL) && + strcmp(a->CATEGORY, "virtual") == 0) + return 1; + + n = xzalloc(sizeof(tree_match_ctx)); + n->free_atom = true; + n->atom = atom_clone(a); + if (rctx->flags & TREE_MATCH_METADATA) { + n->meta = xmalloc(sizeof(*n->meta)); + /* for Packages, all pointers to meta here are to the in memory + * copy of the Packages file, so these pointers can just be + * copied since the tree has to remain open, thus the pointers + * will stay valid */ + memcpy(n->meta, ctx->cat_ctx->ctx->pkgs, sizeof(*n->meta)); + } + + n->next = rctx->ret; + rctx->ret = n; + + return 0; +} + +static int +tree_match_atom_binpkg_cb(tree_pkg_ctx *ctx, void *priv) +{ + struct tree_match_pkgs_cb_ctx *rctx = priv; + depend_atom *a; + tree_match_ctx *n; + + /* skip anything after finding first match */ + if (rctx->flags & TREE_MATCH_FIRST && rctx->ret != NULL) + return 1; + + a = tree_get_atom(ctx, rctx->flags & TREE_MATCH_FULL_ATOM); + + /* skip virtual category if not requested */ + if (!(rctx->flags & TREE_MATCH_VIRTUAL) && + strcmp(a->CATEGORY, "virtual") == 0) + return 1; + + n = xzalloc(sizeof(tree_match_ctx)); + n->free_atom = true; + n->atom = atom_clone(a); + if (rctx->flags & TREE_MATCH_METADATA) + n->meta = tree_pkg_read(ctx); + + n->next = rctx->ret; + rctx->ret = n; + + return 0; +} + +tree_match_ctx * +tree_match_atom(tree_ctx *ctx, depend_atom *query, int flags) { tree_cat_ctx *cat_ctx; tree_pkg_ctx *pkg_ctx; + tree_match_ctx *ret = NULL; depend_atom *atom; + if (ctx->cachetype == CACHE_PACKAGES) { + struct tree_match_pkgs_cb_ctx rctx; + /* Packages needs to be serviced separately because it doesn't + * use a tree internally, but reads off of the Packages file */ + rctx.flags = flags; + rctx.ret = NULL; + ctx->query_atom = query; + tree_foreach_packages(ctx, tree_match_atom_packages_cb, &rctx); + ctx->query_atom = NULL; + return rctx.ret; + } else if (ctx->cachetype == CACHE_BINPKGS) { + struct tree_match_pkgs_cb_ctx rctx; + /* this sulks, but binpkgs modify the pkg_ctx->name to strip off + * .tbz2, and that makes it non-reusable */ + rctx.flags = flags; + rctx.ret = NULL; + tree_foreach_pkg(ctx, tree_match_atom_binpkg_cb, &rctx, true, query); + return rctx.ret; + } + + /* activate cache for future lookups, tree_match_atom relies on + * cache behaviour from tree, which means all categories and + * packages remain in memory until tree_close is being called */ if (ctx->cache.categories == NULL) ctx->cache.categories = create_set(); - if (a->P == NULL) { - return NULL; - } else if (a->CATEGORY == NULL) { - /* loop through all cats and recurse */ - /* TODO: some day */ - return NULL; + ctx->do_sort = true; /* sort uses buffer, which cache relies on */ + ctx->query_atom = NULL; /* ensure the cache contains ALL pkgs */ + +#define search_cat(C) \ +{ \ + while ((pkg_ctx = tree_next_pkg(C)) != NULL) { \ + atom = tree_get_atom(pkg_ctx, \ + query->SLOT != NULL || flags & TREE_MATCH_FULL_ATOM); \ +fprintf(stderr, "fbg: %s\n", atom_to_string(atom)); \ + if (flags & TREE_MATCH_VIRTUAL || \ + strcmp(atom->CATEGORY, "virtual") != 0) \ + if (atom_compare(atom, query) == EQUAL) { \ + tree_match_ctx *n; \ + n = xzalloc(sizeof(tree_match_ctx)); \ + n->free_atom = false; \ + n->atom = atom; \ + if (flags & TREE_MATCH_METADATA) \ + n->meta = tree_pkg_read(pkg_ctx); \ + n->next = ret; \ + ret = n; \ + } \ + if (flags & TREE_MATCH_FIRST && ret != NULL) \ + break; \ + } \ + C->pkg_cur = 0; /* reset to allow another traversal */ \ +} + + if (query->CATEGORY == NULL) { + /* loop through all cats */ + while ((cat_ctx = tree_next_cat(ctx)) != NULL) { + search_cat(cat_ctx); + if (ret != NULL && flags & TREE_MATCH_FIRST) + break; + } + /* allow running again through the cats */ + ctx->cat_cur = 0; } else { /* try CAT, and PN for latest version */ - if ((cat_ctx = tree_open_cat(ctx, a->CATEGORY)) == NULL) - return NULL; - ctx->do_sort = true; /* sort uses buffer, which cache relies on */ - ctx->query_atom = NULL; /* ensure the cache contains ALL pkgs */ - while ((pkg_ctx = tree_next_pkg(cat_ctx)) != NULL) { - atom = tree_get_atom(pkg_ctx, a->SLOT != NULL); - if (atom_compare(atom, a) == EQUAL) - return pkg_ctx; - } + if ((cat_ctx = tree_open_cat(ctx, query->CATEGORY)) != NULL) + search_cat(cat_ctx); + } - return NULL; + return ret; +} + +void +tree_match_close(tree_match_ctx *match) +{ + tree_match_ctx *w; + + for (w = NULL; match != NULL; match = w) { + w = match->next; + if (match->free_atom) + atom_implode(match->atom); + if (match->meta != NULL) + free(match->meta); + free(match); } } diff --git a/libq/tree.h b/libq/tree.h index eaee7ad..900b998 100644 --- a/libq/tree.h +++ b/libq/tree.h @@ -18,6 +18,7 @@ typedef struct tree_cat_ctx tree_cat_ctx; typedef struct tree_pkg_ctx tree_pkg_ctx; typedef struct tree_pkg_meta tree_pkg_meta; typedef struct tree_metadata_xml tree_metadata_xml; +typedef struct tree_match_ctx tree_match_ctx; /* tree context */ struct tree_ctx { @@ -100,6 +101,9 @@ struct tree_pkg_meta { char *Q_USE; char *Q_EPREFIX; char *Q_repository; + char *Q_MD5; + char *Q_SHA1; +#define Q_SIZE Q_SRC_URI /* These are MD5-Cache only */ char *Q__eclasses_; char *Q__md5_; @@ -113,6 +117,15 @@ struct tree_metadata_xml { } *email; }; +/* used with tree_match_atom, both atom and meta are fully materialised + * (populated and deep copied) when set */ +struct tree_match_ctx { + depend_atom *atom; + tree_pkg_meta *meta; + tree_match_ctx *next; + int free_atom; +}; + /* foreach pkg callback function signature */ typedef int (tree_pkg_cb)(tree_pkg_ctx *, void *priv); @@ -138,6 +151,12 @@ int tree_foreach_pkg(tree_ctx *ctx, tree_pkg_cb callback, void *priv, tree_foreach_pkg(ctx, cb, priv, true, query); set *tree_get_atoms(tree_ctx *ctx, bool fullcpv, set *satoms); depend_atom *tree_get_atom(tree_pkg_ctx *pkg_ctx, bool complete); -tree_pkg_ctx *tree_match_atom(tree_ctx *t, depend_atom *a); +tree_match_ctx *tree_match_atom(tree_ctx *t, depend_atom *q, int flags); +#define TREE_MATCH_FULL_ATOM 1<<1 +#define TREE_MATCH_METADATA 1<<2 +#define TREE_MATCH_FIRST 1<<3 +#define TREE_MATCH_VIRTUAL 1<<4 +#define TREE_MATCH_DEFAULT TREE_MATCH_VIRTUAL +void tree_match_close(tree_match_ctx *t); #endif