#!/bin/sh
#
# svn-to-svn - Subversion dump on stdin to dump on stdout
#
# With the -c option, build the repo and check it out to a working
# copy.  The name of the working copy is the repo name suffixed with
# '-checkout'.
#
# With the -d option, expect the repo to exist, undump the repo to
# a Subversion dump file; then do not delete the repo.
#
# With the -e option, edit a Subversion dumpfile and rebuild it, fixing
# the checksum headers.
#
# With the -g option, make a Git repo from the Subversion dump and view
# it in gitk
#
# Any -l option argument will be used to set reposurgeon's log option.
#
# With the -n option, create a repo corresponding to the input stream;
# do not stream the result to stdout and do not delete the repo.
#
# With the -o option, expect the repo to exist, pick it up with
# reposurgeon, and throw the result to stdout as an import stream;
# then do not delete the repo.
#
# With the -q option. suppress progress messages from svnadmin load
# and checkout.
#
# With the -r option, limit the number of Subversion revisions processed
# from the input dump; the specified argument is the humber of the last
# revision emitted.
#
# The -s option strips out generated time-varying headers - the UUID and
# the timestamp in revision zero.  This is necessary for file comparisons 
# in regression tests.
#
# The -t option allows property extensions to be generated.  It's turned
# off by default because git-import chokes on it.
#
# If an argument is specified after the options, it is used as the repository
# directory name; otherwise 'test-repo' is used.
#
# To add complexity to a test load, do -n, then edit the test repo with
# Subversion, then use -d. Note: you must commit to force the repo to
# be up to date before streaming it. Also note that any embedded comments
# will be lost.
#
# The REPOSURGEON environment variable can be used to substitute in a
# different implementation.
#
# The TESTOPT variable can be used to pass an early command or option setting
# to reposurgeon.
#

# shellcheck disable=SC1091
command -v realpath >/dev/null 2>&1 ||
    realpath() { test -z "${1%%/*}" && echo "$1" || echo "$PWD/${1#./}"; }

# Boilerplate ends 

PATH=$PATH:./..

build=T
view=F
edit=F
stream=F
cleanup=T
strip=F
co=F
log=""
quiet=""
limit=""
# Suppress legacy emission by default
streamopts='prefer git'

# Built-in echo insidiously expands backslash escapes.  This is a problem
# when stripping... 
ECHO=/bin/echo

while getopts cdegl:noqr:st opt
do
    case $opt in
        e) build=F; view=F; edit=T; stream=F; dump=F; cleanup=T; strip=F; co=F;;
	c) build=T; view=F; edit=F; stream=F; dump=F; cleanup=F; strip=F; co=T;;
	n) build=T; view=F; edit=F; stream=F; dump=F; cleanup=F; strip=F; co=F;;
        g) build=F; view=T; edit=F; stream=F; dump=F; cleanup=F; strip=F; co=F;;
        o) build=F; view=F; edit=F; stream=T; dump=F; cleanup=F; strip=F; co=F;;
        d) build=F; view=F; edit=F; stream=F; dump=T; cleanup=F; strip=F; co=F;;
        s) build=F; view=F; edit=F; stream=F; dump=F; cleanup=F; strip=T; co=F;;
	t) streamopts="" ;;
	q) quiet=-q ;;
	r) limit="$OPTARG" ;;
	l) log="log $OPTARG" ;;
	*) echo "$0: unknown flag $opt" >&2; exit 1;;
    esac
done
# shellcheck disable=SC2004
shift $(($OPTIND - 1))

tmpdir=${TMPDIR:-/tmp}

# This lets us set the repo location 
# shellcheck disable=SC2006,2046,2086
testrepo=`realpath \`dirname ${1:-test-repo$$}\``/`basename ${1:-test-repo$$}`

# Should we strip time-varying headers out of the input dump file?
if [ $strip = T ]
then
    seen_uuid=F
    seen_date=F
    while IFS= read -r line
    do
	case $line in
	    [0-9]*)
		if [ $seen_date = T ]; then $ECHO "$line"; fi ;  
		seen_date=T ;;
	    UUID*)  
		if [ $seen_uuid = T ]; then $ECHO "$line"; fi ; 
		seen_uuid=T ;;
	    *) $ECHO "$line" ;;
	esac
    done
fi

# Was there a limit option?
if [ -z "$limit" ]
then
    source=/dev/stdin
else
    source="${tmpdir}/svn-to-svn-$$"
    ../repocutter -r "0:${limit}" select >"${source}"
fi

# Should we build a repo from a dump presented on standard input?
if [ $build = T ]
then
    rm -fr "$testrepo" "$testrepo-checkout"
    svnadmin create "$testrepo"
    # shellcheck disable=2086
    if svnadmin load ${quiet} "$testrepo" <"$source"
    then
	:
    else
	exit 1
    fi
fi

if [ "$co" = T ]
then
    # shellcheck disable=2086
    svn co ${quiet} "file://$testrepo" "${testrepo}-checkout" >/dev/null
fi

# Should we edit the streamfile?
if [ "$edit" = T ]
then
    dump=$1
    if [ -z "$dump" ]
    then
	echo "svn-to-svn: a file argument is required" >&2
	exit 1
    elif "$EDITOR" "$1"
    then
	rm -fr "$testrepo" test-checkout
	svnadmin create "$testrepo"
	sed  <"$dump" \
	    -e '/Text-content-md5: /d' -e '/Text-content-sha1: /d' \
	    -e '/Text-copy-source-md5: /d' -e '/Text-copy-source-sha1: /d' \
	    | svnadmin load "$testrepo" >/dev/null
	svnadmin dump "$testrepo" >"$dump"
    fi
fi

# Should we view the repo?
if [ "$view" = T ]
then
    (cd "$testrepo" >/dev/null || (echo "$0: cd failed" >&2; exit 1); ${REPOSURGEON:-reposurgeon} "${log}" "${TESTOPT}" "read ." "prefer git" "rebuild ${tmpdir}/testrepo$$"; cd "${tmpdir}/testrepo$$" 2>/dev/null || (echo "$0: cd failed"; exit 1); gitk --all --tags)
fi

# Should we dump a conversion of the repo as a fast-import stream?
if [ "$stream" = T ]
then
    ${REPOSURGEON:-reposurgeon} "${log}" "${TESTOPT}" "read $testrepo" "$streamopts" "write"
fi

# Should we dump the repo as a Subversion stream?
if [ "$dump" = T ]
then
    svnadmin dump "$testrepo"
fi

# Should we clean up the test directory
if [ "$cleanup" = T ]
then
    rm -fr "$testrepo" test-checkout
fi
