#!/bin/bash
#
# cicl - commit changelog
# =======================
# (c) 2007,2008 daniel g. siegel, Étienne Bersac
#
# cicl is a wrapper around svn commit, which updates the ChangeLog file with
# the commit message before actually commiting. That means, that the same
# commit message will be used in the svn log as in your Changelog file.
#
# The nice thing about that is that if you have a wrong commit (e.g. you were
# drunk and commited the queen of england) you just have to run svn commit as
# usual and the ChangeLog won't get touched. This avoids some "oh, i forgot to
# add foo.[ch]" ChangeLog entries.
#
# Further on you can remove/add files in the commit message, which then get
# automatically added or removed _if_ svn stat lists them as modified.
#
# IF YOU WANT TO HAVE A CONFIG-FILE, JUST PUT THE THINGS BELOW INTO
# ~/.config/ciclrc , WHICH GETS LOADED AUTOMATICALLY
#
###############################################################################
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
#
# Changelog
# =========
# 2008-08-12  add the fmt command to the Changelog message, in order to truncate long lines
# 2008-06-29  set the EDITOR variable if not available
# 2007-10-27  new option: possibility to put Changelog in the list of modified files
# 2007-09-18  initial release

CHANGELOG="ChangeLog"           # the ChangeLog file
ADD_CHANGELOG="n"               # if you want to have the ChangeLog file listed in the modified files
MAINTAINERS_FILE="MAINTAINERS"  # the MAINTAINERS file
AUTHORS_FILE="AUTHORS"          # the AUTHORS file
ASK_AND_VERBOSE="y"             # if you should be asked before doing the commit
# - "y"  - for yes
# - "n"  - for no

# Valid options for AUTHOR:
# - "1" - get the author from the AUTHORS-file
# - "2" - get the author from the MAINTAINERS-file
# - "vincent vuntz" - set the author to a specific string
AUTHOR="2"

# debian and ubuntu system do not set the EDITOR environment variable
if [ -z $EDITOR ]; then
  EDITOR="vim"
fi

##############
# Do not edit below here if you don't know what you are doing
##############

CFGFILE=~/.config/ciclrc
test -f $CFGFILE && source $CFGFILE

usage () {
    echo "$0: Commit changes to the repository updating ChangeLog";
    echo "usage : $0 [PATH...]";
    exit;
}

case $1 in
  "--help"|"-h"|"-?")
  usage;
  ;;
esac

TMPFILE=${CHANGELOG}.tmp
MSGFILE=cicl.message

case $AUTHOR in
  1) # from the AUTHORS-file
    LOGIN=$(whoami)
    AUTHOR=$(grep $LOGIN $AUTHORS_FILE | sed "s/$LOGIN://")
    ;;
  2) # from the MAINTAINERS-file
    LOGIN=$(whoami)
    AUTHOR=$(grep -B 2 "Userid: $LOGIN" $MAINTAINERS_FILE | \
             grep -vi "E-mail" | \
             grep -vi "Userid")
    MAIL=$(grep -B 2 "Userid: $LOGIN" $MAINTAINERS_FILE | \
           grep -i "E-mail" | \
           sed "s/^.* //")
    AUTHOR="$AUTHOR <$MAIL>"
    ;;
  *) # AUTHORS is already set
esac

################
# FIRST get files to commit
################

if [ $# = 0 ] ; then
    FILES=$(svn st | grep -v "^?" | sed 's/^.* //')
    # filter out every
    # - line that starts with "?"
    # - every whitespace at the beginning of a line
else
    F=$@
    for i in $F; do
      # rip out files, which weren't changed
      if [ -z "$(svn st | grep -v "^?" | grep "$i")" ]; then 
        echo "No changes found in $i"
      else
        FILES="$FILES $i"
      fi
    done
fi

if [ -z "$FILES" ]; then
  echo "No changes found..."
  exit;
fi

FILES=$(echo $FILES | sort)


################
# SECOND get commit message
################

echo > $MSGFILE;
echo >> $MSGFILE;
echo "-- Following lines will be ignored" >> $MSGFILE;
for f in $FILES ; do
    echo -n "-- " >> $MSGFILE;
    svn st $f >> $MSGFILE;
done

if [ "$ADD_CHANGELOG" = "y" ] || [ "$ADD_CHANGELOG" = "Y" ]; then
  # svn stat won't list the ChangeLog file, so we are adding it manually
  echo -n "-- " >> $MSGFILE;
  echo "M      ChangeLog" >> $MSGFILE;
  FILES=$(echo $FILES "ChangeLog" | tr " " "\n" | sort | tr "\n" " ")
else
  FILES=$(echo $FILES | tr " " "\n" | sort | tr "\n" " ")
fi

$EDITOR $MSGFILE

# getting the message without
# - lines that begin with "--"
# - empty lines
MESSAGE=$(grep -v "\-- " $MSGFILE | sed '/^ *$/d')

if [ -z "$MESSAGE" ] ; then
    echo "Empty message. Aborting."
    exit;
fi

# getting added/removed files
F=""
MSGFILES=$(grep "^-- [A-Z][[:space:]]\+" $MSGFILE | sed "s/^--.* //g")
for i in $MSGFILES; do
  if [ ! -z "$(svn st | grep -v "^?" | grep "$i")" ]; then 
    if [ -z "$F" ]; then
      F="$i"
    else
      F="$F $i"
    fi
  fi
done

if [ -z "$F" ]; then
  echo "No (modified) files chosen. Aborting."
  exit;
else
  if [ "$ADD_CHANGELOG" = "Y" ] || [ "$ADD_CHANGELOG" = "y" ]; then
    if [ ! "$FILES" = "$F" ];then
      FILES=$(echo $F "ChangeLog" | tr " " "\n" | sort | tr "\n" " ")
    fi
  else
    FILES=$(echo $F | tr " " "\n" | sort | tr "\n" " ")
  fi
fi

rm $MSGFILE


################
# THIRD write ChangeLog entry
################

DATE=`date +%Y-%m-%d`
ENTRY="$DATE  $AUTHOR\n"
echo -e "$ENTRY" > $TMPFILE

ENTRY=`echo -n -e "\t*"`

E=$(echo -e "$FILES" | sed -e "s/ /,/g")

# replace the last "," with a ":"
E=$(echo $E | sed -e "s/,$/:/")
E=$(echo $E | sed -e "s/,/,\n\t  /g")

LOGMSG=$(echo "$MESSAGE" | sed -e "s/^/\n\t  /" | fmt)
ENTRY="$ENTRY $E $LOGMSG\n"

echo -e "$ENTRY" >> $TMPFILE
cat $CHANGELOG >> $TMPFILE


################
# LAST commit
################

if [ "$ASK_AND_VERBOSE" = "y" ] || [ "$ASK_AND_VERBOSE" = "Y" ]; then
  $EDITOR $TMPFILE

  echo -n "do you want to commit the above? (Y/n) "
  read
  if [ ! "$REPLY" = "Y" ] && [ ! "$REPLY" = "y" ] && [ ! "$REPLY" = "" ]; then
    echo "if you dont want to commit, thats fine for me, you lazy fool!"
    exit
  fi
fi

mv $TMPFILE $CHANGELOG
echo $MESSAGE > /tmp/logmsg
svn commit -F /tmp/logmsg $FILES ChangeLog;
rm /tmp/logmsg

