From 0eadaab19d7ad05261dd820d30bfa0a85f3ce5e7 Mon Sep 17 00:00:00 2001 From: Juan RP Date: Mon, 26 May 2014 17:30:44 +0200 Subject: [PATCH] xbps-query: added --regex to use EREs in ownedby and search modes. This replaces previous -S, --search-regex option. The regex option can now be used in the ownedby and search modes. Also added -S, --show option which is the default mode if no other mode set, and defaults to it to preserve compatibility. --- NEWS | 11 ++-- bin/xbps-query/defs.h | 5 +- bin/xbps-query/main.c | 104 ++++++++++++++++++++---------------- bin/xbps-query/ownedby.c | 70 +++++++++++------------- bin/xbps-query/search.c | 104 +++++++++++++++--------------------- bin/xbps-query/xbps-query.8 | 49 +++++++---------- 6 files changed, 163 insertions(+), 180 deletions(-) diff --git a/NEWS b/NEWS index b066ab0b..d77b2c24 100644 --- a/NEWS +++ b/NEWS @@ -1,13 +1,18 @@ xbps-0.37 (???): - * xbps-query(8): new option "-S, --search-regex" that matches packages in - repositories with Extended Regular Expressions as explained in regex(7). + * xbps-query(8): new option (-S, --show) which shows info of a package + installed locally or in a repository with -R. This is the default mode + if no other mode is set; to preserve compatibility with previous versions. + + * xbps-query(8): new long option "--regex" that can be used in the + "ownedby (-o, --ownedby)" and "search (-s, --search)" modes to match + Extended Regular Expressions against package properties. This allows you to find packages by matching EREs in package properties, for example to find out what packages were built between 2014-05-23 and 2014-05-25: - $ xbps-query -S 2014-05-2[35] -p build-date + $ xbps-query --regex -s 2014-05-2[35] -p build-date ... $ diff --git a/bin/xbps-query/defs.h b/bin/xbps-query/defs.h index 7a4c879c..05a3691d 100644 --- a/bin/xbps-query/defs.h +++ b/bin/xbps-query/defs.h @@ -53,8 +53,7 @@ int repo_show_pkg_namedesc(struct xbps_handle *, xbps_object_t, void *, bool *); /* from ownedby.c */ -int ownedby(struct xbps_handle *, int, char **); -int repo_ownedby(struct xbps_handle *, int, char **); +int ownedby(struct xbps_handle *, const char *, bool, bool); /* From list.c */ unsigned int find_longest_pkgver(struct xbps_handle *, xbps_object_t); @@ -68,6 +67,6 @@ int list_pkgs_pkgdb(struct xbps_handle *); int repo_list(struct xbps_handle *); /* from search.c */ -int repo_search(struct xbps_handle *, int, char **, const char *, bool); +int repo_search(struct xbps_handle *, const char *, const char *, bool); #endif /* !_XBPS_QUERY_DEFS_H_ */ diff --git a/bin/xbps-query/main.c b/bin/xbps-query/main.c index 882318c8..a83250c8 100644 --- a/bin/xbps-query/main.c +++ b/bin/xbps-query/main.c @@ -36,33 +36,34 @@ static void __attribute__((noreturn)) usage(bool fail) { fprintf(stdout, - "Usage: xbps-query [OPTIONS...] [PKGNAME]\n" + "Usage: xbps-query [OPTIONS] MODE [ARGUMENTS]\n" "\nOPTIONS\n" " -C --config Full path to configuration file\n" " -c --cachedir Full path to cachedir\n" " -d --debug Debug mode shown to stderr\n" " -h --help Print help usage\n" - " -p --property PROP,... Show properties for PKGNAME\n" + " -p --property PROP[,...] Show properties for PKGNAME\n" " -R --repository Enable repository mode. This mode explicitly\n" " looks for packages in repositories.\n" " --repository= Enable repository mode and add repository\n" " to the top of the list. This option can be\n" " specified multiple times.\n" + " --regex Use Extended Regular Expressions to match\n" " -r --rootdir Full path to rootdir\n" " -V --version Show XBPS version\n" " -v --verbose Verbose messages\n" - "\nMODE [only one mode may be specified]\n" - " -l --list-pkgs List available packages\n" - " -L --list-repos List working repositories\n" + "\nMODE\n" + " -l --list-pkgs List installed packages\n" + " -L --list-repos List registered repositories\n" " -H --list-hold-pkgs List packages on hold state\n" " -m --list-manual-pkgs List packages installed explicitly\n" " -O --list-orphans List package orphans\n" - " -o --ownedby FILE(s) Search for packages owning FILE(s)\n" - " -s --search PATTERN(s) Search for packages matching PATTERN(s)\n" - " -S,--search-regex RE Search for packages matching RE\n" - " -f --files Show files for PKGNAME\n" - " -x --deps Show dependencies for PKGNAME (set it twice for a full dependency tree)\n" - " -X --revdeps Show reverse dependencies for PKGNAME\n"); + " -o --ownedby FILE Search for package files by matching STRING or REGEX\n" + " -S --show PKG Show information for PKG [default mode]\n" + " -s --search PKG Search for packages by matching PKG, STRING or REGEX\n" + " -f --files PKG Show package files for PKG\n" + " -x --deps PKG Show dependencies for PKG (set it twice for a full dependency tree)\n" + " -X --revdeps PKG Show reverse dependencies for PKG\n"); exit(fail ? EXIT_FAILURE : EXIT_SUCCESS); } @@ -70,7 +71,7 @@ usage(bool fail) int main(int argc, char **argv) { - const char *shortopts = "C:c:D:dfhHLlmOop:Rr:sSVvXx"; + const char *shortopts = "C:c:D:dfhHLlmOo:p:Rr:s:S:VvXx"; const struct option longopts[] = { { "config", required_argument, NULL, 'C' }, { "cachedir", required_argument, NULL, 'c' }, @@ -81,31 +82,32 @@ main(int argc, char **argv) { "list-hold-pkgs", no_argument, NULL, 'H' }, { "list-manual-pkgs", no_argument, NULL, 'm' }, { "list-orphans", no_argument, NULL, 'O' }, - { "ownedby", no_argument, NULL, 'o' }, + { "ownedby", required_argument, NULL, 'o' }, { "property", required_argument, NULL, 'p' }, { "repository", optional_argument, NULL, 'R' }, + { "regex", no_argument, NULL, 0 }, { "rootdir", required_argument, NULL, 'r' }, - { "search", no_argument, NULL, 's' }, - { "search-regex", no_argument, NULL, 'S' }, + { "show", required_argument, NULL, 'S' }, + { "search", required_argument, NULL, 's' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, - { "files", no_argument, NULL, 'f' }, - { "deps", no_argument, NULL, 'x' }, - { "revdeps", no_argument, NULL, 'X' }, + { "files", required_argument, NULL, 'f' }, + { "deps", required_argument, NULL, 'x' }, + { "revdeps", required_argument, NULL, 'X' }, { NULL, 0, NULL, 0 }, }; struct xbps_handle xh; - const char *rootdir, *cachedir, *conffile, *props; + const char *pkg, *rootdir, *cachedir, *conffile, *props; int c, flags, rv, show_deps = 0; bool list_pkgs, list_repos, orphans, own; bool list_manual, list_hold, show_prop, show_files, show_rdeps; - bool show, search, search_regex, repo_mode, opmode, fulldeptree; + bool show, search, regex, repo_mode, opmode, fulldeptree; - rootdir = cachedir = conffile = props = NULL; + rootdir = cachedir = conffile = props = pkg = NULL; flags = rv = c = 0; list_pkgs = list_repos = list_hold = orphans = search = own = false; list_manual = show_prop = show_files = false; - search_regex = show = show_rdeps = fulldeptree = false; + regex = show = show_rdeps = fulldeptree = false; repo_mode = opmode = false; memset(&xh, 0, sizeof(xh)); @@ -124,6 +126,7 @@ main(int argc, char **argv) flags |= XBPS_FLAG_DEBUG; break; case 'f': + pkg = optarg; show_files = opmode = true; break; case 'H': @@ -145,6 +148,7 @@ main(int argc, char **argv) orphans = true; break; case 'o': + pkg = optarg; own = opmode = true; break; case 'p': @@ -163,11 +167,13 @@ main(int argc, char **argv) case 'r': rootdir = optarg; break; - case 's': - search = opmode = true; - break; case 'S': - search_regex = opmode = true; + pkg = optarg; + show = opmode = true; + break; + case 's': + pkg = optarg; + search = opmode = true; break; case 'v': flags |= XBPS_FLAG_VERBOSE; @@ -176,24 +182,32 @@ main(int argc, char **argv) printf("%s\n", XBPS_RELVER); exit(EXIT_SUCCESS); case 'x': + pkg = optarg; show_deps++; opmode = true; break; case 'X': + pkg = optarg; show_rdeps = opmode = true; break; + case 0: + regex = true; + break; case '?': usage(true); /* NOTREACHED */ } } - if (!opmode && argc > optind) - show = true; - else if (argc == 1 || (opmode && (argc == optind))) - usage(true); - else if ((search || own) && (argc == optind)) - usage(true); + argc -= optind; + argv += optind; + if (argc > 1) + usage(true); + else if (!opmode) { + /* show mode by default */ + show = opmode = true; + pkg = *argv; + } /* * Initialize libxbps. */ @@ -232,29 +246,25 @@ main(int argc, char **argv) } else if (own) { /* ownedby mode */ - if (repo_mode) - rv = repo_ownedby(&xh, argc - optind, argv + optind); - else - rv = ownedby(&xh, argc - optind, argv + optind); + rv = ownedby(&xh, pkg, repo_mode, regex); - } else if (search || search_regex) { + } else if (search) { /* search mode */ - rv = repo_search(&xh, argc - optind, argv + optind, props, search_regex); + rv = repo_search(&xh, pkg, props, regex); } else if (show || show_prop) { /* show mode */ if (repo_mode) - rv = repo_show_pkg_info(&xh, argv[optind], props); + rv = repo_show_pkg_info(&xh, pkg, props); else - rv = show_pkg_info_from_metadir(&xh, - argv[optind], props); + rv = show_pkg_info_from_metadir(&xh, pkg, props); } else if (show_files) { /* show-files mode */ if (repo_mode) - rv = repo_show_pkg_files(&xh, argv[optind]); + rv = repo_show_pkg_files(&xh, pkg); else - rv = show_pkg_files_from_metadir(&xh, argv[optind]); + rv = show_pkg_files_from_metadir(&xh, pkg); } else if (show_deps) { /* show-deps mode */ @@ -262,16 +272,16 @@ main(int argc, char **argv) fulldeptree = true; if (repo_mode) - rv = repo_show_pkg_deps(&xh, argv[optind], fulldeptree); + rv = repo_show_pkg_deps(&xh, pkg, fulldeptree); else - rv = show_pkg_deps(&xh, argv[optind], fulldeptree); + rv = show_pkg_deps(&xh, pkg, fulldeptree); } else if (show_rdeps) { /* show-rdeps mode */ if (repo_mode) - rv = repo_show_pkg_revdeps(&xh, argv[optind]); + rv = repo_show_pkg_revdeps(&xh, pkg); else - rv = show_pkg_revdeps(&xh, argv[optind]); + rv = show_pkg_revdeps(&xh, pkg); } exit(rv); diff --git a/bin/xbps-query/ownedby.c b/bin/xbps-query/ownedby.c index 2daccb16..062a24bf 100644 --- a/bin/xbps-query/ownedby.c +++ b/bin/xbps-query/ownedby.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2010-2013 Juan Romero Pardines. + * Copyright (c) 2010-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,14 +31,14 @@ #include #include #include +#include #include #include "defs.h" struct ffdata { - int npatterns; - char **patterns; - const char *repouri; + bool regex; + const char *pat, *repouri; xbps_array_t allkeys; xbps_dictionary_t filesd; }; @@ -52,7 +52,7 @@ match_files_by_pattern(xbps_dictionary_t pkg_filesd, xbps_array_t array; xbps_object_t obj; const char *keyname, *filestr, *typestr; - int x; + regex_t regex; keyname = xbps_dictionary_keysym_cstring_nocopy(key); @@ -72,11 +72,15 @@ match_files_by_pattern(xbps_dictionary_t pkg_filesd, xbps_dictionary_get_cstring_nocopy(obj, "file", &filestr); if (filestr == NULL) continue; - for (x = 0; x < ffd->npatterns; x++) { - if ((fnmatch(ffd->patterns[x], filestr, FNM_PERIOD)) == 0) { - printf("%s: %s (%s)\n", pkgver, - filestr, typestr); + if (ffd->regex) { + regcomp(®ex, ffd->pat, REG_EXTENDED|REG_NOSUB); + if (regexec(®ex, filestr, 0, 0, 0) == 0) { + printf("%s: %s (%s)\n", pkgver, filestr, typestr); } + regfree(®ex); + } else { + if ((fnmatch(ffd->pat, filestr, FNM_PERIOD)) == 0) + printf("%s: %s (%s)\n", pkgver, filestr, typestr); } } } @@ -112,22 +116,6 @@ ownedby_pkgdb_cb(struct xbps_handle *xhp, return 0; } -int -ownedby(struct xbps_handle *xhp, int npatterns, char **patterns) -{ - struct ffdata ffd; - char *rfile; - - ffd.npatterns = npatterns; - ffd.patterns = patterns; - - for (int i = 0; i < npatterns; i++) { - rfile = realpath(patterns[i], NULL); - if (rfile) - patterns[i] = rfile; - } - return xbps_pkgdb_foreach_cb(xhp, ownedby_pkgdb_cb, &ffd); -} static int repo_match_cb(struct xbps_handle *xhp _unused, @@ -138,14 +126,19 @@ repo_match_cb(struct xbps_handle *xhp _unused, { struct ffdata *ffd = arg; const char *filestr; + regex_t regex; for (unsigned int i = 0; i < xbps_array_count(obj); i++) { xbps_array_get_cstring_nocopy(obj, i, &filestr); - for (int x = 0; x < ffd->npatterns; x++) { - if ((fnmatch(ffd->patterns[x], filestr, FNM_PERIOD)) == 0) { - printf("%s: %s (%s)\n", - key, filestr, ffd->repouri); + if (ffd->regex) { + regcomp(®ex, ffd->pat, REG_EXTENDED|REG_NOSUB); + if (regexec(®ex, filestr, 0, 0, 0) == 0) { + printf("%s: %s (%s)\n", key, filestr, ffd->repouri); } + regfree(®ex); + } else { + if ((fnmatch(ffd->pat, filestr, FNM_PERIOD)) == 0) + printf("%s: %s (%s)\n", key, filestr, ffd->repouri); } } @@ -172,21 +165,22 @@ repo_ownedby_cb(struct xbps_repo *repo, void *arg, bool *done _unused) } int -repo_ownedby(struct xbps_handle *xhp, int npatterns, char **patterns) +ownedby(struct xbps_handle *xhp, const char *pat, bool repo, bool regex) { struct ffdata ffd; char *rfile; int rv; - ffd.npatterns = npatterns; - ffd.patterns = patterns; + ffd.regex = regex; + ffd.pat = pat; - for (int i = 0; i < npatterns; i++) { - rfile = realpath(patterns[i], NULL); - if (rfile) - patterns[i] = rfile; - } - rv = xbps_rpool_foreach(xhp, repo_ownedby_cb, &ffd); + if ((rfile = realpath(pat, NULL)) != NULL) + ffd.pat = rfile; + + if (repo) + rv = xbps_rpool_foreach(xhp, repo_ownedby_cb, &ffd); + else + rv = xbps_pkgdb_foreach_cb(xhp, ownedby_pkgdb_cb, &ffd); return rv; } diff --git a/bin/xbps-query/search.c b/bin/xbps-query/search.c index ebd827cb..1896f2df 100644 --- a/bin/xbps-query/search.c +++ b/bin/xbps-query/search.c @@ -45,10 +45,8 @@ struct search_data { bool regex; - int npatterns; int maxcols; - char **patterns; - const char *prop, *repourl; + const char *pat, *prop, *repourl; xbps_array_t results; }; @@ -106,36 +104,31 @@ search_array_cb(struct xbps_handle *xhp _unused, xbps_object_t obj2; struct search_data *sd = arg; const char *pkgver, *desc, *str; - int x; + regex_t regex; if (sd->prop == NULL) { + bool vpkgfound = false; /* no prop set, match on pkgver/short_desc objects */ xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); xbps_dictionary_get_cstring_nocopy(obj, "short_desc", &desc); - for (x = 0; x < sd->npatterns; x++) { - bool vpkgfound = false; + if (xbps_match_virtual_pkg_in_dict(obj, sd->pat)) + vpkgfound = true; - if (xbps_match_virtual_pkg_in_dict(obj, sd->patterns[x])) - vpkgfound = true; - - if (sd->regex) { - regex_t regex; - - regcomp(®ex, sd->patterns[x], REG_EXTENDED|REG_NOSUB); - if ((regexec(®ex, pkgver, 0, 0, 0) == 0) || - (regexec(®ex, desc, 0, 0, 0) == 0)) { - xbps_array_add_cstring_nocopy(sd->results, pkgver); - xbps_array_add_cstring_nocopy(sd->results, desc); - } - regfree(®ex); - } else { - if ((xbps_pkgpattern_match(pkgver, sd->patterns[x])) || - (strcasestr(pkgver, sd->patterns[x])) || - (strcasestr(desc, sd->patterns[x])) || vpkgfound) { - xbps_array_add_cstring_nocopy(sd->results, pkgver); - xbps_array_add_cstring_nocopy(sd->results, desc); - } + if (sd->regex) { + regcomp(®ex, sd->pat, REG_EXTENDED|REG_NOSUB); + if ((regexec(®ex, pkgver, 0, 0, 0) == 0) || + (regexec(®ex, desc, 0, 0, 0) == 0)) { + xbps_array_add_cstring_nocopy(sd->results, pkgver); + xbps_array_add_cstring_nocopy(sd->results, desc); + } + regfree(®ex); + } else { + if ((xbps_pkgpattern_match(pkgver, sd->pat)) || + (strcasestr(pkgver, sd->pat)) || + (strcasestr(desc, sd->pat)) || vpkgfound) { + xbps_array_add_cstring_nocopy(sd->results, pkgver); + xbps_array_add_cstring_nocopy(sd->results, desc); } } return 0; @@ -146,22 +139,18 @@ search_array_cb(struct xbps_handle *xhp _unused, /* property is an array */ for (unsigned int i = 0; i < xbps_array_count(obj2); i++) { xbps_array_get_cstring_nocopy(obj2, i, &str); - for (x = 0; x < sd->npatterns; x++) { - if (sd->regex) { - regex_t regex; - - regcomp(®ex, sd->patterns[x], REG_EXTENDED|REG_NOSUB); - if (regexec(®ex, str, 0, 0, 0) == 0) { - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - printf("%s: %s (%s)\n", pkgver, str, sd->repourl); - } - regfree(®ex); - } else { - if ((strcasestr(str, sd->patterns[x])) || - (fnmatch(sd->patterns[x], str, FNM_PERIOD)) == 0) { - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - printf("%s: %s (%s)\n", pkgver, str, sd->repourl); - } + if (sd->regex) { + regcomp(®ex, sd->pat, REG_EXTENDED|REG_NOSUB); + if (regexec(®ex, str, 0, 0, 0) == 0) { + xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); + printf("%s: %s (%s)\n", pkgver, str, sd->repourl); + } + regfree(®ex); + } else { + if ((strcasestr(str, sd->pat)) || + (fnmatch(sd->pat, str, FNM_PERIOD)) == 0) { + xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); + printf("%s: %s (%s)\n", pkgver, str, sd->repourl); } } } @@ -172,21 +161,17 @@ search_array_cb(struct xbps_handle *xhp _unused, } else if (xbps_object_type(obj2) == XBPS_TYPE_STRING) { /* property is a string */ str = xbps_string_cstring_nocopy(obj2); - for (x = 0; x < sd->npatterns; x++) { - if (sd->regex) { - regex_t regex; - - regcomp(®ex, sd->patterns[x], REG_EXTENDED|REG_NOSUB); - if (regexec(®ex, str, 0, 0, 0) == 0) { - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - printf("%s: %s (%s)\n", pkgver, str, sd->repourl); - } - regfree(®ex); - } else { - if (strcasestr(str, sd->patterns[x])) { - xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); - printf("%s: %s (%s)\n", pkgver, str, sd->repourl); - } + if (sd->regex) { + regcomp(®ex, sd->pat, REG_EXTENDED|REG_NOSUB); + if (regexec(®ex, str, 0, 0, 0) == 0) { + xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); + printf("%s: %s (%s)\n", pkgver, str, sd->repourl); + } + regfree(®ex); + } else { + if (strcasestr(str, sd->pat)) { + xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); + printf("%s: %s (%s)\n", pkgver, str, sd->repourl); } } } @@ -208,15 +193,14 @@ search_pkgs_cb(struct xbps_repo *repo, void *arg, bool *done _unused) } int -repo_search(struct xbps_handle *xhp, int npatterns, char **patterns, const char *prop, bool regex) +repo_search(struct xbps_handle *xhp, const char *pat, const char *prop, bool regex) { struct search_data sd; int rv; sd.regex = regex; + sd.pat = pat; sd.prop = prop; - sd.npatterns = npatterns; - sd.patterns = patterns; sd.maxcols = get_maxcols(); sd.results = xbps_array_create(); diff --git a/bin/xbps-query/xbps-query.8 b/bin/xbps-query/xbps-query.8 index c62678c2..5f71e451 100644 --- a/bin/xbps-query/xbps-query.8 +++ b/bin/xbps-query/xbps-query.8 @@ -1,4 +1,4 @@ -.Dd May 25, 2014 +.Dd May 26, 2014 .Os Void Linux .Dt xbps-query 8 .Sh NAME @@ -8,7 +8,7 @@ .Nm xbps-query .Op OPTIONS .Ar MODE -.Op PKG +.Op ARGUMENTS .Sh DESCRIPTION The .Nm @@ -70,6 +70,13 @@ than looking in the target root directory. The .Ar url argument is optional and can be used to add the repository to the top of the list. This option can be specified multiple times. +.It Fl -regex +Enables string matching by using Extended Regular Expressions in compatible modes, +currently in the +.Sy ownedby +and +.Sy search +modes. .It Fl r, Fl -rootdir Ar dir Specifies a full path for the target root directory. .It Fl v, Fl -verbose @@ -125,36 +132,20 @@ manually by the user (i.e not as dependency of any package). Lists package orphans in the package database (pkgdb), i.e packages that were installed as dependencies and no package is currently depending on them directly. -.It Fl o, Fl -ownedby Ar PATTERN... -Search for packages owning the files specified by +.It Fl o, Fl -ownedby Ar PATTERN +Search for package files by matching .Ar PATTERN . The .Ar PATTERN -argument can be a simple string or a shell wildcard pattern as explained in -.Xr fnmatch 3 . -Multiple patterns may be specified. -.It Fl S, Fl -search-regex Ar RE.. [ Fl -property Ar PROP ] -Search for packages in repositories matching -.Ar RE -on its -.Em pkgver -and/or -.Em short_desc -properties. -.Ar RE -is a -.Em POSIX Extended Regular Expression -as explained in -.Xr regex 7 . -If a package property is specified with -.Fl -property, -all packages matching -.Ar RE -against -.Ar PROP -will be shown. -.It Fl s, Fl -search Ar PATTERN... [ Fl -property Ar PROP ] -Search for packages in repositories matching +argument can be a simple string, a shell wildcard pattern as explained in +.Xr fnmatch 3 +or an Extended Regular Expression as explained in +.Xr regex 7 +(if +.Fl -regex +option is set). +.It Fl s, Fl -search Ar PATTERN [ Fl -property Ar PROP ] +Search for packages in repositories by matching .Ar PATTERN on its .Em pkgver