#!/bin/bash
#
#   Usage: get-nemo-src [options] ver=tag [out=dir] [src=path]
#          Quantities in square brackets are optional
#
# Purpose: Extract a particular version of the NEMO source code from a repository
#
# Options:
# All options begin with a dash (-) and must appear before any other command line arg
# Single letter options may be combined, as in "get-nemo-src -vv ..."
#   -t   ...list all tags and exit
#   -c   ...list all commits, one per line, and exit
#   -f   ...force overwrite of any existing output directory
#           If -f is not used and the output dir exists then the program will abort
#   -v   ...increase verbosity (additive)
#   -h   ...show this usage message
#   -x   ...echo shell commands to stdout (used for debugging)
#
# Definitions:
#   ver=commit ...the source revision to be extracted (use -t to list possible tags)
#   out=dir    ...the dir into which the source will be copied
#                 If out=... is not present then the name "nemo_src_$commit" is used
#   src=LIST   ...a white space separated list of dirs or file names
#                 If src=... is present then only these files/dirs will be copied
#                 Each dir/file will be realtive to the nemo subdir in the repository
#
# Examples:
#  To list all tags in the repository use
#    get-nemo-src -t
#
#  To list all commits, including dates and a message, use
#    get-nemo-src -c
#
#  To get all source files associated with nemo 3.4 in dir mydir use
#    get-nemo-src ver=nemo_v3.4 out=mydir
#
#  To extract only the ARCH and CONFIG subdirs from nemo 3.4.1 use
#    get-nemo-src ver=nemo_v3.4.1 src="ARCH CONFIG"
#
########################################################################
#
# Larry Solheim Sep 2012

FULLPATH=`type $0|awk '{print $3}'` # pathname of this script
Runame=`basename $FULLPATH`
usage() {
  err_exit=0
  while getopts e opt; do
    case $opt in
      e) err_exit=1 ;;
    esac
  done
  shift `expr $OPTIND - 1`

  [ -n "$1" ] && echo >&2 "${Runame}:" "$@"
  echo >&2 " "
  sed >&2 -n '/^###/q; s/^#$/# /; s/^ *$/# /; 3,$s/^# //p;' "$FULLPATH"
  if [ $err_exit -eq 0 ]; then
    exit
  else
    exit 1
  fi
}

# Create time stamp to be used in file names etc
stamp=`date "+%j%H%M%S"$$`

# Identify, by name, the machine this script is running on
this_host=`hostname|cut -d'.' -f1`

bail(){
echo "${Runame}: *** ERROR *** $1"
exit 1
}

add2path(){
  if echo $PATH|/bin/grep -Evq "'(^|:)'$1'($|:)'" ; then
     if [ "$2" = "atend" ] ; then
        PATH=$PATH:$1
     else
        PATH=$1:$PATH
     fi
  fi
}

# echo without return (ie: emulate -n if not recognized by echo)
if [ "X`echo -n`" = "X-n" ]; then
  echo_n() { echo ${1+"$@"}'\c'; }
else
  echo_n() { echo -n ${1+"$@"}; }
fi

# Set defaults

# The version of code to extract and compile
version=''

# CCRNSRC must be defined
CCRNSRC=${CCRNSRC:=/home/acrnsrc}
[   -z "$CCRNSRC" ] && bail "CCRNSRC must be defined"
[ ! -d "$CCRNSRC" ] && bail "$CCRNSRC is not a directory"

# The default location of the repository containing nemo source code
source_repo=$CCRNSRC/ocean_dir/nemo-CCCma.git

# show_tags = 1 means the program should list all tags in the repo and then exit
show_tags=0

# show_all_commits = 1 means kist all commints, one per line, then exit
show_all_commits=0

# force = 1 means remove any existing output dir and then recreate it prior to
#           populating it with the requested NEMO source
# force = 0 mean abort if the output dir already exists
force=0

# A subdir or pathname relative to the repository root dir
# This will identify the subset of the source tree that is to be extracted
usr_src=''

# Verbosity flag
verbose=0

# The name of a directory in which the extracted source will go
out_dir=''

# process command line options
while getopts cfhtvx opt
do
  case $opt in
    f) force=1 ;;
    t) show_tags=1 ;;
    c) show_all_commits=1 ;;
    v) verbose=`expr $verbose + 1` ;;
    x) set -x ;;
    h) usage ;;
    -) shift; break ;; # end of options
    ?) usage -e $USAGE   ;;
  esac
done
shift `expr $OPTIND - 1`

# Process the remaining command line args
for arg in "$@"; do
  case $arg in
    *=*) var=`echo $arg|awk -F\= '{printf "%s",$1}' -`
         val=`echo "$arg"|awk '{i=index($0,"=")+1;printf "%s",substr($0,i)}' -`
         # add this variable definition to the current environment
         [ -n "$var" ] && eval ${var}=\"\$val\"  # preserve quoted assignments
         val=`echo $val|sed 's/^ *//; s/ *$//'`  # remove leading and trailing space
         [ -z "$val" ] && bail "Invalid command line arg --> $arg <-- Empty value."
         case $var in
           ver) version="$val" ;;           # git version, tag or branch
           out) out_dir="$val" ;;           # output directory name
           src) usr_src="$usr_src $val" ;;  # extract a subset of the repo src
           repo) source_repo="$val" ;;      # location of git repository
           *) bail "Invalid command line arg --> $arg <-- Unknown variable." ;;
         esac
         ;;
    *) bail "Invalid command line arg --> $arg <-- Expecting variable assignment." ;;
  esac
done

[ -z "$source_repo" ] && usage -e "The source repository name is missing."
[ ! -d "$source_repo" ] && usage -e "Repository is not a directory --> $source_repo <--"

if [ $show_tags -eq 1 ]; then
  # Simply list all tags in the repository and exit
  cd $source_repo
  git tag
  exit
fi

if [ $show_all_commits -eq 1 ]; then
  cd $source_repo
  git log --date=local --pretty='%h :: %cd --- %s' | cat
  exit
fi

# version is mandatory
[ -z "$version" ] &&
    usage -e "A version number, tag or branch is required on the command line."

# If the user did not supply an output dir name then define one here
[ -z "$out_dir" ] && out_dir=nemo_src_$version

if [ -d $out_dir ]; then
  if [ $force -eq 1 ]; then
    # Remove any existing output dir
    rm -fr $out_dir || usage -e "Unable to remove $out_dir"
  else
    # The output dir exists but the user has not invoked the force (-f) option
    usage -e "Output directory --> $out_dir <-- exists. Use -f to force overwrite."
  fi
fi

# Create the output dir
mkdir -m 755 $out_dir || usage -e "Unable to create output directory --> $out_dir <--"

fail=0
GIT=`which git` || fail=1
if [ $fail -eq 1 ]; then
  # When not on the users path, find git in a known location (if possible)
  case $this_host in
    c1*|c2*) # This is spica or hadar
      # Set up env to use git when running on the back end
      GIT_PATH=/users/tor/acrn/rls/local/aix64/bin
      [ ! -d "$GIT_PATH" ]     && bail "$GIT_PATH is not a directory"
      [ ! -s "$GIT_PATH/git" ] && bail "$GIT_PATH/git is missing"
      [ ! -x "$GIT_PATH/git" ] && bail "You require execute permission for $GIT_PATH/git"
      add2path $GIT_PATH
      ;;
    *) bail "Unable to find git."
  esac
fi

# Get a full pathname for the output dir
out_dir_full=$(cd $out_dir; pwd)

# nemo_rootd is a dir relative to the root of the git repository
# This dir will contain the NEMO source code
nemo_rootd=nemo

extract_path=$nemo_rootd
 
if [ -n "$usr_src" ]; then
  # If the user has supplied an explicit list of source dirs (or files)
  # to extract then redefine extract_path accordingly
  # Note, these files are always relative to nemo_rootd as defined above
  extract_path=$(for p in $usr_src; do echo -n "$nemo_rootd/$p "; done)
fi

# Extract the requested files from the repository
git archive --remote=$source_repo --format=tar $version $extract_path | \
  (cd $out_dir_full && tar xf -) ||
  bail "Unable to extract revision --> $version <-- from repository $source_repo"

# Move everything out of nemo_rootd and remove nemo_rootd from out_dir
cd $out_dir_full
if [ -d $nemo_rootd ]; then
  mv $nemo_rootd/* .
  rm -fr $nemo_rootd
fi

# Make it all world readable
find . -type d | xargs chmod a+rx
find . -type f | xargs chmod a+r

echo "Source for revision $version is in ${out_dir}"
