#!/bin/bash
# $Id: autobuild,v 1.125 2005/10/05 15:32:28 wedgingt Exp $ @email.arc.nasa.gov
#
# Automatically build most/all variants of the EUROPA planner system.
#   See just below (or run with '-h') for (minimal) usage information.

echo ''
echo 'EUROPA autobuild script'
echo ''

coverage=false
performance=false
if test ! -z "$1"
then
    case "$1" in
	-c|--coverage)
	    coverage=true;
	    shift
	    ;;
        -p|--performance)
            performance=true
            shift
            ;;
        -h|-H|'-?'|--help|--Help|--HELP)
            echo "$0"': Usage: '"`basename $0`"' [-chm] [email@address.domain]'
	    echo '    -c, --coverage: build the COVERAGE variant (which is not fully supported yet)'
            echo '    -h, -H, --help: help (print this message and exit)'
            echo '    -p, --performance: run the performance tests via the run-performance-tests jam target'
            echo '        (only with VARIANTS=OPTIMIZED and VARIANTS=PROFILE)'
            echo '    Any other option (with a leading dash: "-") evokes an error.'
            echo '  Any other single argument should be an email address for status messages;'
            echo '    it defaults to "$USER@email.arc.nasa.gov" ("$USER" is currently "'"$USER"'").'
            exit 0
            ;;
        -*)
            echo "$0"': unknown flag; see "autobuild -h" for help.'
            exit 20
            ;;
    esac
fi

# $email will be the address to mail messages to.
# If a user name or email address is given as an argument, send email to that
#   address instead, do not call cvs except to update and get diffs,
#   do not remove PLASMA, and require starting within an existing PLASMA checkout.
if test -z "$1"
then
    email="$USER"@email.arc.nasa.gov
    removePlasma=false
else
    email="$1"
    if test "$email" != 'europa-night-build-results@nx.arc.nasa.gov'
    then
        removePlasma=false
    else
        removePlasma=true
    fi
fi

if "$removePlasma"
then
    # For this to work, this script must be called by its full path name
    #   when emailing to checkins@postdoc.arc.nasa.gov.
    startdir="`dirname $0`"
    startdir="`cd $startdir; pwd`"
    cd "$startdir"
    PLASMA_DIR="$startdir"/PLASMA
else
    startdir="`pwd`"
    case "$startdir" in
    *PLASMA)
            if test ! -d CVS
            then
                echo "$0"': must be run inside existing PLASMA checkout when giving email address other than europa-night-build-results@nx.arc.nasa.gov'
                exit 21
            fi
            PLASMA_DIR="$startdir"
            ;;
    *)
            echo "$0"': must be run inside existing PLASMA checkout when giving email address other than europa-night-build-results@nx.arc.nasa.gov'
            exit 22
            ;;
    esac
fi

# "Guess" where the programs that we need are, based on the operating system.
#   Almost certainly only works at NASA/Ames in Code TC.
OS="`uname -s`"
case "$OS" in
    [Ll][Ii][Nn][Uu][Xx])
        CVS_HOME=/usr
        GCC_ROOTDIR=/usr/local/gcc-3.4.0
        JAM_HOME=/usr/local/jam2.5
        JAVA_HOME=/usr/java/j2sdk1.4.2_04
        ;;
    [Ss][Uu][Nn][Oo][Ss])
        CVS_HOME=/usr/local
        GCC_ROOTDIR=/usr/local/beta/gcc-3.3.3
        JAM_HOME=/usr/local/beta/bin
        JAVA_HOME=/usr/local/jdk1.5.0_04
        ;;
esac

if test "`hostname`" = tara.arc.nasa.gov
then
    # Linux computer with different setup than others at NASA/Ames Code TC.
    JAVA_HOME=/usr/java/j2sdk1.4.2_05
    JAM_HOME=/usr/local/jam-2.5
fi

for x in "$CVS_HOME"/bin/cvs "$GCC_ROOTDIR"/bin/g++ "$JAM_HOME"/jam "$JAVA_HOME"/bin/javac "$GCC_ROOTDIR"/lib
do
  if test ! -x "$x"
  then
    echo ''
    echo "$0"': cannot find '"$x"
    exit 2
  fi
done

# Usually, this is run via cron, which does not use the usual $PATH
PATH="$JAVA_HOME"/bin:"$JAM_HOME":"$GCC_ROOTDIR"/bin:"$CVS_HOME"/bin:/usr/ucb:/opt/ssh/bin:"$PATH"
export GCC_ROOTDIR JAVA_HOME PATH

info="Emailing to $email; removePlasma is $removePlasma`echo ''; uname -a; echo ''; $GCC_ROOTDIR/bin/g++ --version ; pwd ; echo ''`"
echo "$info"

# CVS info
CVS_RSH=ssh
CVSROOT='copernicus.arc.nasa.gov:/home/cvs/ISG-Repository'
export CVS_RSH CVSROOT

# Don't run this script more than once in the same directory.
#   Should figure out a way to require at most one run on a computer at a time,
#     as that's the real requirement (related to the CVS tagging scheme).
if mkdir working
then
    # Remove the "lock" when this shell process exits.
    trap 'rmdir $startdir/working' 0
else
    echo ''
    echo "$0"': could not create lock directory; already running?'
    exit 1
fi

# Make sure that libstdc++.so is in this.
#   Cannot easily test for it since some installs don't create libstdc++.so per se,
#     but only with a version number appended.
#   In general, may have to ask the compiler where the libraries are, which
#     only gcc/g++ supports (to my knowledge).
if test -z "$LD_LIBRARY_PATH"
then
    LD_LIBRARY_PATH="$GCC_ROOTDIR"/lib:"$PLASMA_DIR"/lib
else
    LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$GCC_ROOTDIR"/lib:"$PLASMA_DIR"/lib
fi
export LD_LIBRARY_PATH

if "$removePlasma"
then
    rm -rf Old
    test -d Prior && mv Prior Old
    # Refuse to run if a prior check out is present.
    if test -d PLASMA -o -d Prior
    then
        (echo "$info";
            echo 'PLASMA directory already present or configuration botch; aborting autobuild') | \
                Mail -s 'PLASMA Autobuild on '"`hostname`"' in '"`pwd`"' aborted' "$email"
        mkdir "$startdir"/working/aborted
        exit 3
    fi
    mkdir Prior
    mv cvs.PLASMA jam.* Prior/
fi

# The (compilation) variants to build and test.
variants='DEV OPTIMIZED PROFILE'
if $coverage
then
    if $performance
    then
        echo "$0"': COVERAGE and PROFILE require incompatible g++ options; skipping COVERAGE'
    else
        variants="$variants"' COVERAGE'
    fi
fi

# The different ways of building the libraries.
libmethods='STATIC NONE SHARED'

# Don't try to use X11 (mostly to prevent Purify from doing so)
DISPLAY=
export DISPLAY

# On Linux, debug memory allocation.
MALLOC_CHECK_=2
export MALLOC_CHECK_

# Apply limits; some planner runs want lots of RAM (>2GB).
ulimit -c 400000
ulimit -d 1300000
ulimit -s 1300000
ulimit -t 3600
ulimit -v 1300000

# Print the limits so it is obvious what they are when something goes wrong.
ulimit -a

# Perform a cvs command, checking that it succeeds, etc., and send email if something goes wrong.
function cvsCmd() {
  if test "$1" != 'co' -a "$1" != 'checkout' -a "$1" != 'rtag' -a "$removePlasma" = 'true'
  then
    mkdir PLASMA/autobuild.bug
    (echo "$info"; echo ''; echo 'cvsCmd() called with unexpected arguments: '"$*") | \
        Mail -s 'PLASMA autobuild bug on '"`hostname`"' in '"`pwd`"' failed' "$email"
    mkdir "$startdir"/working/failed
    exit 23
  fi
  if test "$1" != '-q' -a "$2" != 'update' -a "$removePlasma" = 'false'
  then
    mkdir PLASMA/autobuild.bug
    (echo "$info"; echo ''; echo 'cvsCmd() called with unexpected arguments: '"$*") | \
        Mail -s 'PLASMA autobuild bug on '"`hostname`"' in '"`pwd`"' failed' "$email"
    mkdir "$startdir"/working/failed
    exit 24
  fi
  echo Calling cvs $* at "`date`" ... >> cvs.PLASMA 2>&1
  cvs $* >> cvs.PLASMA 2>&1
  status=$?
  echo '"cvs '"$*"' in '"`pwd`"' exited '"$status"
  if test "$status" != 0
  then
    mkdir PLASMA/cvs.failed
    (echo "$info"; echo ''; echo '"cvs '"$*"' failed; aborting autobuild'; tail cvs.PLASMA) | \
        Mail -s 'PLASMA Autobuild cvs on '"`hostname`"' in '"`pwd`"' failed' "$email"
    mkdir "$startdir"/working/failed
    exit "$status"
  fi
}

# Run jam with the given arguments, saving the output in a specific file
#   and complaining via email if something fails.
function jamCmd() {
  outFile="jam.$2.$var.$libmethod"
  jam "${jam_args[@]}" $1 > "$outFile" 2>&1
  status=$?
  echo 'jam '"${jam_args[*]} $1"' in '"`pwd`"' exited '"$status"
  case "$1" in
      *performance*) # Pull out the "important" lines.  The choice in the pattern after 'sys' is space or tab.
          egrep -i '(node)|(user)|(real)|(sys[	 ])|(RUN_)' "$outFile" > "$outFile".summary
          ;;
  esac
  if test $status -ne 0
  then
    (echo "$info";
     echo '';
     echo 'PPW_CONFIG='"$PPW_CONFIG"'; export PPW_CONFIG';
     echo 'jam '"${jam_args[*]} $1"' in '"`pwd`"' exited '"$status";
     if test -s "$outFile".summary
         then
         echo '';
         echo 'Performance summary '"$outFile"'.summary:';
         echo '';
         cat "$outFile".summary;
         echo '';
     fi
     more "$outFile" < /dev/null) | \
        Mail -s 'PLASMA Autobuild jam '"${jam_args[*]} $1"' on '"`hostname`"' failed' "$email"
    mkdir "$startdir"/working/failed
    exit $status
  fi
}

if "$removePlasma"
then
    # This tag - and all others used by this script - must be unique to
    #   this computer, or two autobuild scripts running on different hosts
    #   are likely to interfere with each other.
    testingTag=AutobuildTesting_"`hostname | sed -e 's/[.].*//'`"

    # This is needed if nothing under PLASMA has "$testingTag".
    cvsCmd rtag -F "$testingTag" PLASMA/README
    # Remove the prior testing tag before ...
    cvsCmd rtag -d "$testingTag" PLASMA
    # ... tagging the to-be-tested version:
    cvsCmd rtag -rHEAD "$testingTag" PLASMA
else
    : 'Would update once, before running jam, but that introduces problems'
    : '  related to this script itself being under the PLASMA CVS tree.'
fi

# Warn if there is a newer version of this script in CVS ?
warn=true

if test ! -d "$startdir"/working
    then
    echo ''
    echo "$0"': lock directory '"$startdir"'/working removed externally; exiting early'
    exit 4
fi
if test -d "$startdir"/working/stop
    then
    echo ''
    echo "$0"': directory '"$startdir"'/working/stop created externally; exiting early'
    exit 5
fi

for var in $variants
  do
  for libmethod in $libmethods
    do
    if test "$var $libmethod" = 'PROFILE SHARED' \
            -o "$var $libmethod" = 'COVERAGE SHARED' \
            -o "$var $libmethod" = 'COVERAGE NONE'
        then
        continue
    fi
    if test ! -d "$startdir"/working
        then
        echo ''
        echo "$0"': lock directory '"$startdir"'/working removed externally; exiting early'
        exit 4
    fi
    if test -d "$startdir"/working/stop
        then
        echo ''
        echo "$0"': directory '"$startdir"'/working/stop created externally; exiting early'
        exit 5
    fi
    if "$removePlasma"
        then
        cvsCmd co -r "$testingTag" PLASMA
        if "$warn"
            then
            cmp -s "$0" PLASMA/System/test/autobuild
            status=$?
            if test "$status" -ne 0
                then
                echo ''
                echo "$0"': warning: newer autobuild script in CVS'
                echo ''
                warn=false
            fi
        fi
        cd PLASMA
    fi
    jam_args=(-sVARIANTS="$var" -sLIBRARIES="$libmethod")
    PPW_CONFIG=''
    jamCmd plasma-all plasma
    jamCmd run-checkin-tests run-checkin-tests
    jamCmd run-all-tests run-all-tests

    # Add this to the next test's arguments for use with valgrind, memcheck, etc.:
    # -o \( "$var" = 'DEV' -a "$libmethod" = 'SHARED' \)
    if "$performance" && \
        test \( \( "$var" = 'PROFILE' -o "$var" = 'OPTIMIZED' \) -a "$libmethod" = 'STATIC' \)
        then
        jamCmd run-performance-tests run-performance-tests
    fi
    if "$removePlasma"
        then
        jamCmd clean clean
        PPW_CONFIG="$startdir"'/PLASMA/Solvers/component/PlanWorks.cfg'
    else
        PPW_CONFIG="$startdir"'/Solvers/component/PlanWorks.cfg'
    fi
    export PPW_CONFIG
    jamCmd run-nddl-planner-tests withPPW
    if "$removePlasma"
        then
        jamCmd clean clean
    fi
    (echo "$info"; echo 'PLASMA autobuild and tests of variant '"$var"' with library method '"$libmethod"' in '"`pwd`"' passed.';
        more jam.*.$var.$libmethod.summary jam.*.$var.$libmethod < /dev/null) | \
            Mail -s 'PLASMA Autobuild '"$var"' '"$libmethod"' on '"`hostname`"' passed' "$email"
    if "$removePlasma"
        then
        # Save the output files.
        if test -s "$outFile".summary && "$removePlasma"
            then
            # Use a "pattern" for the first file in case the other pattern does not match anything due to not profiling
            mv "$outFile".summar[y] System/test/RUN_satellites-1-*.gprof ..
        fi
        mv -f jam.* ..
        cd ..
        # Remove everything so that each variant is tested completely independently.
        #   Should probably test everything without removing in between as well, but ...
        rm -rf PLASMA
    fi
  done
done

# All the tests have passed (or jamCmd would have exit'd this script)

if "$removePlasma"
then
    tag=AutobuildPassed_"`hostname | sed -e 's/[.].*//'`"
    prior="$tag"'_old'
    # Make sure the prior tag is in CVS:
    cvsCmd rtag -F "$prior" PLASMA/README
    # ... before removing it:
    cvsCmd rtag -d "$prior" PLASMA
    # ... and changing it to the previous successful tag,
    #   again after making sure that tag is in CVS:
    cvsCmd rtag -rHEAD "$tag" PLASMA/README
    cvsCmd rtag -F -r "$tag" "$prior" PLASMA
    # ... and removing "$tag" so that any files that are later 'cvs remove'd are no longer tagged:
    cvsCmd rtag -d "$tag" PLASMA

    # Finally, tag the tested version to indicate it passed the tests:
    cvsCmd rtag -r "$testingTag" "$tag" PLASMA
else
    cvs -q diff -c > cvs.diff-c 2>&1
fi

(echo "$info";
    echo '';
    if "$removePlasma"
    then
        echo "All builds, tests, and cleans passed for each variant (of $variants) and";
        echo "  each method of building the libraries (of $libmethods).";
        echo "Tagged: 'cvs rtag $tag'";
    else
        echo "All builds and tests passed for each variant (of $variants) and";
        echo "  each method of building the libraries (of $libmethods).";
	echo "Note: 'jam clean' was not run and no CVS tags were made or changed.";
    fi
  ) | \
  Mail -s 'PLASMA Autobuild on '"`hostname`"' passed' "$email"

date > lastCompleted

exit 0
