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