aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Groffen <grobian@gentoo.org>2019-04-25 11:03:21 +0200
committerFabian Groffen <grobian@gentoo.org>2019-04-25 11:03:21 +0200
commit33598fc089e54253261d5a0ec176bde9d300a94f (patch)
tree00b30c8040235cb55e49ba271b3ef5af95aae3e4 /qsearch.c
parentlibq/cache: set repo in cache_pkg_ctx when found (diff)
downloadportage-utils-33598fc089e54253261d5a0ec176bde9d300a94f.tar.gz
portage-utils-33598fc089e54253261d5a0ec176bde9d300a94f.tar.bz2
portage-utils-33598fc089e54253261d5a0ec176bde9d300a94f.zip
qsearch: rewrite to use libq/cache
Signed-off-by: Fabian Groffen <grobian@gentoo.org>
Diffstat (limited to 'qsearch.c')
-rw-r--r--qsearch.c281
1 files changed, 100 insertions, 181 deletions
diff --git a/qsearch.c b/qsearch.c
index f543b8ad..b6d7410c 100644
--- a/qsearch.c
+++ b/qsearch.c
@@ -25,232 +25,151 @@
#include "xarray.h"
#include "xregex.h"
-#define QSEARCH_FLAGS "acesSNH" COMMON_FLAGS
+#define QSEARCH_FLAGS "asSNHR" COMMON_FLAGS
static struct option const qsearch_long_opts[] = {
{"all", no_argument, NULL, 'a'},
- {"cache", no_argument, NULL, 'c'},
- {"ebuilds", no_argument, NULL, 'e'},
{"search", no_argument, NULL, 's'},
{"desc", a_argument, NULL, 'S'},
{"name-only", no_argument, NULL, 'N'},
{"homepage", no_argument, NULL, 'H'},
+ {"repo", no_argument, NULL, 'R'},
COMMON_LONG_OPTS
};
static const char * const qsearch_opts_help[] = {
"List the descriptions of every package in the cache",
- "Use the portage cache",
- "Use the portage ebuild tree (default)",
"Regex search package basenames",
- "Regex search package descriptions",
+ "Regex search package descriptions (or homepage when using -H)",
"Only show package name",
- "Show homepage info",
+ "Show homepage info instead of description",
+ "Show repository the ebuild originates from",
COMMON_OPTS_HELP
};
#define qsearch_usage(ret) usage(ret, QSEARCH_FLAGS, qsearch_long_opts, qsearch_opts_help, NULL, lookup_applet_idx("qsearch"))
-#define LAST_BUF_SIZE 256
+struct qsearch_state {
+ bool show_homepage:1;
+ bool show_name:1;
+ bool show_desc:1;
+ bool show_repo:1;
+ bool search_desc:1;
+ bool search_name:1;
+ regex_t search_expr;
+};
-/* Search an ebuild's details via the metadata cache. */
-static void
-qsearch_ebuild_metadata(
- int overlay_fd,
- const char *ebuild,
- const char *search_me,
- char *last,
- bool search_desc,
- bool search_all,
- bool search_name,
- bool show_name_only,
- bool show_homepage)
+static int
+qsearch_cb(cache_pkg_ctx *pkg_ctx, void *priv)
{
- (void)overlay_fd;
- (void)search_name;
-
- portage_cache *pcache = cache_read_file(portcachedir_type, ebuild);
-
- if (pcache == NULL) {
- warnf("missing cache, please (re)generate");
- return;
+ static depend_atom *last_atom;
+
+ struct qsearch_state *state = (struct qsearch_state *)priv;
+ depend_atom *atom;
+ char buf[_Q_PATH_MAX];
+ cache_pkg_meta *meta;
+ char *desc;
+ char *repo;
+ bool match;
+
+ snprintf(buf, sizeof(buf), "%s/%s", pkg_ctx->cat_ctx->name, pkg_ctx->name);
+ atom = atom_explode(buf);
+ if (atom == NULL)
+ return 0;
+
+ /* skip duplicate packages (we never report version) */
+ if (last_atom != NULL && strcmp(last_atom->PN, atom->PN) == 0) {
+ atom_implode(atom);
+ return 0;
}
- if (strcmp(pcache->atom->PN, last) != 0) {
- strncpy(last, pcache->atom->PN, LAST_BUF_SIZE);
- if (search_all || rematch(search_me,
- (search_desc ? pcache->DESCRIPTION : ebuild),
- REG_EXTENDED | REG_ICASE) == 0)
- printf("%s%s/%s%s%s%s%s\n", BOLD, pcache->atom->CATEGORY, BLUE,
- pcache->atom->PN, NORM,
- (show_name_only ? "" : " "),
- (show_name_only ? "" :
- (show_homepage ? pcache->HOMEPAGE : pcache->DESCRIPTION)));
- }
- cache_free(pcache);
-}
-
-/* Search an ebuild's details via the ebuild cache. */
-static void
-qsearch_ebuild_ebuild(
- int overlay_fd,
- const char *ebuild,
- const char *search_me,
- char *last,
- bool search_desc,
- bool search_all,
- bool search_name,
- bool show_name_only,
- bool show_homepage)
-{
- const char * const search_vars[] = { "DESCRIPTION=", "HOMEPAGE=" };
- const char *search_var = search_vars[show_homepage ? 1 : 0];
- size_t search_len = strlen(search_var);
- char *p, *q, *str;
- char *buf = NULL;
- int linelen;
- size_t buflen;
- bool show_it = false;
- FILE *ebuildfp;
- int fd;
-
- str = xstrdup(ebuild);
- p = dirname(str);
-
- (void)search_desc;
- (void)show_homepage;
-
- if (strcmp(p, last) == 0)
- goto no_cache_ebuild_match;
-
- strncpy(last, p, LAST_BUF_SIZE);
- if (search_name) {
- if (rematch(search_me, basename(last), REG_EXTENDED | REG_ICASE) != 0) {
- goto no_cache_ebuild_match;
- } else {
- q = NULL;
- show_it = true;
+ match = false;
+ if (state->search_name &&
+ regexec(&state->search_expr, atom->PN, 0, NULL, 0) == 0)
+ match = true;
+
+ desc = NULL;
+ meta = NULL;
+ if ((match && (state->show_homepage || state->show_desc)) ||
+ (!match && state->search_desc))
+ {
+ meta = cache_pkg_read(pkg_ctx);
+ if (meta != NULL) {
+ if (state->show_homepage)
+ desc = meta->HOMEPAGE;
+ else if (state->show_desc)
+ desc = meta->DESCRIPTION;
}
}
- fd = openat(overlay_fd, ebuild, O_RDONLY|O_CLOEXEC);
- if (fd != -1) {
- ebuildfp = fdopen(fd, "r");
- if (ebuildfp == NULL) {
- close(fd);
- goto no_cache_ebuild_match;
- }
- } else {
- warnf("missing cache, please (re)generate");
- goto no_cache_ebuild_match;
+ if (!match && state->search_desc && desc != NULL &&
+ regexec(&state->search_expr, desc, 0, NULL, 0) == 0)
+ match = true;
+
+ repo = NULL;
+ if (match) {
+ if (state->show_repo)
+ repo = pkg_ctx->repo;
+ printf("%s%s/%s%s%s%s%s%s%s%s\n", BOLD, atom->CATEGORY,
+ BLUE, atom->PN,
+ GREEN, (repo ? "::" : ""), (repo ? repo : ""), NORM,
+ (state->show_name ? "" : " "),
+ (state->show_name ? "" : desc ? desc : ""));
}
- while ((linelen = getline(&buf, &buflen, ebuildfp)) >= 0) {
- if ((size_t)linelen <= search_len)
- continue;
- if (strncmp(buf, search_var, search_len) != 0)
- continue;
- if ((q = strrchr(buf, '"')) != NULL)
- *q = 0;
- if (strlen(buf) <= search_len)
- break;
- q = buf + search_len + 1;
- if (!search_all && !search_name &&
- rematch(search_me, q, REG_EXTENDED | REG_ICASE) != 0)
- break;
- show_it = true;
- break;
- }
+ if (meta != NULL)
+ cache_close_meta(meta);
- if (show_it) {
- const char *pkg = basename(p);
- printf("%s%s/%s%s%s%s%s\n",
- BOLD, dirname(p), BLUE, pkg, NORM,
- (show_name_only ? "" : " "),
- (show_name_only ? "" : q ? : "<no DESCRIPTION found>"));
- }
+ if (last_atom != NULL)
+ atom_implode(last_atom);
+ last_atom = atom;
- free(buf);
- fclose(ebuildfp);
- no_cache_ebuild_match:
- free(str);
+ return EXIT_SUCCESS;
}
int qsearch_main(int argc, char **argv)
{
- char last[LAST_BUF_SIZE];
- char *search_me = NULL;
- bool show_homepage = false, show_name_only = false;
- bool search_desc = false, search_all = false, search_name = true;
- int search_cache = CACHE_EBUILD;
+ int ret = EXIT_SUCCESS;
+ const char *search_me = NULL;
int i;
- void (*search_func)(int, const char *, const char *, char *last, bool, bool, bool, bool, bool);
+ const char *overlay;
+ size_t n;
+ struct qsearch_state state = {
+ .show_homepage = false,
+ .show_name = false,
+ .show_desc = false,
+ .show_repo = false,
+ .search_desc = false,
+ .search_name = false,
+ };
while ((i = GETOPT_LONG(QSEARCH, qsearch, "")) != -1) {
switch (i) {
COMMON_GETOPTS_CASES(qsearch)
- case 'a': search_all = true; break;
- case 'c': search_cache = CACHE_METADATA; break;
- case 'e': search_cache = CACHE_EBUILD; break;
- case 's': search_desc = false; search_name = true; break;
- case 'S': search_desc = true; search_name = false; break;
- case 'N': show_name_only = true; break;
- case 'H': show_homepage = true; break;
+ case 'a': search_me = ".*"; break;
+ case 's': state.search_name = true; break;
+ case 'S': state.search_desc = true; break;
+ case 'N': state.show_name = true; break;
+ case 'H': state.show_homepage = true; break;
+ case 'R': state.show_repo = true; break;
}
}
- switch (search_cache) {
- case CACHE_METADATA:
- search_func = qsearch_ebuild_metadata;
- break;
- case CACHE_EBUILD:
- search_func = qsearch_ebuild_ebuild;
- break;
- default:
- err("unknown cache %i", search_cache);
- }
+ /* set defaults */
+ if (!state.show_homepage)
+ state.show_desc = true;
+ if (!state.search_name && !state.search_desc)
+ state.search_name = true;
- if (search_all) {
- search_desc = true;
- search_name = false;
- } else {
+ /* compile expression */
+ if (search_me == NULL) {
if (argc == optind)
qsearch_usage(EXIT_FAILURE);
search_me = argv[optind];
}
- last[0] = 0;
+ xregcomp(&state.search_expr, search_me, REG_EXTENDED | REG_ICASE);
- int ret = 0;
- size_t n;
- const char *overlay;
- array_for_each(overlays, n, overlay) {
- FILE *fp = fopen(initialize_flat(overlay, search_cache, false), "r");
- if (!fp) {
- warnp("opening cache for %s failed", overlay);
- ret = 1;
- continue;
- }
-
- int overlay_fd = open(overlay, O_RDONLY|O_CLOEXEC|O_PATH);
- if (overlay_fd < 0) {
- fclose(fp);
- warnp("open failed: %s", overlay);
- ret = 1;
- continue;
- }
-
- int linelen;
- size_t buflen;
- char *buf = NULL;
- while ((linelen = getline(&buf, &buflen, fp)) >= 0) {
- rmspace_len(buf, (size_t)linelen);
- if (!buf[0])
- continue;
-
- search_func(overlay_fd, buf, search_me, last, search_desc,
- search_all, search_name, show_name_only, show_homepage);
- }
- free(buf);
- close(overlay_fd);
- fclose(fp);
- }
+ /* use sorted order here so the duplicate reduction works reliably */
+ array_for_each(overlays, n, overlay)
+ ret |= cache_foreach_pkg_sorted(portroot, overlay, qsearch_cb,
+ &state, NULL, NULL);
return ret;
}