aboutsummaryrefslogtreecommitdiff
path: root/sbosearch
diff options
context:
space:
mode:
Diffstat (limited to 'sbosearch')
-rwxr-xr-xsbosearch516
1 files changed, 516 insertions, 0 deletions
diff --git a/sbosearch b/sbosearch
new file mode 100755
index 0000000..e4b48d9
--- /dev/null
+++ b/sbosearch
@@ -0,0 +1,516 @@
+#!/bin/bash
+
+# This really is a bash script, uses bashisms, don't change the shebang.
+
+DFLTBROWSER=xdg-open
+
+SLACKVER=${SLACKVER:-$( cut -d' ' -f2 /etc/slackware-version )}
+SLACKVER=${SLACKVER:-14.1}
+
+SBOROOT=${SBOROOT:-/var/lib/sbopkg/SBo/$SLACKVER}
+[ ! -d "$SBOROOT" ] && SBOROOT=.
+
+SELF=$( echo $0 | sed 's,.*/,,' )
+
+usage() {
+ cat <<EOF
+$SELF: search local slackbuilds.org repository
+
+Usage: $SELF [-a] [-v] [-I] [-R] [-B] [-H] [-r required] [-e email]
+ [-m maintainer] [-k keyword] [-c category] [build] [...]
+ $SELF --all
+ $SELF --help
+
+Find all SlackBuilds in the local repository matching the given
+criteria. If multiple search options are given, they are ANDed together
+by default.
+
+Options:
+
+Options may not be bundled (use "-a -v", not "-av"), and the spacing
+shown is required (use "-r foo", not "-rfoo").
+
+Search options:
+[build] Match builds by name.
+-r required Matches builds with <required> in the REQUIRES= field (only
+ exists in repo versions 14.0 and up).
+-e email Match email address.
+-m maintainer Match MAINTAINER= (real name, not email).
+-h homepage Match HOMEPAGE.
+-d readmetxt Match text in documentation (the README).
+-c category Match builds in <category>. Category names may be abbreviated,
+ e.g. "sys" for system, "ga" for games.
+-k keyword Keyword search (TAGS.txt, includes build names, only exists
+ in repo versions 14.1 and up).
+
+Search modifier options:
+--all List all builds. Any search options will be ignored.
+-a AND all the search options together (default is OR).
+-v Invert the search (find builds not matching the criteria).
+-i Search for installed packages only.
+-u Search for uninstalled packages only.
+-x Exact match (for build names only, not -r -e -m -h -d)
+
+Output options:
+-S Print short names (no category, "zdoom" not "games/zdoom").
+-P Print full paths to tarballs.
+-X Extract tarballs into current dir.
+-I cat .info files for all builds found.
+-R cat README files for all builds found.
+-B Open SBo repo page in browser, for each build found.
+-H Open HOMEPAGE in browser, for each build found.
+-C Check installed status (print "installed" or "NOT installed"
+ for each build found).
+
+The local repo must be in the current directory, or in the
+directory given by the SBOROOT environment variable, which defaults to
+/var/lib/sbopkg/SBo/\$SLACKVER. If SLACKVER is not set in the environment,
+its value will be extracted from /etc/slackware-version (or set to
+14.1, if this file doesn't exist).
+
+All search arguments are treated as case-insensitive regular expressions.
+Required, email, maintainer, and homepage arguments are unanchored,
+and can't be anchored with ^ or $. However, you can use \< and \> to
+anchor on word boundaries (e.g. "-e \<bob@" will match bob@example.com,
+but not silentbob@example.com).
+
+Build names are anchored on the left, so searching for 'z' will find all
+the build names that begin with 'z'. If you want to find all the build
+names containing a 'z', use '.*z' instead. You can search for all build
+names ending with 'z' by using '.*z\>' (actually this will also find
+things like compiz-bcop, which have a z at a word boundary).
+
+Search options can be given more than once, e.g. "-r foo -r bar" means
+find builds that require either foo or bar (or, with -a, builds that
+require both foo and bar).
+
+The -B and -H options use the environment variable BROWSER to set
+which browser to use. If BROWSER is not set, "$DFLTBROWSER" is used. Be
+careful with these: trying to open several hundred (or several thousand)
+browser instances will likely eat your machine for breakfast, especially
+if firefox is the default browser. Best to run the search without -B or
+-H first, to see how many matches you get.
+EOF
+}
+
+die() {
+ if [ -n "$TMPDIR" -a -d "$TMPDIR" ]; then
+ rm -rf $TMPDIR
+ fi
+ echo "$SELF: $@ (try '$SELF --help')" 1>&2
+ exit 1
+}
+
+info() {
+ echo "$SELF: info: $@" 1>&2
+}
+
+warn() {
+ echo "$SELF: warning: $@" 1>&2
+}
+
+set_input() {
+ if [ "$mode" = "or" ]; then
+ INPUT=$ALL
+ else
+ INPUT=$RESULTS
+ fi
+ : > $OUTPUT
+}
+
+set_output() {
+ if [ "$mode" = "or" ]; then
+ cat $OUTPUT >> $RESULTS
+ else
+ mv $OUTPUT $RESULTS
+ fi
+}
+
+info_search() {
+ set_input
+ egrep -i -l "^$1=.*$2" $( cat $INPUT ) > $OUTPUT
+ set_output
+}
+
+# keyword search is complicated by the fact that TAGS.txt doesn't
+# store the category. Also, we don't differentiate between the keywords
+# and the build name at the start of the line.
+keyword_search() {
+ local pkg
+
+ if [ ! -e $SBOROOT/TAGS.txt ]; then
+ cat <<EOF 1>&2
+$SELF: $SBOROOT/TAGS.txt not found.
+
+Note that this file only exists for Slackware versions 14.1 and up. We
+seem to be searching version $SLACKVER.
+
+EOF
+ die "can't do keyword search"
+ fi
+
+ set_input
+ egrep -i "$1" $SBOROOT/TAGS.txt | while read line; do
+ pkg=$( echo "$line" | cut -d: -f1 )
+ egrep "/$pkg\.info\$" $INPUT >> $OUTPUT
+ done
+ set_output
+}
+
+category_search() {
+ local categ
+ set_input
+ categ=$( cut -d/ -f1 $ALL | sort -u | egrep -i "$1" | head -1 )
+ [ -z "$categ" ] && die "fatal: no such category '$1'"
+ egrep -i "^$categ/" $INPUT > $OUTPUT
+ set_output
+}
+
+build_search() {
+ set_input
+ if [ "$exact" == "1" ]; then
+ fgrep "$1/$1.info" $INPUT > $OUTPUT
+ else
+ egrep -i "/$1[^/]*\.info\$" $INPUT > $OUTPUT
+ fi
+ set_output
+}
+
+readme_search() {
+ local info readme
+
+ set_input
+ for info in $( cat $INPUT ); do
+ readme=$( echo $info | sed 's,/[^/]*$,/README,' )
+ egrep -q -i "$1" $readme && echo $info >> $OUTPUT
+ done
+ set_output
+}
+
+is_installed() {
+ [ ! -e /var/log/packages/ ] && die "no /var/log/packages, are you sure this is Slackware?"
+ local pkg="$( echo $1 | cut -d/ -f2 )"
+ [ ! -e $TMPDIR/installed_pkgs ] && \
+ ls /var/log/packages/ | rev | cut -d- -f4- | rev > $TMPDIR/installed_pkgs
+ fgrep -q -x $pkg $TMPDIR/installed_pkgs
+ return $?
+}
+
+# works, but slow:
+## is_installed() {
+## local pkg candidate olddir found=1
+##
+## found=1
+## pkg="$( echo $1 | cut -d/ -f2 )"
+## olddir="$( pwd )"
+## cd /var/log/packages || die "no /var/log/packages, are you sure this is Slackware?"
+##
+## for candidate in "$( ls $pkg* 2>/dev/null )"; do
+## if [ "$pkg" = "$( echo $candidate | rev | cut -d- -f4- | rev )" ]; then
+## found=0
+## fi
+## done
+##
+## cd $olddir
+## return $found
+## }
+
+# also slow
+## is_installed() {
+## local pkg
+##
+## if [ ! -e $TMPDIR/installed_pkgs ]; then
+## ls /var/log/packages/ > $TMPDIR/installed_pkgs || \
+## die "no /var/log/packages, are you sure this is Slackware?"
+## fi
+##
+## pkg="$( echo $1 | cut -d/ -f2 )"
+## egrep -q "^$pkg"'-[^-]+-[^-]+-[^-]+$' $TMPDIR/installed_pkgs
+## return $?
+## }
+##
+## installed_search_backend() {
+## local pkg
+## set_input
+## for pkg in $( cat $INPUT ); do
+## eval is_installed $pkg $2 echo $pkg >> $OUTPUT
+## done
+## set_output
+## }
+##
+## installed_search() {
+## installed_search_backend "$1" "&&"
+## }
+##
+## uninstalled_search() {
+## installed_search_backend "$1" "||"
+## }
+
+# almost works, fast, might try to fix someday
+## installed_search() {
+## set_input
+## ls /var/log/packages/ | rev | cut -d- -f4- | rev > $TMPDIR/installed_pkgs || \
+## die "no /var/log/packages, are you sure this is Slackware?"
+## sort -t / -k 2 $INPUT > $INPUT.tmp
+## join -t / -1 2 -o 1.1,1.2 $INPUT.tmp $TMPDIR/installed_pkgs > $OUTPUT
+## exit 0
+## set_output
+## }
+
+# works, slow, but not as slow as the 1st try
+## installed_search() {
+## local -A packages
+## local pkg shortpkg
+##
+## [ ! -e /var/log/packages/ ] && die "no /var/log/packages, are you sure this is Slackware?"
+##
+## set_input
+## echo "got here 1"
+## for pkg in $( cat $INPUT ); do
+## echo -n "." 1>&2
+## shortpkg=$( expr "$pkg" : '.*/\([^/]*\)/' )
+## #shortpkg=$( echo $pkg | cut -d/ -f2 )
+## packages[$shortpkg]=$pkg
+## done
+## echo "got here 2"
+## ls /var/log/packages/ | rev | cut -d- -f4- | rev | while read pkg; do
+## [ -n "${packages[$pkg]}" ] && echo ${packages[$pkg]} >> $OUTPUT
+## done
+## echo "got here 3"
+## set_output
+## }
+
+# lightning fast and works correctly, compared to the commented-out
+# attempts above.
+installed_search_backend() {
+ local pkg grepopt="$1"
+
+ [ ! -e /var/log/packages/ ] && die "no /var/log/packages, are you sure this is Slackware?"
+
+ set_input
+ cut -d/ -f2 $INPUT > $INPUT.shortnames
+
+ # $INPUT.shortnames.found is foo => /foo.info
+ # fgrep -x means "match entire line only", used to avoid matching e.g.
+ # zathura when looking for zathura-cb. It's *much* faster than using
+ # egrep with ^ and $.
+ ls /var/log/packages/ | rev | cut -d- -f4- | rev | \
+ fgrep -x -f $INPUT.shortnames | \
+ sed 's,.*,/&.info,' \
+ > $INPUT.shortnames.found
+
+ fgrep $grepopt -f $INPUT.shortnames.found $INPUT > $OUTPUT
+ set_output
+}
+
+installed_search() {
+ installed_search_backend ""
+}
+
+uninstalled_search() {
+ installed_search_backend "-v"
+}
+
+invert_results() {
+ fgrep -v -f $RESULTS $ALL > $OUTPUT
+ mv $OUTPUT $RESULTS
+}
+
+open_in_browser() {
+ BROWSER="${BROWSER:-$DFLTBROWSER}"
+ info "opening URL '$1' with browser '$BROWSER'"
+ $BROWSER "$1"
+}
+
+print_results() {
+ if [ "$simpleoutput" = "1" ]; then
+ cat $OUTPUT
+ return
+ fi
+
+ # N.B. don't use 'cat $OUTPUT | while read line' here, console browsers
+ # don't like having their stdin redirected (especially not links)
+ for line in $( cat $OUTPUT ) ; do
+ # -X option
+ if [ "$extract" = "1" ]; then
+ tar -C $OLD_PWD -xvf $SBOROOT/$line.tar.gz
+ fi
+
+ # -P option
+ if [ "$printpaths" = "1" ]; then
+ echo -n $SBOROOT/$line.tar.gz
+ else
+ # -S option
+ if [ "$shortoutput" = "1" ]; then
+ echo -n $( echo $line | cut -d/ -f2 )
+ else
+ echo -n $line
+ fi
+ fi
+
+ # -C option
+ if [ "$checkinstalled" = "1" ]; then
+ is_installed $line && echo ": installed" || echo ": NOT installed"
+ else
+ echo
+ fi
+
+ # -R option
+ if [ -n "$readmefiles" ]; then
+ echo '==>' $line/README
+ cat $line/README
+ echo
+ fi
+
+ # -I option
+ if [ -n "$infofiles" ]; then
+ echo '==>' $line/*.info
+ cat $line/*.info
+ echo
+ fi
+
+ # -H option
+ if [ -n "$hpbrowser" ]; then
+ ( source $line/*.info ; open_in_browser "$HOMEPAGE" )
+ fi
+
+ # -B option
+ if [ -n "$browser" ]; then
+ open_in_browser "http://slackbuilds.org/repository/$SLACKVER/$line/"
+ fi
+ done
+}
+
+# main()
+
+mode="or"
+simpleoutput=1
+
+if [ "$*" == "" ]; then
+ set -- --help
+fi
+
+while [ -n "$1" ]; do
+ arg="$1"
+ shift
+ case "$arg" in
+ "--help") usage ; exit 0 ;;
+ "--all") showall=1 ;;
+ "-a") mode="and" ;;
+ "-r") required="$required $1" ; shift ;;
+ "-e") email="$email $1" ; shift ;;
+ "-m") maintainer="$maintainer $1" ; shift ;;
+ "-h") homepage="$homepage $1" ; shift ;;
+ "-k") keyword="$keyword $1" ; shift ;;
+ "-c") category="$category $1" ; shift ;;
+ "-d") readme="$readme $1" ; shift ;;
+ "-v") invert=1 ;;
+ "-R") readmefiles=1 ; simpleoutput=0 ;;
+ "-I") infofiles=1 ; simpleoutput=0 ;;
+ "-B") browser=1 ; simpleoutput=0 ;;
+ "-H") hpbrowser=1 ; simpleoutput=0 ;;
+ "-S") shortoutput=1 ; simpleoutput=0 ;;
+ "-P") printpaths=1 ; simpleoutput=0 ;;
+ "-X") extract=1 ; simpleoutput=0 ;;
+ "-C") checkinstalled=1 ; simpleoutput=0 ;;
+ "-i") installedonly=1 ;;
+ "-u") uninstalledonly=1 ;;
+ "-x") exact=1 ;;
+ -*) die "unknown option '$arg'" ;;
+ *) build="$build $arg" ;;
+ esac
+done
+
+if [ "$installedonly" = "1" -a "$uninstalledonly" = "1" ]; then
+ die "-i and -u don't make sense to use together"
+fi
+
+TMPDIR=${TMP:-/tmp}/sbosearch.$$.$RANDOM
+rm -rf $TMPDIR
+mkdir -p $TMPDIR
+
+ALL=$TMPDIR/allinfos
+OUTPUT=$TMPDIR/output
+RESULTS=$TMPDIR/results
+
+OLD_PWD=$( pwd )
+cd $SBOROOT || die "set SBOROOT or cd to the SBo/<version>/ directory."
+
+# Unfortunately ChangeLog.txt is the only file that's present in the SBo
+# tree for every Slack version.
+if [ ! -e ChangeLog.txt ]; then
+ warn "can't find ChangeLog.txt in $SBOROOT, are you sure this is a valid repo?"
+fi
+
+/bin/ls */*/*.info > $ALL
+[ "$showall" = "1" ] && mode="and"
+
+# Init results.
+# in 'and' mode, each search is done in the results of the previous
+# search. The first search starts with the full list, so the results
+# of the 'previous' (nonexistent) search must be the full list.
+# in 'or' mode, every search is done against the full list, and the
+# results are built up by appending (so the result starts out empty).
+if [ "$mode" = "and" ]; then
+ cp $ALL $RESULTS
+else
+ touch $RESULTS
+fi
+
+# Do the searches.
+# Thought about parametrizing these, so there could be a loop such as
+# for i in REQUIRES EMAIL MAINTAINER HOMEPAGE; do info_search $i; done
+# ...but it would lead to fugly bash code that I wouldn't care to debug
+# a year from now.
+
+if [ "$showall" != "1" ]; then
+ [ -n "$required" ] && for term in $required; do
+ info_search REQUIRES $term
+ done
+
+ [ -n "$email" ] && for term in $email; do
+ info_search EMAIL $term
+ done
+
+ [ -n "$maintainer" ] && for term in $maintainer; do
+ info_search MAINTAINER $term
+ done
+
+ [ -n "$homepage" ] && for term in $homepage; do
+ info_search HOMEPAGE $term
+ done
+
+ [ -n "$keyword" ] && for term in $keyword; do
+ keyword_search $term
+ done
+
+ [ -n "$category" ] && for term in $category; do
+ category_search $term
+ done
+
+ [ -n "$build" ] && for term in $build; do
+ build_search $term
+ done
+
+ [ -n "$readme" ] && for term in $readme; do
+ readme_search $term
+ done
+
+ [ -n "$installedonly" ] && installed_search
+
+ [ -n "$uninstalledonly" ] && uninstalled_search
+
+ [ -n "$invert" ] && invert_results
+fi
+
+# done with all the searches, pretty up the output.
+if [ "$shortoutput" = "1" ]; then
+ sortopts="-t / -k 2"
+fi
+
+sort -u $sortopts $RESULTS | cut -d/ -f1-2 > $OUTPUT
+
+print_results
+
+rm -rf $TMPDIR
+exit 0