public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Fabian Groffen" <grobian@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/portage-utils:master commit in: libq/
Date: Mon, 21 Apr 2025 14:44:33 +0000 (UTC)	[thread overview]
Message-ID: <1745246308.eb6d9110d09080e63944da0c1b0265156ab1e326.grobian@gentoo> (raw)

commit:     eb6d9110d09080e63944da0c1b0265156ab1e326
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Mon Apr 21 14:38:28 2025 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Mon Apr 21 14:38:28 2025 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=eb6d9110

libq/tree: consider ebuild-tree cache as a cache, not a tree

While it is certainly faster to only consider a metadata cache (such as
md5-cache) it yields incorrect results on trees in flux or under
development.  The only correct way is to consider the ebuilds, and look
at an existing cache, if it matches.

This commit implements this behaviour for libq/tree, used by various q
utilities.  It considers an cache for an ebuild tree, and uses it for
operations where it needs info from inside the ebuilds (such as DEPEND,
etc.) over trying to fetch it from the ebuild itself.

This is considerably slower than just considering the metadata alone,
if only because we now have to traverse multiple extra directories (one
for each package) as opposed to just reading the metadata.  However,
this is unavoidable, and hopefully can be mitigated by parallel scans in
the future.

Bug: https://bugs.gentoo.org/934549
Bug: https://bugs.gentoo.org/898194
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/tree.c | 350 +++++++++++++++++++++++++++++++++++++-----------------------
 libq/tree.h |   1 +
 2 files changed, 219 insertions(+), 132 deletions(-)

diff --git a/libq/tree.c b/libq/tree.c
index 80e570f..abce6f4 100644
--- a/libq/tree.c
+++ b/libq/tree.c
@@ -14,6 +14,8 @@
 #include <sys/stat.h>
 #include <ctype.h>
 #include <xalloc.h>
+#include "md5.h"
+#include "sha1.h"
 
 #include "atom.h"
 #include "eat_file.h"
@@ -83,44 +85,32 @@ tree_open(const char *sroot, const char *portdir)
 {
 	tree_ctx *ret;
 	char buf[_Q_PATH_MAX];
-	char *repo = NULL;
-	size_t repolen = 0;
 
-	snprintf(buf, sizeof(buf), "%s%s/%s", sroot, portdir, portrepo_name);
-	if (eat_file(buf, &repo, &repolen)) {
-		(void)rmspace(repo);
-	} else {
-		repo = NULL;  /* ignore missing repo file */
+	ret = tree_open_ebuild(sroot, portdir);
+	if (ret == NULL)
+	{
+		warnf("could not open repository at %s (under root %s)",
+			  portdir, sroot);
+
+		return NULL;
 	}
 
+	/* look for cache trees to speed things up */
 	snprintf(buf, sizeof(buf), "%s/%s", portdir, portcachedir_md5);
-	ret = tree_open_int(sroot, buf, true);
-	if (ret != NULL) {
-		ret->treetype = TREE_METADATA_MD5;
-		ret->repo = repo;
+	ret->subtree = tree_open_int(sroot, buf, true);
+	if (ret->subtree != NULL) {
+		ret->subtree->treetype = TREE_METADATA_MD5;
 		return ret;
 	}
 
 	snprintf(buf, sizeof(buf), "%s/%s", portdir, portcachedir_pms);
-	ret = tree_open_int(sroot, buf, true);
-	if (ret != NULL) {
-		ret->treetype = TREE_METADATA_PMS;
-		ret->repo = repo;
-		return ret;
-	}
-
-	ret = tree_open_int(sroot, portdir, true);
-	if (ret != NULL) {
-		ret->treetype = TREE_EBUILD;
-		ret->repo = repo;
+	ret->subtree = tree_open_int(sroot, buf, true);
+	if (ret->subtree != NULL) {
+		ret->subtree->treetype = TREE_METADATA_PMS;
 		return ret;
 	}
 
-	if (repo != NULL)
-		free(repo);
-	warnf("could not open repository at %s (under root %s)", portdir, sroot);
-
-	return NULL;
+	return ret;
 }
 
 tree_ctx *
@@ -209,6 +199,8 @@ tree_close(tree_ctx *ctx)
 		free(ctx->pkgs);
 	if (ctx->ebuilddir_ctx != NULL)
 		free(ctx->ebuilddir_ctx);
+	if (ctx->subtree != NULL)
+		tree_close(ctx->subtree);
 	free(ctx);
 }
 
@@ -397,6 +389,7 @@ tree_close_cat(tree_cat_ctx *cat_ctx)
 	/* close(ctx->fd); */
 	if (cat_ctx->ctx->do_sort)
 		free(cat_ctx->pkg_ctxs);
+
 	free(cat_ctx);
 }
 
@@ -406,6 +399,12 @@ tree_filter_pkg(const struct dirent *de)
 	int i;
 	bool founddash = false;
 
+#ifdef DT_UNKNOWN
+	/* pkg must be a file */
+	if (de->d_type != DT_REG)
+		return 0;
+#endif
+
 	/* PMS 3.1.2 */
 	for (i = 0; de->d_name[i] != '\0'; i++) {
 		switch (de->d_name[i]) {
@@ -429,13 +428,34 @@ tree_filter_pkg(const struct dirent *de)
 		}
 	}
 
+	if (i > 0 &&
+		(strcmp(de->d_name, "Manifest") == 0 ||
+		 strcmp(de->d_name, "metadata.xml") == 0))
+		i = 0;
+
 	return i;
 }
 
 tree_pkg_ctx *
 tree_open_pkg(tree_cat_ctx *cat_ctx, const char *name)
 {
-	tree_pkg_ctx *pkg_ctx = xzalloc(sizeof(*pkg_ctx));
+	tree_pkg_ctx *pkg_ctx;
+
+	if (cat_ctx->ctx->treetype == TREE_EBUILD &&
+		cat_ctx->ctx->ebuilddir_cat_ctx == cat_ctx)
+	{
+		char *p;
+		if ((p = strstr(name, ".ebuild")) == NULL)
+			return NULL;  /* invalid, must be some random other file */
+		*p = '\0';
+	} else if (cat_ctx->ctx->treetype == TREE_BINPKGS) {
+		char *p;
+		if ((p = strstr(name, ".tbz2")) == NULL)
+			return NULL;  /* invalid, no support for .gpkg yet */
+		*p = '\0';
+	}
+
+	pkg_ctx = xzalloc(sizeof(*pkg_ctx));
 	pkg_ctx->name = name;
 	pkg_ctx->repo = cat_ctx->ctx->repo;
 	pkg_ctx->fd = -1;
@@ -549,12 +569,7 @@ tree_next_pkg(tree_cat_ctx *cat_ctx)
 	tree_ctx *ctx = cat_ctx->ctx;
 	tree_pkg_ctx *ret = NULL;
 
-	if (ctx->do_sort && cat_ctx->pkg_ctxs != NULL) {
-		/* bypass to use the cache if it exists */
-		ret = tree_next_pkg_int(cat_ctx);
-	} else if (ctx->treetype == TREE_EBUILD) {
-		char *p;
-
+	if (ctx->treetype == TREE_EBUILD) {
 		/* serve *.ebuild files each as separate pkg_ctx with name set
 		 * to CAT/P like in VDB and metadata */
 		do {
@@ -573,6 +588,7 @@ tree_next_pkg(tree_cat_ctx *cat_ctx)
 				pkgdir->do_sort = ctx->do_sort;
 				pkgdir->repo = ctx->repo;
 				pkgdir->treetype = ctx->treetype;
+				pkgdir->subtree = ctx->subtree;
 
 				ctx->ebuilddir_cat_ctx =
 					tree_open_cat(pkgdir, ctx->ebuilddir_pkg_ctx->name);
@@ -586,31 +602,15 @@ tree_next_pkg(tree_cat_ctx *cat_ctx)
 
 				/* "zap" the pkg such that it looks like CAT/P */
 				ctx->ebuilddir_cat_ctx->name = cat_ctx->name;
+				ctx->ebuilddir_cat_ctx->ctx = ctx;
 			}
 
 			ret = tree_next_pkg_int(ctx->ebuilddir_cat_ctx);
 			if (ret == NULL) {
 				tree_close_cat(ctx->ebuilddir_cat_ctx);
 				ctx->ebuilddir_pkg_ctx = NULL;
-			} else {
-				if ((p = strstr(ret->name, ".ebuild")) == NULL) {
-					tree_close_pkg(ret);
-					ret = NULL;
-				} else {
-					*p = '\0';
-				}
 			}
 		} while (ret == NULL);
-	} else if (ctx->treetype == TREE_BINPKGS) {
-		char *p = NULL;
-		ret = NULL;
-		do {
-			if (ret != NULL)
-				tree_close_pkg(ret);
-			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);
 	}
@@ -1054,7 +1054,7 @@ tree_read_file_binpkg(tree_pkg_ctx *pkg_ctx)
 	 * fake, but allows to transparantly use a dir of binpkgs */
 	if (newfd != -1) {
 		size_t fsize;
-		size_t needlen = 40 + 1 + 19 + 1;
+		size_t needlen = SHA1_DIGEST_SIZE + 1 + 19 + 1;
 		size_t pos = 0;
 		size_t len = 0;
 
@@ -1070,7 +1070,7 @@ tree_read_file_binpkg(tree_pkg_ctx *pkg_ctx)
 		}
 
 		m->Q_SHA1 = m->storage->ptr + pos;
-		m->Q_SIZE = m->Q_SHA1 + 40 + 1;
+		m->Q_SIZE = m->Q_SHA1 + SHA1_DIGEST_SIZE + 1;
 		m->storage->pos += needlen;
 
 		lseek(newfd, 0, SEEK_SET);  /* reposition at the whole file */
@@ -1082,6 +1082,29 @@ tree_read_file_binpkg(tree_pkg_ctx *pkg_ctx)
 	return m;
 }
 
+static int
+tree_pkg_read_openfd_int(tree_pkg_ctx *pkg_ctx)
+{
+	tree_ctx *ctx = pkg_ctx->cat_ctx->ctx;
+
+	if (pkg_ctx->fd == -1) {
+		if (ctx->treetype == TREE_EBUILD ||
+			ctx->treetype == TREE_BINPKGS)
+		{
+			char buf[_Q_PATH_MAX];
+			snprintf(buf, sizeof(buf), "%s.%s", pkg_ctx->name,
+					 ctx->treetype == TREE_EBUILD ? "ebuild" : "tbz2");
+			pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, buf,
+								 O_RDONLY | O_CLOEXEC);
+		} else {
+			pkg_ctx->fd = openat(pkg_ctx->cat_ctx->fd, pkg_ctx->name,
+								 O_RDONLY | O_CLOEXEC);
+		}
+	}
+
+	return pkg_ctx->fd;
+}
+
 static tree_pkg_meta *
 tree_pkg_read(tree_pkg_ctx *pkg_ctx)
 {
@@ -1091,21 +1114,8 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx)
 	if (pkg_ctx->meta != NULL)
 		return pkg_ctx->meta;
 
-	if (pkg_ctx->fd == -1) {
-		if (ctx->treetype == TREE_EBUILD || ctx->treetype == TREE_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;
-	}
+	if (tree_pkg_read_openfd_int(pkg_ctx) == -1)
+		return NULL;
 
 	if (ctx->treetype == TREE_METADATA_MD5) {
 		ret = tree_read_file_md5(pkg_ctx);
@@ -1121,7 +1131,66 @@ tree_pkg_read(tree_pkg_ctx *pkg_ctx)
 		 * is extinct, because these checks are insufficient and
 		 * impossible on e.g. a git-based tree. */
 	} else if (ctx->treetype == TREE_EBUILD) {
-		ret = tree_read_file_ebuild(pkg_ctx);
+		ret = NULL;
+		if (ctx->subtree != NULL) {
+			tree_cat_ctx  *scat;
+			tree_pkg_ctx  *spkg  = NULL;
+
+			/* the cache takes care of repeated calls here */
+			scat = tree_open_cat(ctx->subtree, pkg_ctx->cat_ctx->name);
+			if (scat != NULL)
+				spkg = tree_open_pkg(scat, pkg_ctx->name);
+
+			if (spkg != NULL) {
+				if (ctx->subtree->treetype == TREE_METADATA_MD5) {
+					/* in this case a cache entry exists, however, it
+					 * may be out of date, for that we need to check the
+					 * md5 hashes with the ebuild/eclass files,
+					 * obviously when the source ebuild doesn't exist,
+					 * we never get here */
+					char   *mdmd5;
+					char    srcmd5[MD5_DIGEST_SIZE];
+					size_t  flen;
+
+					if (hash_multiple_file_fd(pkg_ctx->fd,
+										  	  srcmd5, NULL, NULL, NULL,
+										  	  NULL, &flen, HASH_MD5) == 0)
+						pkg_ctx->fd = -1;
+
+					mdmd5 = tree_pkg_meta_get(spkg, _md5_);
+					/* TODO: eclass compares */
+
+					/* is this a valid cache? use it! */
+					if (mdmd5 != NULL &&
+						memcmp(mdmd5, srcmd5, MD5_DIGEST_SIZE) == 0)
+					{
+						ret = tree_pkg_read(spkg);
+					}
+				} else if (ctx->subtree->treetype == TREE_METADATA_PMS) {
+					struct stat ebld;
+					struct stat pmsc;
+
+					if (fstat(pkg_ctx->fd, &ebld) != 0 ||
+						fstat(tree_pkg_read_openfd_int(spkg), &pmsc) != 0 ||
+						ebld.st_mtime > pmsc.st_mtime ||
+						(ebld.st_mtime == pmsc.st_mtime &&
+						 ebld.st_mtim.tv_nsec > pmsc.st_mtim.tv_nsec))
+					{
+						/* fail or ebuild is newer, so ignore */
+						close(spkg->fd);
+						spkg->fd = -1;
+					} else {
+						ret = tree_pkg_read(spkg);
+						close(pkg_ctx->fd);
+						pkg_ctx->fd = -1;
+					}
+				}
+			}
+		}
+		if (ret == NULL) {
+			(void)tree_pkg_read_openfd_int(pkg_ctx);  /* re-open if fallback */
+			ret = tree_read_file_ebuild(pkg_ctx);
+		}
 	} else if (ctx->treetype == TREE_BINPKGS) {
 		ret = tree_read_file_binpkg(pkg_ctx);
 	} else if (ctx->treetype == TREE_PACKAGES) {
@@ -1730,12 +1799,14 @@ tree_match_atom_cache_populate_cb(tree_pkg_ctx *ctx, void *priv)
 		cat_ctx->name = contains_set(atom->CATEGORY, cache);
 	}
 
+	pkg = xcalloc(1, sizeof(*pkg));
+
 	/* FIXME: this really could use a set */
 	cat_ctx->pkg_cnt++;
 	cat_ctx->pkg_ctxs = xrealloc(cat_ctx->pkg_ctxs,
 			sizeof(*cat_ctx->pkg_ctxs) * cat_ctx->pkg_cnt);
-	cat_ctx->pkg_ctxs[cat_ctx->pkg_cnt - 1] =
-		pkg = tree_open_pkg(cat_ctx, atom->PF);
+	cat_ctx->pkg_ctxs[cat_ctx->pkg_cnt - 1] = pkg;
+	pkg->cat_ctx = cat_ctx;
 	pkg->atom = atom_clone(atom);
 	pkg->name = xstrdup(pkg->atom->PF);
 	pkg->repo = tctx->repo != NULL ? xstrdup(tctx->repo) : NULL;
@@ -1757,19 +1828,85 @@ tree_match_atom_cache_populate_cb(tree_pkg_ctx *ctx, void *priv)
 	return 0;
 }
 
+static tree_match_ctx *
+tree_match_search_cat_int(
+		tree_cat_ctx      *cat_ctx,
+		const depend_atom *query,
+		int                flags
+)
+{
+	tree_pkg_ctx   *pkg_ctx;
+	tree_match_ctx *ret      = NULL;
+	depend_atom    *atom;
+	char           *lastpn   = NULL;
+
+	while ((pkg_ctx = tree_next_pkg(cat_ctx)) != NULL) {
+		atom = tree_get_atom(pkg_ctx,
+							 (query->SLOT != NULL ||
+							  flags & TREE_MATCH_FULL_ATOM));
+		/* skip virtual/ package as requested */
+		if (!(flags & TREE_MATCH_VIRTUAL ||
+			  strcmp(atom->CATEGORY, "virtual") != 0))
+			continue;
+		/* skip acct-* package as requested */
+		if (!(flags & TREE_MATCH_ACCT ||
+			  strncmp(atom->CATEGORY, "acct-", sizeof("acct-") - 1) != 0))
+			continue;
+		/* see if this atom matches the query */
+		if (atom_compare(atom, query) == EQUAL) {
+			tree_match_ctx *n;
+			/* skip over additional versions for match latest */
+			if (flags & TREE_MATCH_LATEST && lastpn != NULL &&
+				strcmp(lastpn, atom->PN) == 0)
+				continue;
+			/* create a new match result */
+			n = xzalloc(sizeof(tree_match_ctx));
+			n->atom = atom;
+			n->pkg = pkg_ctx;
+			if (cat_ctx->ctx->treetype == TREE_PACKAGES &&
+				pkg_ctx->meta->Q_PATH != NULL)
+			{
+				/* binpkg-multi-instance has a PATH ready for us */
+				snprintf(n->path, sizeof(n->path), "%s/%s",
+						 (char *)cat_ctx->ctx->path, pkg_ctx->meta->Q_PATH);
+			} else {
+				snprintf(n->path, sizeof(n->path), "%s/%s/%s%s",
+						 (char *)cat_ctx->ctx->path,
+						 cat_ctx->name, pkg_ctx->name,
+						 cat_ctx->ctx->treetype == TREE_EBUILD   ? ".ebuild" :
+						 cat_ctx->ctx->treetype == TREE_BINPKGS  ? ".tbz2"   :
+						 cat_ctx->ctx->treetype == TREE_PACKAGES ? ".tbz2"   :
+						                                           "");
+			}
+			if (flags & TREE_MATCH_METADATA)
+				n->meta = tree_pkg_read(pkg_ctx);
+			if (cat_ctx->ctx->treetype == TREE_BINPKGS ||
+				cat_ctx->ctx->treetype == TREE_PACKAGES)
+				n->free_atom = n->free_meta = 0;
+			n->next = ret;
+			ret = n;
+			lastpn = atom->PN;
+		}
+		if (flags & TREE_MATCH_FIRST && ret != NULL)
+			break;
+	}
+	cat_ctx->pkg_cur = 0;  /* reset to allow another traversal */
+
+	return ret;
+}
+
 tree_match_ctx *
 tree_match_atom(tree_ctx *ctx, const depend_atom *query, int flags)
 {
 	tree_cat_ctx *cat_ctx;
-	tree_pkg_ctx *pkg_ctx;
 	tree_match_ctx *ret = NULL;
-	depend_atom *atom;
 
 	ctx->do_sort = true;     /* sort uses buffer, which cache relies on */
 	ctx->query_atom = NULL;  /* ensure the cache contains ALL pkgs */
 
-	if ((ctx->treetype == TREE_PACKAGES || ctx->treetype == TREE_BINPKGS)
-			&& ctx->cache.categories == NULL)
+	if ((ctx->treetype == TREE_PACKAGES ||
+		 ctx->treetype == TREE_BINPKGS) &&
+		ctx->cache.categories == NULL)
 	{
 		set *cache;
 		DECLARE_ARRAY(cats);
@@ -1791,9 +1928,8 @@ tree_match_atom(tree_ctx *ctx, const depend_atom *query, int flags)
 		tree_foreach_pkg(ctx,
 				tree_match_atom_cache_populate_cb, cache, true, NULL);
 
-		ctx->do_sort = true;  /* turn it back on */
+		ctx->do_sort = true;  /* turn it back on after tree_foreach_pkg */
 		ctx->cache.all_categories = true;
-
 		ctx->cache.categories = cache;
 
 		/* loop through all categories, and sort the pkgs */
@@ -1813,63 +1949,13 @@ tree_match_atom(tree_ctx *ctx, const depend_atom *query, int flags)
 	if (ctx->cache.categories == NULL)
 		ctx->cache.categories = create_set();
 
-#define search_cat(C) \
-{ \
-	char *lastpn = NULL; \
-	while ((pkg_ctx = tree_next_pkg(C)) != NULL) { \
-		atom = tree_get_atom(pkg_ctx, \
-				query->SLOT != NULL || flags & TREE_MATCH_FULL_ATOM); \
-		/* skip virtual/ package as requested */ \
-		if (!(flags & TREE_MATCH_VIRTUAL || \
-				strcmp(atom->CATEGORY, "virtual") != 0)) \
-			continue; \
-		/* skip acct-* package as requested */ \
-		if (!(flags & TREE_MATCH_ACCT || \
-				strncmp(atom->CATEGORY, "acct-", sizeof("acct-") - 1) != 0)) \
-			continue; \
-		/* see if this atom matches the query */ \
-		if (atom_compare(atom, query) == EQUAL) { \
-			tree_match_ctx *n; \
-			/* skip over additional versions for match latest */ \
-			if (flags & TREE_MATCH_LATEST && lastpn != NULL && \
-					strcmp(lastpn, atom->PN) == 0) \
-				continue; \
-			/* create a new match result */ \
-			n = xzalloc(sizeof(tree_match_ctx)); \
-			n->atom = atom; \
-			n->pkg = pkg_ctx; \
-			if (C->ctx->treetype == TREE_PACKAGES && \
-				pkg_ctx->meta->Q_PATH != NULL) \
-			{ \
-				/* binpkg-multi-instance has a PATH ready for us */ \
-				snprintf(n->path, sizeof(n->path), "%s/%s", \
-						 (char *)C->ctx->path, pkg_ctx->meta->Q_PATH); \
-			} else { \
-				snprintf(n->path, sizeof(n->path), "%s/%s/%s%s", \
-						 (char *)C->ctx->path, C->name, pkg_ctx->name, \
-						 C->ctx->treetype == TREE_EBUILD   ? ".ebuild" : \
-						 C->ctx->treetype == TREE_BINPKGS  ? ".tbz2" : \
-						 C->ctx->treetype == TREE_PACKAGES ? ".tbz2" : ""); \
-			} \
-			if (flags & TREE_MATCH_METADATA) \
-				n->meta = tree_pkg_read(pkg_ctx); \
-			if (C->ctx->treetype == TREE_BINPKGS || \
-					C->ctx->treetype == TREE_PACKAGES) \
-				n->free_atom = n->free_meta = 0; \
-			n->next = ret; \
-			ret = n; \
-			lastpn = atom->PN; \
-		} \
-		if (flags & TREE_MATCH_FIRST && ret != NULL) \
-			break; \
-	} \
-	C->pkg_cur = 0;  /* reset to allow another traversal */ \
-}
-
 	if (query->CATEGORY == NULL) {
+		tree_match_ctx *tret;
 		/* loop through all cats */
 		while ((cat_ctx = tree_next_cat(ctx)) != NULL) {
-			search_cat(cat_ctx);
+			tret = tree_match_search_cat_int(cat_ctx, query, flags);
+			if (tret != NULL)
+				ret = tret;
 			if (ret != NULL && flags & TREE_MATCH_FIRST)
 				break;
 		}
@@ -1878,7 +1964,7 @@ tree_match_atom(tree_ctx *ctx, const depend_atom *query, int flags)
 	} else {
 		/* try CAT, and PN for latest version */
 		if ((cat_ctx = tree_open_cat(ctx, query->CATEGORY)) != NULL)
-			search_cat(cat_ctx);
+			ret = tree_match_search_cat_int(cat_ctx, query, flags);
 	}
 
 	return ret;

diff --git a/libq/tree.h b/libq/tree.h
index ed7b55b..2af425e 100644
--- a/libq/tree.h
+++ b/libq/tree.h
@@ -39,6 +39,7 @@ struct tree_ctx {
 		TREE_PACKAGES,
 		TREE_BINPKGS,
 	} treetype:3;
+	tree_ctx *subtree;
 	tree_pkg_ctx *ebuilddir_pkg_ctx;
 	tree_cat_ctx *ebuilddir_cat_ctx;
 	tree_ctx *ebuilddir_ctx;


             reply	other threads:[~2025-04-21 14:44 UTC|newest]

Thread overview: 197+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-21 14:44 Fabian Groffen [this message]
  -- strict thread matches above, loose matches on Subject: below --
2024-07-03 19:44 [gentoo-commits] proj/portage-utils:master commit in: libq/ Fabian Groffen
2024-04-08 19:27 Fabian Groffen
2024-02-01  8:21 Fabian Groffen
2024-02-01  8:21 Fabian Groffen
2024-01-31 20:41 Fabian Groffen
2024-01-31 19:30 Fabian Groffen
2024-01-31 19:29 Fabian Groffen
2024-01-27 13:28 Fabian Groffen
2023-04-21 19:11 Fabian Groffen
2023-01-30 14:14 Fabian Groffen
2022-05-26 14:36 Fabian Groffen
2022-05-26 14:36 Fabian Groffen
2022-05-20 17:15 Fabian Groffen
2022-05-20 17:15 Fabian Groffen
2022-05-19  8:32 Fabian Groffen
2022-05-19  8:16 Fabian Groffen
2022-05-19  7:45 Fabian Groffen
2022-02-12 17:13 Fabian Groffen
2022-02-12 17:13 Fabian Groffen
2022-02-06 14:51 Fabian Groffen
2022-02-06 14:29 Fabian Groffen
2022-02-06 13:27 Fabian Groffen
2022-02-06 13:27 Fabian Groffen
2022-02-06 12:22 Fabian Groffen
2021-12-29 12:20 Fabian Groffen
2021-12-26 13:59 Fabian Groffen
2021-12-26 13:59 Fabian Groffen
2021-12-26 13:59 Fabian Groffen
2021-12-26 13:59 Fabian Groffen
2021-12-13  8:39 Fabian Groffen
2021-12-13  8:39 Fabian Groffen
2021-11-13 14:27 Fabian Groffen
2021-10-09 12:13 Fabian Groffen
2021-10-04  6:28 Fabian Groffen
2021-10-04  6:28 Fabian Groffen
2021-10-03 10:49 Fabian Groffen
2021-06-23  7:14 Fabian Groffen
2021-06-14  9:34 Fabian Groffen
2021-06-14  9:34 Fabian Groffen
2021-06-14  9:34 Fabian Groffen
2021-06-14  9:34 Fabian Groffen
2021-06-14  9:34 Fabian Groffen
2021-06-14  9:34 Fabian Groffen
2021-06-01 19:43 Fabian Groffen
2021-05-23 10:54 Fabian Groffen
2021-05-10  9:15 Fabian Groffen
2021-04-29 15:04 Fabian Groffen
2021-04-29 13:47 Fabian Groffen
2021-04-29 13:24 Fabian Groffen
2021-03-13 12:44 Fabian Groffen
2021-02-20 12:06 Fabian Groffen
2021-02-20 11:44 Fabian Groffen
2021-02-17 20:23 Fabian Groffen
2021-02-17 20:23 Fabian Groffen
2021-01-15 20:05 Fabian Groffen
2020-06-27  9:38 Fabian Groffen
2020-06-07 10:41 Fabian Groffen
2020-05-25 18:19 Fabian Groffen
2020-05-25 18:02 Fabian Groffen
2020-05-25 13:26 Fabian Groffen
2020-05-25 11:20 Fabian Groffen
2020-05-25 11:06 Fabian Groffen
2020-05-25 10:43 Fabian Groffen
2020-05-25 10:43 Fabian Groffen
2020-05-25 10:43 Fabian Groffen
2020-05-25 10:43 Fabian Groffen
2020-05-25 10:43 Fabian Groffen
2020-05-17 12:35 Fabian Groffen
2020-05-17 12:35 Fabian Groffen
2020-02-03 13:17 Fabian Groffen
2020-02-03 13:09 Fabian Groffen
2020-01-26 19:31 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-22 19:54 Fabian Groffen
2020-01-20 19:54 Fabian Groffen
2020-01-20 19:34 Fabian Groffen
2020-01-19 19:36 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 19:09 Fabian Groffen
2020-01-19 16:37 Fabian Groffen
2020-01-19 12:37 Fabian Groffen
2020-01-19 10:05 Fabian Groffen
2020-01-19  9:49 Fabian Groffen
2020-01-19  9:49 Fabian Groffen
2020-01-17  8:22 Fabian Groffen
2020-01-05 16:08 Fabian Groffen
2020-01-05 16:08 Fabian Groffen
2020-01-05 16:08 Fabian Groffen
2020-01-02 15:09 Fabian Groffen
2020-01-02 14:07 Fabian Groffen
2020-01-02 14:07 Fabian Groffen
2020-01-02 14:07 Fabian Groffen
2020-01-02 11:55 Fabian Groffen
2020-01-02 11:19 Fabian Groffen
2019-12-30 17:24 Fabian Groffen
2019-12-27 21:19 Fabian Groffen
2019-12-27 16:57 Fabian Groffen
2019-12-27 16:57 Fabian Groffen
2019-11-29 13:22 Fabian Groffen
2019-11-20 17:23 Fabian Groffen
2019-11-19 20:28 Fabian Groffen
2019-11-17 15:12 Fabian Groffen
2019-11-17 15:12 Fabian Groffen
2019-11-13 18:19 Fabian Groffen
2019-11-13 15:48 Fabian Groffen
2019-11-13 15:20 Fabian Groffen
2019-11-09 10:29 Fabian Groffen
2019-09-26 14:06 Fabian Groffen
2019-09-26 14:06 Fabian Groffen
2019-09-26 14:06 Fabian Groffen
2019-09-26 14:06 Fabian Groffen
2019-09-26 13:00 Fabian Groffen
2019-09-25 15:05 Fabian Groffen
2019-09-21 19:53 Fabian Groffen
2019-09-21 19:53 Fabian Groffen
2019-07-14 18:51 Fabian Groffen
2019-07-13 15:37 Fabian Groffen
2019-07-13  9:50 Fabian Groffen
2019-07-12 18:04 Fabian Groffen
2019-06-19  7:41 Fabian Groffen
2019-06-10 10:09 Fabian Groffen
2019-06-05  7:57 Fabian Groffen
2019-05-21 14:12 Fabian Groffen
2019-05-14 20:19 Fabian Groffen
2019-05-14 20:19 Fabian Groffen
2019-05-11 11:11 Fabian Groffen
2019-05-11  7:14 Fabian Groffen
2019-05-11  7:14 Fabian Groffen
2019-05-10 15:32 Fabian Groffen
2019-05-10 15:32 Fabian Groffen
2019-05-10 15:32 Fabian Groffen
2019-05-07  6:19 Fabian Groffen
2019-05-06 16:04 Fabian Groffen
2019-05-06 16:04 Fabian Groffen
2019-05-05 20:05 Fabian Groffen
2019-05-05 18:13 Fabian Groffen
2019-05-05  8:58 Fabian Groffen
2019-05-04 11:53 Fabian Groffen
2019-05-03 11:45 Fabian Groffen
2019-05-02 15:17 Fabian Groffen
2019-05-01 19:09 Fabian Groffen
2019-04-30  8:20 Fabian Groffen
2019-04-30  7:54 Fabian Groffen
2019-04-28 17:10 Fabian Groffen
2019-04-28 16:21 Fabian Groffen
2019-04-28 16:02 Fabian Groffen
2019-04-27  8:38 Fabian Groffen
2019-04-25 17:36 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-25  9:22 Fabian Groffen
2019-04-19 11:47 Fabian Groffen
2019-03-27 10:55 Fabian Groffen
2019-03-11 20:55 Fabian Groffen
2019-03-09 18:58 Fabian Groffen
2019-02-27 20:53 Fabian Groffen
2019-02-27 20:53 Fabian Groffen
2019-02-05 14:19 Fabian Groffen
2018-12-20 20:02 Fabian Groffen
2018-12-20 20:02 Fabian Groffen
2018-12-20 18:24 Fabian Groffen
2018-04-09  7:15 Fabian Groffen
2018-04-05 13:31 Fabian Groffen
2018-04-05 12:46 Fabian Groffen
2018-04-03 20:00 Fabian Groffen
2018-03-26 18:41 Fabian Groffen
2018-03-25 14:13 Fabian Groffen
2018-03-25 14:00 Fabian Groffen
2018-03-23 20:17 Fabian Groffen
2018-03-23 11:56 Fabian Groffen
2018-03-23 11:29 Fabian Groffen
2017-12-29 11:45 Fabian Groffen
2017-12-29 11:45 Fabian Groffen
2017-12-29 11:45 Fabian Groffen
2016-12-29  2:25 Mike Frysinger
2016-11-12 17:23 Mike Frysinger
2016-02-14  1:26 Mike Frysinger
2016-02-14  1:26 Mike Frysinger
2015-11-26  8:43 Mike Frysinger
2015-10-15 22:00 Mike Frysinger
2015-10-15 22:00 Mike Frysinger
2015-05-31  8:31 Mike Frysinger
2015-05-19 17:37 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-24  1:26 Mike Frysinger
2015-02-21 18:06 Mike Frysinger
2015-02-16 11:47 Mike Frysinger
2014-03-11  4:53 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger
2014-03-08  5:51 Mike Frysinger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1745246308.eb6d9110d09080e63944da0c1b0265156ab1e326.grobian@gentoo \
    --to=grobian@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox