#
#	aegis - project change supervisor
#	Copyright (C) 2004 Peter Miller;
#	All rights reserved.
#
#	As a specific exception to the GPL, you are allowed to copy
#	this source file into your own project and modify it, without
#	releasing your project under the GPL, unless there is some other
#	file or condition which would require it.
#
# MANIFEST: shell script to commit changes to Subversion
#
# This script is expected to be run by the integrate_pass_notify_command
# and as such the baseline has already assumed the shape asked for by
# the change.
#
#	integrate_pass_notify_command =
#    	    "$bin/ae-svn-ci $project $change http://svn.site.com/svn/trunk --username svn_user";
#
# Alternatively, you may wish to tailor this script to the individual
# needs of your project.  Make it a source file, e.g. "etc/ae-svn-ci.sh"
# and then use the following:
#
#	integrate_pass_notify_command =
#    	    "$sh ${s etc/ae-svn-ci} $project $change http://svn.site.com/svn/trunk --username svn_user";
#

USAGE="Usage: $0 [-hnq] <project> <change> <url> [<co_options>]"

PRINT="echo"
EXECUTE="eval"

while getopts "hnq" FLAG
do
    case ${FLAG} in
    h )
        echo "${USAGE}"
        exit 0
        ;;
    n )
        EXECUTE=":"
        ;;
    q )
        PRINT=":"
        ;;
    * )
        echo "$0: unknown option ${FLAG}" >&2
        exit 1
        ;;
    esac
done

shift `expr ${OPTIND} - 1`

case $# in
[012])
    echo "${USAGE}" 1>&2
    exit 1
    ;;
*)
    project=$1
    change=$2
    svn_url=$3
    shift 3
    svn_co_flags=$*
    ;;
esac

here=`pwd`

AEGIS_PROJECT=$project
export AEGIS_PROJECT
AEGIS_CHANGE=$change
export AEGIS_CHANGE

module=`echo $project | sed 's|[.].*||'`

baseline=`aegis -cd -bl`

if test X${TMPDIR} = X; then TMPDIR=/var/tmp; fi

TMP=${TMPDIR}/ae-svn-ci.$$
mkdir ${TMP}
cd ${TMP}

PWD=`pwd`
if test X${PWD} != X${TMP}; then
    echo "$0: ended up in ${PWD}, not ${TMP}" >&2
    exit 1
fi

fail()
{
    set +x
    cd $here
    rm -rf ${TMP}
    echo "FAILED" 1>&2
    exit 1
}
trap "fail" 1 2 3 15

Command()
{
    ${PRINT} "$*"
    ${EXECUTE} "$*"
}

#
# Create a new Subversion work area.
#
# Note: this assumes the module is checked-out into a directory of the
# same name.  Is there a way to ask Subversion where it is going to put a
# module, so we can always get the "cd" right?
#
${PRINT} svn co $svn_url $module $svn_co_flags
${EXECUTE} svn co $svn_url $module $svn_co_flags > LOG 2>&1
if test $? -ne 0; then cat LOG; fail; fi
${EXECUTE} cd $module

#
# Now we need to extract the sources from Aegis and drop them into the
# Subversion work area.  There are two ways to do this.
#
# The first way is to use the generated tarball.
# This has the advantage that it has the Makefile.in file in it, and
# will work immediately.
#
# The second way is to use aetar, which will give exact sources, and
# omit all derived files.  This will *not* include the Makefile.in,
# and so will not be readily compilable.
#
# gunzip < $baseline/export/${project}.tar.gz | tardy -rp ${project} | tar xf -
aetar -send -comp-alg=gzip -o - | tar xzf -

#
# If any new directories have been created we will need to add them
# to Subversion before we can add the new files which we know are in them,
# or they would not have been created.  Do this only if the -n option
# isn't used, because if it is, we won't have actually checked out the
# source and we'd erroneously report that all of them need to be added.
#
if test "X${EXECUTE}" != "X:"
then
    find . -name .svn -prune -o -type d -print |
    xargs --max-args=1 |
    while read dir
    do
        if [ ! -d "$dir/.svn" ]
        then
            Command svn add -N "$dir"
        fi
    done
fi

#
# Use the Aegis meta-data to perform some commands that Subversion can't
# figure out for itself.  We use an inline "aer" report script to identify
# when a remove-create pair are actually due to a move.
#
aegis -rpt -nph -f - <<_EOF_ |
auto cs;
cs = project[project_name()].state.branch.change[change_number()];

columns({width = 1000;});

auto file, moved;
for (file in cs.src)
{
    if (file.move != "")
        moved[file.move] = 1;
}

auto action;
for (file in cs.src)
{
    if (file.action == "remove" && file.move != "")
        action = "move";
    else
        action = file.action;
    /*
     * Suppress printing of any files created as the result of a move.
     * These are printed as the destination when printing the line for
     * the file that was *removed* as a result of the move.
     */
    if (action != "create" || ! moved[file.file_name])
        print(sprintf("%s %s \\"%s\\" \\"%s\\"", file.usage, action, file.file_name, file.move));
}
_EOF_
while read line
do
    eval set -- "$line"
    usage="$1"
    action="$2"
    srcfile="$3"
    dstfile="$4"
    case $action in
    create)
        Command svn add $srcfile
        ;;
    remove)
        Command rm -f $srcfile
        Command svn remove $srcfile
        ;;
    move)
        Command mv $dstfile $dstfile.move
        Command svn move $srcfile $dstfile
        Command cp $dstfile.move $dstfile
        Command rm -f $dstfile.move
        ;;
    *)
        ;;
    esac
done

#
# Extract the brief description.  We'd like to do this using aesub
# or something, like so:
#
#      message=`aesub '${version} - ${change description}'`
#
# but the expansion of ${change description} has a lame hard-coded max of
# 80 characters, so we have to do this by hand.  (This has the slight
# benefit of preserving backslashes in front of any double-quotes in
# the text; that will have to be handled if we go back to using aesub.)
#
description=`aegis -ca -l | sed -n 's/brief_description = "\(.*\)";$/\1/p'`
version=`aesub '${version}'`
message="$version - $description"

#
# Now commit all the changes.
#
Command svn commit -m \"$message\"

#
# All done.  Clean up and go home.
#
cd $here
rm -rf ${TMP}
exit 0