#!/bin/bash
#
#   Usage: ccclog [letter options] [version]
#          At least 1 command line option is required
#
# Purpose: Show information associated with a particular version of a git repo
#
# Options:
# All options begin with a dash (-) and must appear before any other command line arg
#   -c  ..query the default coupler repository
#   -n  ..query the default NEMO repository
#   -j  ..query the default cccjob repository
#   -l  ..show the full 40 characters of the sha1 (abbreviated sha1 output by default)
#   -0 -1 ... -9 ..the number of commits to output. 0 means all. (default 1)
#   -v  ..increase the amount of output (multiple "v" options are cumulative)
#   -s  ..show only the sha1 commit hash (this overrides -v)
#   -b  ..list all branches (-b or -t will override all other options
#   -t  ..list all tags      If both -b and -t are used then -t will be ignored)
#   -h  ..display a usage message and exit
#
# Definitions:
#   repo=PATH   ..specify the pathname of an alternative git repository
#                 One of repo=PATH, option "-c" or option "-n" must appear on the command line
#                 If multiple repo specifications are provided on the command line then
#                 the repo=PATH form will override any command line option and the furthest right
#                 option on the command line will override any other options
#   after=DATE  ..show commits more recent than this date
#   before=DATE ..show commits older than this date
#
# A single word referencing the desired version (e.g. branch, tag, partial sha1, etc) may
# be supplied on the command line. If this version reference does not appear on the
# command line then the most recent commit on the master branch is assumed.
#
# Examples:
#  To see info about the most recent commit on the master branch
#  of the default coupler source repository use
#    ccclog -c
#
#  To see info about the most recent commit on the master branch
#  of the default NEMO source repository use
#    ccclog -n
#
#  To see info about the most recent commit on the master branch
#  of a user supplied repository use
#    ccclog repo=/path/to/my/repo
#
#  To see info about all commits on the master branch
#  of the default coupler source repository use
#    ccclog -c0 
#
########################################################################
#
# Larry Solheim ...Aug 2016

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"$$`

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

if [ -z "$CCRNSRC" ]; then
  echo "*** WARNING *** CCRNSRC is not defined in this environment"
else
  # Abort if CCRNSRC is defined and not a directory
  [ ! -d "$CCRNSRC" ] && bail "CCRNSRC=$CCRNSRC is not a directory"
fi

# The default location of the directory containing coupler git repository
cpl_repo=$CCRNSRC/coupler_dir/coupler.git

# The default location of the directory containing NEMO git repository
nemo_repo=$CCRNSRC/ocean_dir/nemo-CCCma.git

# The default location of the directory containing cccjob git repository
cccjob_repo=$CCRNSRC/cccjob_dir/cccjob.git

# The full path to the directory containing the git repository to query
repo=''

# The version associated with this commit
version=''

# short_sha1 is a boolean flag used to determine if the sha1 returned is abbreviated or not
short_sha1=1

# Control the amount of info written to stdout
verbose=1

# Output the sha1 only (overrides verbose)
sha1_only=0

# The number of commits to show in the output
number=1

show_branch=0
show_tag=0
show_repo_path=0

# Limit commits shown by date
after_date=''
before_date=''

# process command line options
while getopts bcdhjlnstvx0123456789 opt
do
  case $opt in
    c) repo=$cpl_repo  ;;
    n) repo=$nemo_repo ;;
    j) repo=$cccjob_repo ;;
    l) short_sha1=0 ;;
    v) verbose=$((verbose+1)) ;;
    s) sha1_only=1 ;;
    b) show_branch=1 ;;
    t) show_tag=1 ;;
    d) show_repo_path=1 ;;
    [0-9]) number=$opt ;;
    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
           repo) # git version, tag or branch
                 # This definition will override any set via the -c or -n options
                 repo="$val" ;;
           after) # Show commits more recent than this date
                 after_date="$val" ;;
           before) # Show commits older than this date
                 before_date="$val" ;;
           *) bail "Invalid command line arg --> $arg <-- Unknown variable." ;;
         esac
         ;;
      *) if [ -z "$version" ]; then
           # The first time through assign version with the user supplied value
           version=$arg
         else
           # It is an error for any other words to appear on the command line
           bail "Invalid command line arg --> $arg <-- Expecting variable assignment or keyword."
         fi
         ;;
  esac
done

# Sanity checks on the value of repo
[ -z "$repo" ] && usage -e "repo is not defined"
[ ! -d $repo ] && bail "$repo is not a directory"

# Assign version if it has not been defined on the command line
[ -z "$version" ] && version=master

# Set the number of commits to display
if [ $number -eq 0 ]; then
  ncommit=''
else
  ncommit=-$number
fi

# Set a date range to display
if [ -n "$after_date" ]; then
  ncommit=''
fi
if [ -n "$before_date" ]; then
  ncommit=''
fi

# Adjust verbose when sha1_only is true
[ $sha1_only -eq 1 ] && verbose=0

# Set the format depending on the value of verbose
case $verbose in
  0) if [ $short_sha1 -eq 1 ]; then
       fmt=%h
     else
       fmt=%H
     fi
     ;;
  1) if [ $short_sha1 -eq 1 ]; then
       fmt="%h %ci %cn%d --- %s"
     else
       fmt="%H %ci %cn%d --- %s"
     fi
     ;;
  2) fmt=medium
     ;;
  3) fmt=fuller
     ;;
  *) fmt=raw
     ;;
esac

# rmt_mach=joule
# rmt_cmd="cd ${repo}; git log $ncommit --format=\"$fmt\" $version"
# ssh $rmt_mach 'bash -s' -- <<< $rmt_cmd ||
#      bail "Problem executing git log on $rmt_mach"

if [ $show_repo_path -eq 1 ]; then
  echo $repo
fi

cd $repo
if [ $show_branch -eq 1 ]; then
  out=$(git branch) || bail "Unable to find branches"
elif [ $show_tag -eq 1 ]; then
  out=$(git tag)    || bail "Unable to find tags"
else
  if [ -n "$after_date" -a -n "$before_date" ]; then
    out=$(git log $ncommit --after="$after_date" --before="$before_date" --format="$fmt" $version) ||
        bail "Try a different version string"
  elif [ -n "$after_date" ]; then
    out=$(git log $ncommit --after="$after_date" --format="$fmt" $version) ||
        bail "Try a different version string"
  elif [ -n "$before_date" ]; then
    out=$(git log $ncommit --before="$before_date" --format="$fmt" $version) ||
        bail "Try a different version string"
  else
    out=$(git log $ncommit --format="$fmt" $version) ||
        bail "Try a different version string"
  fi
fi
echo "$out"
