[RFC] make search extensions
Roman Neuhauser
neuhauser at sigpipe.cz
Sun Oct 23 15:20:07 PDT 2005
I'm collecting comments on the attached patch[1] (please refrain from
telling me to send-pr).
The patch pulls the awk body of the search target in
Mk/bsd.port.subdir.mk into Tools/make_search. I used the opportunity to
add comments (impossible with the embedded oneliner approach), and
tweaked the code in a few ways to make it more readable.
Contents:
* includes the change in
http://www.freebsd.org/cgi/query-pr.cgi?pr=ports/87840
* adds the possibility to display a line only if the value is not
empty (no more empty B-deps: or R-deps: lines)
this is set by the user by appending a question mark to the display
key, as in:
make search display=name,path,bdeps\?
* adds conditional (see above) display of F-deps:, E-deps:, P-deps:
lines
* enables searching on the F/E/P dependency fields
* the here/there/top spaghetti was replaced with equivalent code
which better communicates the intent
* updates ports.7, plus misc. fixes to make the text more correct
[1] also at http://codex.sigpipe.cz/FreeBSD/ports/make_search,0.patch
--
How many Vietnam vets does it take to screw in a light bulb?
You don't know, man. You don't KNOW.
Cause you weren't THERE. http://bash.org/?255991
-------------- next part --------------
Index: Mk/bsd.port.subdir.mk
===================================================================
RCS file: /home/ncvs/ports/Mk/bsd.port.subdir.mk,v
retrieving revision 1.60
diff -u -r1.60 bsd.port.subdir.mk
--- Mk/bsd.port.subdir.mk 28 Feb 2005 21:09:04 -0000 1.60
+++ Mk/bsd.port.subdir.mk 23 Oct 2005 21:02:12 -0000
@@ -327,106 +327,32 @@
PKGINSTALLVER="${PKGINSTALLVER:S/"/"'"'"/g:S/\$/\$\$/g:S/\\/\\\\/g}"
.endif
-PORTSEARCH_DISPLAY_FIELDS?=name,path,info,maint,index,bdeps,rdeps,www
+PORTSEARCH_DISPLAY_FIELDS?=name,path,info,maint,cat,bdeps?,rdeps?,www,fdeps?,edeps?,pdeps?
PORTSEARCH_KEYLIM?=0
PORTSEARCH_XKEYLIM?=0
PORTSEARCH_IGNORECASE?=1
+PORTSEARCH_DISPLAY_SHORT?=0
search: ${PORTSDIR}/${INDEXFILE}
- @here=${.CURDIR}; \
- cd ${PORTSDIR}; \
- if [ -z "$$key" -a -z "$$xkey" -a \
- -z "$$name" -a -z "$$xname" -a \
- -z "$$path" -a -z "$$xpath" -a \
- -z "$$info" -a -z "$$xinfo" -a \
- -z "$$maint" -a -z "$$xmaint" -a \
- -z "$$cat" -a -z "$$xcat" -a \
- -z "$$bdeps" -a -z "$$xbdeps" -a \
- -z "$$rdeps" -a -z "$$xrdeps" -a \
- -z "$$www" -a -z "$$xwww" ]; \
- then \
- echo "The search target requires a keyword parameter or name parameter,"; \
- echo "e.g.: \"make search key=somekeyword\""; \
- echo "or \"make search name=somekeyword\""; \
- exit; \
- fi; \
- awk -F\| -v there="$$here/" -v top="$$(pwd -P)" \
+ @test -n "$$display" && disp="$$display"; \
+ test -n "$$xdisplay" && xdisp="$$xdisplay"; \
+ awk -F\| -v pwd="${.CURDIR}/" -v portsdir="${PORTSDIR}" \
-v key="$$key" -v xkey="$$xkey" \
-v name="$$name" -v xname="$$xname" \
-v path="$$path" -v xpath="$$xpath" \
-v info="$$info" -v xinfo="$$xinfo" \
-v maint="$$maint" -v xmaint="$$xmaint" \
-v cat="$$cat" -v xcat="$$xcat" \
+ -v fdeps="$$fdeps" -v xfdeps="$$xfdeps" \
+ -v edeps="$$edeps" -v xedeps="$$xedeps" \
+ -v pdeps="$$pdeps" -v xpdeps="$$xpdeps" \
-v bdeps="$$bdeps" -v xbdeps="$$xbdeps" \
-v rdeps="$$rdeps" -v xrdeps="$$xrdeps" \
-v www="$$www" -v xwww="$$xwww" \
-v icase="$${icase:-${PORTSEARCH_IGNORECASE}}" \
-v keylim="$${keylim:-${PORTSEARCH_KEYLIM}}" \
-v xkeylim="$${xkeylim:-${PORTSEARCH_XKEYLIM}}" \
- -v display="$${display:-${PORTSEARCH_DISPLAY_FIELDS}}" \
- 'BEGIN { \
- if (substr(there, 1, length(top)) == top) \
- there = "${PORTSDIR}" substr(there, 1 + length(top)); \
- therelen = length(there); \
- keylen = length(key); keylim = keylim && keylen; \
- if (!keylim && keylen) \
- parms[0] = (icase ? tolower(key) : key); \
- xkeylen = length(xkey); xkeylim = xkeylim && xkeylen; \
- if (!xkeylim && xkeylen) \
- xparms[0] = (icase ? tolower(xkey) : xkey); \
- if (icase) { \
- if (length(name)) parms[1] = tolower(name); if (length(xname)) xparms[1] = tolower(xname); \
- if (length(path)) parms[2] = tolower(path); if (length(xpath)) xparms[2] = tolower(xpath); \
- if (length(info)) parms[4] = tolower(info); if (length(xinfo)) xparms[4] = tolower(xinfo); \
- if (length(maint)) parms[6] = tolower(maint); if (length(xmaint)) xparms[6] = tolower(xmaint); \
- if (length(cat)) parms[7] = tolower(cat); if (length(xcat)) xparms[7] = tolower(xcat); \
- if (length(bdeps)) parms[8] = tolower(bdeps); if (length(xbdeps)) xparms[8] = tolower(xbdeps); \
- if (length(rdeps)) parms[9] = tolower(rdeps); if (length(xrdeps)) xparms[9] = tolower(xrdeps); \
- if (length(www)) parms[10] = tolower(www); if (length(xwww)) xparms[10] = tolower(xwww); \
- } else { \
- if (length(name)) parms[1] = name; if (length(xname)) xparms[1] = xname; \
- if (length(path)) parms[2] = path; if (length(xpath)) xparms[2] = xpath; \
- if (length(info)) parms[4] = info; if (length(xinfo)) xparms[4] = xinfo; \
- if (length(maint)) parms[6] = maint; if (length(xmaint)) xparms[6] = xmaint; \
- if (length(cat)) parms[7] = cat; if (length(xcat)) xparms[7] = xcat; \
- if (length(bdeps)) parms[8] = bdeps; if (length(xbdeps)) xparms[8] = xbdeps; \
- if (length(rdeps)) parms[9] = rdeps; if (length(xrdeps)) xparms[9] = xrdeps; \
- if (length(www)) parms[10] = www; if (length(xwww)) xparms[10] = xwww; \
- } \
- fields["name"] = 1; names[1] = "Port"; \
- fields["path"] = 2; names[2] = "Path"; \
- fields["info"] = 4; names[4] = "Info"; \
- fields["maint"] = 6; names[6] = "Maint"; \
- fields["cat"] = 7; names[7] = "Index"; \
- fields["bdeps"] = 8; names[8] = "B-deps"; \
- fields["rdeps"] = 9; names[9] = "R-deps"; \
- fields["www"] = 10; names[10] = "WWW"; \
- split(display, d, /,[ \t]*/); \
- for (i in d) { \
- disp[fields[d[i]]] = 1; \
- } \
- } \
- { \
- if (substr($$2, 1, therelen) != there) \
- next; \
- for (i in parms) \
- if ((icase ? tolower($$i) : $$i) !~ parms[i]) \
- next; \
- for (i in xparms) \
- if ((icase ? tolower($$i) : $$i) ~ xparms[i]) \
- next; \
- found = 0; \
- for (i = 1; i < 11; i++) \
- if (i in disp) { \
- if (xkeylim && (icase ? tolower($$i) : $$i) ~ xkey) \
- next; \
- if (!found && keylim && (icase ? tolower($$i) : $$i) ~ key) \
- found = 1; \
- } \
- if (keylim && !found) \
- next; \
- for (i = 1; i < 11; i++) \
- if (i in disp) \
- printf("%s:\t%s\n", names[i], $$i); \
- print(""); \
- }' ${PORTSDIR}/${INDEXFILE}
+ -v disp="$${disp:-${PORTSEARCH_DISPLAY_FIELDS}}" \
+ -v xdisp="$${xdisp}" \
+ -v short="$${short:-${PORTSEARCH_DISPLAY_SHORT}}" \
+ -f ${PORTSDIR}/Tools/make_search ${PORTSDIR}/${INDEXFILE}
Index: Tools/make_search
===================================================================
RCS file: Tools/make_search
diff -N Tools/make_search
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Tools/make_search 23 Oct 2005 21:19:23 -0000
@@ -0,0 +1,184 @@
+# This script is the body of the "make search" mechanism. It is easier to
+# use it through that interface than by hand. It accepts number of parameters
+# which can be divided into two groups:
+# - query parameters are described in ports(7)
+# - internals are described here
+#
+# pwd lets this script know where it's called from. Calling make search
+# inside a category directory limits the search to ports in that category,
+# which is otherwise equivalent to make search cat=${PWD:#$PORTSDIR/}
+#
+# portsdir is the canonical ${PORTSDIR}.
+#
+# The input fields are assumed to match the ordering in ${INDEXFILE}.
+# Patterns found in the parameters are matched against their respective fields
+# in ${INDEXFILE}.
+#
+# $FreeBSD$
+#
+BEGIN {
+ if ( 0 == length(key) && 0 == length(xkey) \
+ && 0 == length(name) && 0 == length(xname) \
+ && 0 == length(path) && 0 == length(xpath) \
+ && 0 == length(info) && 0 == length(xinfo) \
+ && 0 == length(maint) && 0 == length(xmaint) \
+ && 0 == length(cat) && 0 == length(xcat) \
+ && 0 == length(fdeps) && 0 == length(xfdeps) \
+ && 0 == length(edeps) && 0 == length(xedeps) \
+ && 0 == length(pdeps) && 0 == length(xpdeps) \
+ && 0 == length(bdeps) && 0 == length(xbdeps) \
+ && 0 == length(rdeps) && 0 == length(xrdeps) \
+ && 0 == length(www) && 0 == length(xwww))
+ {
+ print "See ports(7) for a description of the search target.";
+ exit;
+ }
+ if (0 == length(pwd) || 0 == length(portsdir)) {
+ print "-v pwd=/path or -v portsdir=/path is missing"
+ exit;
+ }
+ "realpath " portsdir | getline realportsdir;
+ if (substr(pwd, 1, length(realportsdir)) == realportsdir) {
+ # this looks strange, but is valid concatenation
+ pwd = portsdir substr(pwd, 1 + length(realportsdir));
+ }
+ pwdlen = length(pwd);
+
+ # if keylim is false, we want to apply the key query to the full record.
+ # parms[0] will be matched against $0, which is good enough.
+ # same for xkeylim below.
+ # it keylim / xkeylim is set, we instead
+ keylen = length(key);
+ keylim = keylim && keylen;
+ if (!keylim && keylen) {
+ parms[0] = (icase ? tolower(key) : key);
+ }
+ xkeylen = length(xkey);
+ xkeylim = xkeylim && xkeylen;
+ if (!xkeylim && xkeylen) {
+ xparms[0] = (icase ? tolower(xkey) : xkey);
+ }
+ # call tolower() once to save time
+ if (length(name)) parms[1] = (icase ? tolower(name) : name);
+ if (length(xname)) xparms[1] = (icase ? tolower(xname) : xname);
+ if (length(path)) parms[2] = (icase ? tolower(path) : path);
+ if (length(xpath)) xparms[2] = (icase ? tolower(xpath) : xpath);
+ if (length(info)) parms[4] = (icase ? tolower(info) : info);
+ if (length(xinfo)) xparms[4] = (icase ? tolower(xinfo) : xinfo);
+ if (length(maint)) parms[6] = (icase ? tolower(maint) : maint);
+ if (length(xmaint)) xparms[6] = (icase ? tolower(xmaint) : xmaint);
+ if (length(cat)) parms[7] = (icase ? tolower(cat) : cat);
+ if (length(xcat)) xparms[7] = (icase ? tolower(xcat) : xcat);
+ if (length(bdeps)) parms[8] = (icase ? tolower(bdeps) : bdeps);
+ if (length(xbdeps)) xparms[8] = (icase ? tolower(xbdeps) : xbdeps);
+ if (length(rdeps)) parms[9] = (icase ? tolower(rdeps) : rdeps);
+ if (length(xrdeps)) xparms[9] = (icase ? tolower(xrdeps) : xrdeps);
+ if (length(www)) parms[10] = (icase ? tolower(www) : www);
+ if (length(xwww)) xparms[10] = (icase ? tolower(xwww) : xwww);
+ if (length(fdeps)) parms[11] = (icase ? tolower(fdeps) : fdeps);
+ if (length(xfdeps)) xparms[11] = (icase ? tolower(xfdeps) : xfdeps);
+ if (length(edeps)) parms[12] = (icase ? tolower(edeps) : edeps);
+ if (length(xedeps)) xparms[12] = (icase ? tolower(xedeps) : xedeps);
+ if (length(pdeps)) parms[13] = (icase ? tolower(pdeps) : pdeps);
+ if (length(xpdeps)) xparms[13] = (icase ? tolower(xpdeps) : xpdeps);
+ name2pos["name"] = 1; pos2desc[1] = "Port";
+ name2pos["path"] = 2; pos2desc[2] = "Path";
+ name2pos["info"] = 4; pos2desc[4] = "Info";
+ name2pos["maint"] = 6; pos2desc[6] = "Maint";
+ name2pos["cat"] = 7; pos2desc[7] = "Index";
+ name2pos["bdeps"] = 8; pos2desc[8] = "B-deps";
+ name2pos["rdeps"] = 9; pos2desc[9] = "R-deps";
+ name2pos["www"] = 10; pos2desc[10] = "WWW";
+ name2pos["fdeps"] = 11; pos2desc[11] = "F-deps";
+ name2pos["edeps"] = 12; pos2desc[12] = "E-deps";
+ name2pos["pdeps"] = 13; pos2desc[13] = "P-deps";
+
+ mandatory = 1;
+ optional = 2;
+ # find out which fields should be displayed
+ split(disp, d, /,[ \t]*/);
+ for (key in d) {
+ dfv = mandatory;
+ spec = d[key];
+ # if the field ends with "?", it will be displayed only when nonempty
+ if ("?" == substr(spec, length(spec))) {
+ spec = substr(spec, 1, length(spec) - 1);
+ dfv = optional;
+ }
+ if (spec in name2pos) {
+ fldpos = name2pos[spec];
+ display_fields[fldpos] = dfv;
+ }
+ }
+ # find out which fields should be removed from the display
+ split(xdisp, d, /,[ \t]*/);
+ for (key in d) {
+ if (d[key] in name2pos) {
+ fldpos = name2pos[d[key]];
+ delete display_fields[fldpos];
+ }
+ }
+}
+{
+ # skip ports from other categories
+ if (substr($2, 1, pwdlen) != pwd) {
+ next;
+ }
+ # lowercase the values if icase is true
+ for (i = 1; i <= NF; i++) {
+ maybe_lower[i] = (icase ? tolower($i) : $i);
+ }
+ # each foo and xfoo query term is matched against the respective input field
+ # parms and xparms are already tolower()ed when icase is true.
+ # if !keylim, key is matched against $0;
+ # if !xkeylim, xkey is matched against $0.
+ #
+ # skip lines that don't match their inclusive query strings
+ for (pos in parms) {
+ if (maybe_lower[pos] !~ parms[pos]) {
+ next;
+ }
+ }
+ # skip lines that match their exclusive query strings
+ for (pos in xparms) {
+ if (maybe_lower[pos] ~ xparms[pos]) {
+ next;
+ }
+ }
+ # if keylim or xkeylim is in effect they need to be satisfied now.
+ if (xkeylim) {
+ for (pos in display_fields) {
+ if (maybe_lower[pos] ~ xkey) {
+ next;
+ }
+ }
+ }
+ # try to match key against any of the displayed fields
+ if (keylim) {
+ found = 0;
+ for (pos in display_fields) {
+ if (maybe_lower[pos] ~ key) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ next;
+ }
+ }
+ # display
+ for (pos = 1; pos <= NF; pos++) {
+ if (pos in display_fields) {
+ # skip fields that are optional and empty
+ if (optional == display_fields[pos] && $pos ~ /^[[:space:]]*$/) {
+ continue;
+ }
+ printf("%s:\t%s\n", pos2desc[pos], $pos);
+ }
+ }
+ if (!short) {
+ print("");
+ }
+}
+
+# vim: ft=awk
Index: share/man/man7/ports.7
===================================================================
RCS file: /home/ncvs/src/share/man/man7/ports.7,v
retrieving revision 1.52
diff -u -r1.52 ports.7
--- share/man/man7/ports.7 20 Jul 2005 22:22:53 -0000 1.52
+++ share/man/man7/ports.7 23 Oct 2005 20:55:07 -0000
@@ -256,36 +256,117 @@
.It Cm search
Search the
.Pa INDEX
-file for the pattern specified by the
-.Va key
-(searches the port name, comment, and dependencies),
-.Va name
-(searches the port name only),
-.Va path
-(searches the port path),
-.Va info
-(searches the port info),
-.Va maint
-(searches the port maintainer),
-.Va cat
-(searches the port category),
-.Va bdeps
-(searches the port build-time dependency),
-.Va rdeps
-(searches the port run-time dependency)
+file for the pattern specified by the following parameters, listed along
+with port
.Xr make 1
-variables, and their exclusion counterparts:
+macros they match (they're treated as awk(1) regular expressions):
+.Pp
+.Bl -tag -width ".Va maint" -compact
+.It Va name
+.Va PKGNAME
+.It Va path
+absolute port directory path
+.It Va info
+.Va COMMENT
+.It Va maint
+.Va MAINTAINER
+.It Va cat
+.Va CATEGORY
+.It Va fdeps
+.Va FETCH_DEPENDS
+.It Va edeps
+.Va EXTRACT_DEPENDS
+.It Va pdeps
+.Va PATCH_DEPENDS
+.It Va bdeps
+.Va BUILD_DEPENDS
+.It Va rdeps
+.Va RUN_DEPENDS
+.It Va www
+.Va MASTER_SITES
+.It Va key
+any of the above, but see keylim, xkeylim below
+.El
+.Pp
+All of these have exclusion counterparts:
.Va xname , xkey
etc.
+.Pp
+.Va display
+(or
+.Va disp )
+names the fields to display,
+Any field name may be appended with a question mark, such fields are displayed
+only when they are not empty.
+Default:
+.Qq name,path,info,maint,cat,bdeps?,rdeps?,www,fdeps?,edeps?,pdeps? .
+.Pa /etc/make.conf
+variable:
+.Va PORTSEARCH_DISPLAY_FIELDS .
+.Pp
+Note that the order of fields in output follows the order in
+.Pa INDEX .
+This might be changed to use the order in
+.Va display
+in the future.
+.Pp
+.Va xdisplay
+(or
+.Va xdisp )
+names the
+fields to remove from the (default) list of fields.
+.Pp
+.Va keylim
+defines the scope of
+.Va key .
+Possible values: 0, 1.
+When 0,
+.Va key
+is matched against the whole record; when 1,
+.Va key
+is only matched against displayed fields.
+Default: 0.
+.Pa /etc/make.conf
+variable:
+.Va PORTSEARCH_KEYLIM .
+.Pp
+.Va xkeylim
+defines the scope of
+.Va xkey .
+Possible values: 0, 1.
+When 0,
+.Va xkey
+is matched against the whole record; when 1,
+.Va xkey
+is only matched against displayed fields.
+Default: 0.
+.Pa /etc/make.conf
+variable:
+.Va PORTSEARCH_XKEYLIM .
+.Pp
+.Va icase
+toggles case sensitivity.
+Possible values: 0, 1.
+Default: 1.
+.Pa /etc/make.conf
+variable:
+.Va PORTSEARCH_IGNORECASE .
+.Pp
+.Va short
+toggles the output of the record separator (empty line).
+Possible values: 0, 1.
+Default: 0.
+.Pa /etc/make.conf
+variable:
+.Va PORTSEARCH_DISPLAY_SHORT .
+.Pp
For example, one would type:
.Pp
.Dl "cd /usr/ports && make search name=query"
.Pp
to find all ports whose
-name matches
+names match
.Dq Li query .
-Results include the matching ports' path, comment, maintainer,
-build dependencies, and run dependencies.
.Bd -literal -offset indent
cd /usr/ports && make search name=pear- \e
xbdeps=apache
@@ -308,7 +389,7 @@
or
.Dq Li http .
.Bd -literal -offset indent
-make search key=apache display=name,path,info keylim=1
+make search key=apache disp=name,path,info keylim=1
.Ed
.Pp
To find ports that contain
More information about the freebsd-ports
mailing list