From owner-freebsd-ports@FreeBSD.ORG Sun Oct 23 22:20:07 2005 Return-Path: X-Original-To: freebsd-ports@freebsd.org Delivered-To: freebsd-ports@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 5059D16A41F for ; Sun, 23 Oct 2005 22:20:07 +0000 (GMT) (envelope-from neuhauser@sigpipe.cz) Received: from isis.sigpipe.cz (fw.sigpipe.cz [62.245.70.224]) by mx1.FreeBSD.org (Postfix) with ESMTP id 56A1143D46 for ; Sun, 23 Oct 2005 22:20:06 +0000 (GMT) (envelope-from neuhauser@sigpipe.cz) Received: by isis.sigpipe.cz (Postfix, from userid 1001) id 535CA1F87BFD; Mon, 24 Oct 2005 00:20:05 +0200 (CEST) Date: Mon, 24 Oct 2005 00:20:05 +0200 From: Roman Neuhauser To: freebsd-ports Message-ID: <20051023222005.GA1504@isis.sigpipe.cz> Mail-Followup-To: freebsd-ports Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="OXfL5xGRrasGEqWY" Content-Disposition: inline User-Agent: Mutt/1.5.9i Subject: [RFC] make search extensions X-BeenThere: freebsd-ports@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting software to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 23 Oct 2005 22:20:07 -0000 --OXfL5xGRrasGEqWY Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 --OXfL5xGRrasGEqWY Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="make_search,0.patch" 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 --OXfL5xGRrasGEqWY--