Ever wanted to search the whole subversion repository?

Did you ever remember that you coded something exactly the way you need it now but don’t know the project name anymore? – Was it this one? (check out project, click through the files) No… wait, perhaps this one? (check out project, click through the files) No… *sigh*

At least for Subversion users the following script is a solution – you can narrow your search by regex concerning file path and content, but then search in all projects of the whole repository. Have fun with it!

#!/bin/sh
#
# svn-grep.sh <CONTENT_SEARCH_EXPRESSION> [<PATH_SEARCH_EXPRESSION>]
# - both arguments are regular expressions for egrep
# - the second argument is optional
# - branches and tags excluded, only searches in trunk
#
# example: ./svn-grep.sh "sun\.misc\.Unsafe" "\.java\$"
#

if [ "x$1" == "x" ]; then
echo "no content search expression - cancelled"
exit 1
fi

# local access is much faster, so use it if you can:
BASEURL="file:///opt/svn-repo/projects"
#BASEURL="https://svn.mydomain.com/projects"

SEARCH=$1
NAMEEXCLUDE="\(/tags/\|/branches/\|/\$\)"
NAMESEARCH='.'

if [ "x$2" != "x" ]; then
NAMESEARCH="$2"
fi

echo ""
echo "starting a search in $BASEURL for $SEARCH in files with a path like $NAMESEARCH"
echo ""
echo "step 1/2: collecting all paths to be considered (can take some time)..."
TEMPFILE=$(mktemp /tmp/svn-grep.XXXXXXXXXX)
svn ls -R "$BASEURL" | grep -v -e "$NAMEEXCLUDE" | grep -e "$NAMESEARCH" >$TEMPFILE &
SVN_LS_PID=$!
while ps -p $SVN_LS_PID >/dev/null; do
sleep 1
TEMPFILE_LINES=$(cat $TEMPFILE | wc -l)
echo -ne "\r [ found $TEMPFILE_LINES candidates ] "
done
TEMPFILE_LINES=$(cat $TEMPFILE | wc -l)
echo -e "\rstep 1/2 finished, found $TEMPFILE_LINES candidates"
echo ""

echo "step 2/2: search through the contents of all candidates"
echo "-----------------------------------------"
i=0

cat $TEMPFILE | while read file;
do
result=$(svn cat "$BASEURL/$file" | grep -e $SEARCH)
i=$(($i+1))
if [ -n "$result" ]; then
echo -e "\r$file"
else
percent=$(bc <<<"scale=1; 100*$i/$TEMPFILE_LINES")
if [ $(($i%50)) == 0 ]; then
echo -ne "\r [ ${percent} % ] "
fi
fi
done

echo -e "\r-----------------------------------------"
echo "step 2/2 finished"

rm $TEMPFILE