#! /bin/bash
# A script for building GS2. This is free software, released
# under the MIT licence.
# Written by:
#            Edmund Highcock (edmundhighcock@users.sourceforge.net)
# Modified by:
#            D Dickinson (ddickinson@users.sourceforge.net)

function short_help(){
    cat <<EOF
usage: ./$(basename $0) Options

OPTIONS:
   -h          Show this message and long help
   -c <VAL>    Pass <VAL> as extra commands to make
   -s <VAL>    Specify the system name, used to determine which configuration to use
   -t <VAL>    Run a particular test (automatically implies -o tests)
   -v <VAL>    Set the verbosity for tests (0-5)
   -d          Build with DEBUG=on
   -g          Build with gcov coverage flags (USE_GCOV=on)
   -n          When used with tests, build but don't run the tests.
   -l <level>  Set test level: higher values include slower tests; default is 1
   -p <nprocs> Set number of MPI processes to use for tests
   -o <VAL>    Specify operation to perform, can be one of:
                     ls              : List the supported systems 
                     help            : Prints the long help
                     man             : Pipes the long help to less
                     config          : Creates the configuration file
                     print_config    : Creates and prints the configuration file
                     build           : Runs make to compile code (no target specfied) <DEFAULT>
                     gs2             : Runs make to compile gs2 executable
                     tests           : Uses make to run unit_tests and linear_tests
                     unit_tests      : Run unit_tests
                     linear_tests    : Run linear_tests
                     nonlinear_tests : Run nonlinear_tests
                     update          : Updates this script
                     depend          : Builds the dependency file
                     clean           : Runs make clean
                     distclean       : Runs make distclean
EOF

}
function print_help {
  echo ""
  echo " GS2 Build Script"
  echo
  echo "This script is a utility for building GS2."
  echo "To build gs2, execute:" 
  echo " $ ./build_gs2 -s <system>"
  echo 
  echo "If you have set GK_SYSTEM you can neglect the -s"
  echo "option."
  echo 
  echo "To see a list of available systems:"
  echo " $ ./build_gs2 -o ls"
  echo 
  echo "To run the tests: "
  echo " $ ./build_gs2 -o tests -s <system>"
  echo 
  echo "To run a specific test:"
  echo " $ ./build_gs2 -t <test> -s <system>"
  echo "E.g."
  echo " $ ./build_gs2 -t le_grids -s <system>"
  echo " $ ./build_gs2 -t 'le_grids cyclone_itg' -s <system>"
  echo 
  echo "To run tests while measuring code coverage, use the g flag:"
  echo " $ ./build_gs2 -t <test> -s <system> -g"
  echo "E.g."
  echo " $ ./build_gs2 -t le_grids -s <system> -g"
  echo " $ ./build_gs2 -t 'le_grids cyclone_itg' -s <system> -g"
  echo "After running, annoted source code showing lines touched"
  echo "is saved in the directory 'coverage_<command>', "
  echo "e.g. 'coverage_test', 'coverage_linear_tests'"
  echo 
  echo "To run tests with a given number of MPI processes, use the p flag:"
  echo " $ ./build_gs2 -t <test> -s <system> -p <nprocs>"
  echo
  echo "For more specific commands you can use the c flag:"
  echo " $ ./build_gs2 -c DEBUG=on"
  echo " $ ./build_gs2 -c 'DEBUG=on USE_FFT=fftw3'"
  echo "The c flag passes an arbitrary string to the"
  echo "make command."
  echo 
  echo "To print the configuration for a given system:"
  echo " $ ./build_gs2 -s <system> -o print_config "
  echo 
  echo "You can use this to configure your system"
  echo "without building GS2 like this:"
  echo " $ ./build_gs2 -s <system> -o config "
  echo " $ source system_config"
  echo
  echo "It uses a standard set of choices about"
  echo "configuration based on the value of -s. These"
  echo "choices may need to be maintained as software is upgraded."
  echo "If this script is being run from within a release of GS2,"
  echo "rather than from the development repository, it can be updated"
  echo "to the latest development version using: "
  echo " $ ./build_gs2 -o update"
  echo
}

function check_system_set {
if [ "$GK_SYSTEM" == "" ] 
then
  echo "ERROR: Please set the -s option or set the GK_SYSTEM environment variable."
  exit 1
fi
}


function run_configuration {
make system_config GK_SYSTEM=$GK_SYSTEM -I Makefiles || exit 1
}

function setup_build {
check_system_set
run_configuration
source system_config
}

function teardown {
GCOV_DIR=coverage_$COMMAND
if [ ${RUN_GCOV} == "on" ]
then
gcov *.f90
gcov utils/*.f90 -o .
mkdir -p $GCOV_DIR
mv *.gcov $GCOV_DIR/.
fi
}


#Defaults
MAKE_OPTIONAL_COMMAND=""
COMMAND="build"
RUN_GCOV=off

#Parse arguments
while getopts "hdngs:c:o:t:v:l:p:" OPTIONS
do
  case ${OPTIONS} in
    h)
      short_help
      exit 0
      ;;
    s)
      GK_SYSTEM=${OPTARG}
      ;;
    c)
      MAKE_OPTIONAL_COMMAND=${OPTARG}
      ;;
    d)
      DBGFLAG=DEBUG=on
      ;;
    g)
      GCOVFLAG=USE_GCOV=on
      RUN_GCOV=on
      ;;
    n)
      TESTNORUNFLAG=TESTNORUN=true
      ;;
    o)
      COMMAND=${OPTARG}
      ;;
    t)
      COMMAND=tests
      TESTSET=TESTS=$OPTARG
      ;;
    l)
      LEVELSET=TEST_LEVEL=$OPTARG
      ;;
    p)
      MPIPROCSET=NPROCS=$OPTARG
      ;;
    v)
      COMMAND=tests
      VERBSET=GK_VERBOSITY=$OPTARG
      ;;

    *)
      short_help
      exit 1
      ;;
  esac
done

# Define combined make flags
MAKEFLAGSALL="$MAKEFLAGS $DBGFLAG $TESTNORUNFLAG $VERBSET GK_SYSTEM=$GK_SYSTEM $MAKE_OPTIONAL_COMMAND $LEVELSET $GCOVFLAG $MPIPROCSET"

#Now perform operation
case $COMMAND in 
  man)
    print_help | less
    exit 0
    ;;
  help)
    print_help
    ;;
  config)
    check_system_set
    run_configuration
    ;;
  print_config)
    check_system_set
    run_configuration
    echo
    echo "Configuration for system $GK_SYSTEM:"
    cat system_config
    ;;
  ls)
    find Makefiles -type f -exec grep -q STANDARD_SYSTEM_CONFIGURATION {} \; -print | grep -v svn | grep -Ev '~$|swp$|orig$' | sed 's|Makefiles/Makefile\.||g' | sort #| xargs echo
    ;;
  build)
    setup_build
    make $MAKEFLAGSALL
    ;;
  tests|unit_tests|linear_tests|nonlinear_tests|depend|gs2)
    setup_build
    if [ "$TESTSET" == "" ] 
    then
      make $COMMAND $MAKEFLAGSALL
    else
      make $COMMAND "$TESTSET" $MAKEFLAGSALL
    #echo make $COMMAND $TESTSET $MAKEFLAGSALL
    fi
    teardown
    ;;
  update)
    svn up Makefiles
    svn up scripts/build_gs2
    exit 0
    ;;
  clean)
    setup_build
    make $COMMAND $MAKEFLAGSALL
    ;;
  distclean)
    setup_build
    make $COMMAND $MAKEFLAGSALL
    ;;
  *)
    echo "ERROR: Unknown command $COMMAND. Run" 
    echo " $ ./build_gs2 -h" 
    echo "for usage."
    echo " $ ./build_gs2 -o man"
    echo "for more details."
    ;;
esac

exit 0
