#!/bin/bash

#####################################################################

# Description: Automation Deployment Script

#              Netkiller series utilities

# Author: Neo<netkiller@msn.com>

# Homepage: http://netkiller.github.com/

#                       http://netkiller.sourceforge.net/

# GIT URL:  https://github.com/netkiller/deployment.git

# $Id$

#####################################################################

# :set  tabstop=4

# :set shiftwidth=4

# :set expandtab


if [ -z $DEPLOY_HOME ]; then

       echo 'Example: export DEPLOY_HOME=/srv/deploy'

       exit

fi

if [ -f $DEPLOY_HOME/conf/default.conf ];then

   . $DEPLOY_HOME/conf/default.conf

fi


if [ -f $DEPLOY_HOME/conf/stage.conf ];then

   . $DEPLOY_HOME/conf/stage.conf

fi


#================================================================================


LOGFILE="deploy.$(date -d "today" +"%Y-%m-%d").log"

TMPDIR=$(mktemp -d --suffix=.tmp -p /tmp deploy.XXXXXX)

SVN=/usr/bin/svn

GIT=/usr/bin/git


BACKUPDIR=/backup

RSYNC="rsync"

UPLOAD_DIR=$TMPDIR

REVISION=''

DEBUG='yes'

# development  production  testing

if [ -z $STAGE ]; then

   echo 'Example: touch conf/stage.conf'

   echo "STAGE='development' or STAGE='testing' or STAGE='production'"

   exit

fi

#================================================================================


if [ ! -d ${TMPDIR} ]; then

   mkdir ${TMPDIR}

fi


#chmod 700 -R ${SRCDIR}/*

umask 0077

#pkgname=${project}-${version}-${datetime}.pkg

#tar jcvf ${pkgname} /tmp/${project} --remove-files >> deploy.log

#####################################################################


function logging(){

       local logfile="$LOGDIR/$LOGFILE"

       local timepoint=$(date -d "today" +"%Y-%m-%d %H:%M:%S")

       local status=$1

       local message=$2

       echo "[$timepoint] [${status}] ${message}" >> $logfile

}


function debug(){

       if [ ${DEBUG} = 'yes' ]; then

               local logfile="$LOGDIR/debug.log"

               local timepoint=$(date -d "today" +"%Y-%m-%d %H:%M:%S")

               local status=$1

               local message=$2

               echo "[$timepoint] [${status}] ${message}" >> $logfile

       fi

}


#logging 'OK' 'This is test msg!!!'

#debug 'OK' 'This is debug msg!!!'


function conf(){

   local cmd=$2

   local prj=$3

   case $cmd in

       list)

           ls $SYSCONFDIR/*/*

           ;;

       new)

           mkdir -p $SYSCONFDIR        

                       #if [ ! -d ${BACKUPDIR} ]; then

                       #       mkdir -p $BACKUPDIR

                       #fi


           read -p "Project directory: " prjdir

           if [ -z $prjdir ]; then

               exit

           fi

           if [ -f $SYSCONFDIR/$prjdir.conf ]; then

               echo "cannot create config $prjdir.conf': File exists"

               exit 1

           fi


           read -p "subversion url: $REPOSITORIES/: " svnurl

           if [ -z $svnurl ]; then

               svnurl=$REPOSITORIES

           fi

           read -p "hostname: " host

           if [ -z $host ]; then

               host="localhost"

               echo "default hostname 'localhost'"

           fi

           read -p "upload mode ftp/scp/sftp/rsync: " mode

           if [ -z $mode ]; then

               mode=ftp

           else

               case $mode in

                   ftp)

                       mode="ftpdeploy"

                       ;;

                   scp)

                       mode="scpdeploy"

                       ;;

                   sftp)

                       mode="sftpdeploy"

                       ;;

                   rsync)

                       mode="rsync"

                       ;;

               esac

           fi

           read -p "Create $prjdir config? [y/n]" -n 1 key

           echo

           if [ $key = 'y' ]; then

               echo -ne "REPOSITORIES=$REPOSITORIES/$svnurl

COMMAND=$mode

HOSTNAME=$host

               " >> $SYSCONFDIR/$prjdir.conf

           fi

           ;;

       remove)

           if [ -f $SYSCONFDIR/$prj ]; then

               rm -rf $SYSCONFDIR/$prj

           fi

           ;;

       show)

           cat $SYSCONFDIR/$prj

           ;;

       edit)

           vim $SYSCONFDIR/$prj

           ;;

       *)

                       ls $SYSCONFDIR/*/*

                       ;;

   esac


}



#####################################################################


function config {

   local cfg=$1

   exclude_from=$PREFIX/exclude/${cfg}.lst

   include_from=$PREFIX/include/${cfg}.lst


   if [ -f $SYSCONFDIR/${STAGE}/${cfg}.conf ];then

       . $SYSCONFDIR/${STAGE}/${cfg}.conf

   else

       echo "Please provide the config($SYSCONFDIR/${STAGE}/${cfg}.conf) to deploy!"

       exit

   fi

   if [ -z "$cfg" ]; then

       echo "Please provide the path for deploy!"

               exit

   fi


   if [ ! -f $exclude_from ]; then

       echo "Please provide a list of excluded in the $exclude_from."

       touch $exclude_from

       exit

   fi

   if [ ! -f $include_from ]; then

       echo "Please provide a list of included in the $include_from."

       touch $include_from

       exit

   fi


#    case ${STAGE} in

#        development)

#            SUBVERSION='development'

#            ;;

#        testing)

#            SUBVERSION=''

#            ;;

#        production)

#            ;;

#        *)

#            SUBVERSION='current'

#            ;;

#    esac


}


function deploy() {


   local domain=$2

       local host=$3

       local commit=$4

       local logfile=${LOGDIR}/${host}.${domain}.log

       local backupdir=${BACKUPDIR}/${host}.${domain}/$(date '+%Y-%m-%d/%H:%M:%S')

       local message=${STAGE}/${domain}/${host}.${domain}


   if [ $# -lt 3 ]; then

       usage

   fi


       if [ ${STAGE} = 'production' ]; then

               read -p "Are you sure you want to continue deploying? [y/n]" -n 1 key

               echo

               if [ $key != 'y' ]; then

                       exit

               fi

       fi

   if [ $host = 'all' ]; then

       for h in $(ls -1 $SYSCONFDIR/${STAGE}/$domain/ | cut -d. -f1)

       do

           /bin/sh $BINDIR/deploy.git ${STAGE} $domain $h

       done

       exit

   fi




   #if [ ! -z $revision  ]; then

   #    REVISION="-r ${revision}"

   #fi


   config ${domain}/${host}


       project=$SRCDIR/${STAGE}/${domain}/${host}.${domain}


       GIT_OPTS=${REVISION}

       echo '================================================================================'

       if [ -d ${project} ]; then

               cd $project

               #$GIT stash

               #$GIT pull --progress

               #$GIT stash clear

               #$GIT checkout .


               $GIT reset HEAD --hard >> $logfile

               echo -n " Repository: ${REPOSITORY} "

               $GIT pull --progress            

               if [ ! -z $commit ]; then

                       $GIT checkout $commit .

                       echo " Commit: $commit"

                       logging 'checkout' "commit:$commit ${project} "

               else

                       logging 'update' ${project}

               fi


       else

           mkdir -p ${project}

               $GIT clone ${REPOSITORY} ${project} >> $logfile

               logging 'checkout' ${project}

       fi

       echo '================================================================================'

       RSYNC_OPTS=" -azv --backup --backup-dir=${backupdir} --exclude=.git --log-file=${logfile} --exclude-from=$exclude_from --include-from=$include_from"


       if [ -d ${SHAREDIR}/${STAGE}/${domain}/${host}/ ]; then

               cp -a ${SHAREDIR}/${STAGE}/${domain}/${host}/* ${project}/

       fi

       echo '- share:' >> ${logfile}

       echo ' Share [ OK ]'

       if [ -f ${LIBEXECDIR}/${domain}/${host}/before ];then

               /bin/sh ${LIBEXECDIR}/${domain}/${host}/before >> ${logfile}

       fi

       echo '- libexec:' >> ${logfile}

       echo ' Libexec [ OK ]'

   find $SRCDIR/* -type f -name "Thumbs.db" -exec rm -rf {} \;

       echo '================================================================================'


       for addr in ${REMOTE}

       do


       echo " Deploy [${message}] ${addr}"

               echo '================================================================================'


               case ${MODE} in

                   FTP)

                               ftpdeploy

                               ;;

                       SCP)

                               scp -ar ${project}/* ${addr}:${DESTINATION}

                               ;;

                       SFTP)

                               sftpdeploy

                               ;;

                       RSYNC)

                               $RSYNC $RSYNC_OPTS $OPTION ${project}/* ${addr}::${DESTINATION}

                               debug 'rsync' "$RSYNC $RSYNC_OPTS $OPTION ${project}/* ${addr}::${DESTINATION}"

                               ;;

                       "RSYNC+SSH")

                               $RSYNC $RSYNC_OPTS ${project}/* ${addr}:${DESTINATION}

                               ;;

               esac


               if [ -z "${REVISION}" ]; then

                       logging 'deploy' "${message} => ${addr}:${DESTINATION}"

               else

                       logging 'revert' "${message} => ${addr}:${DESTINATION}"

               fi

               echo '--------------------------------------------------' >> ${logfile}

       done


       if [ -f ${LIBEXECDIR}/${domain}/${host}/after ];then

               #ssh ${scp} < ${LIBEXECDIR}/${domain}/${host}/after

               exit

       fi


}


function revert() {


   #if [ $STAGE = 'testing' -o $STAGE = 'development' -o $STAGE = 'production' ]; then

       local domain=$3

       local host=$4

       local commit=$5

#    else

#       local domain=$1

#        local host=$2

#        local revision=$3

   #fi

   deploy $STAGE $domain $host $commit

}


function timepoint {

       TIMEPOINT=`date '+%Y-%m-%d.%H-%M-%S'`

   echo $TIMEPOINT >> timepoint.log

}


function unstable {

   local edition=$(basename $unstable)

   svn export ${unstable} ${src}/$edition


   for ignore in $( cat excluded.lst ); do

       rm -rf ${src}/$edition/$ignore

   done


   $RSYNC ${src}/$edition ${destination}


   ssh ${remote} < script/unstable

}


function clean() {

   local stage=$2

       local domain=$3

   local host=$4

       local project=$SRCDIR/${stage}/${domain}/$host.${domain}


   if [ $# -lt 3 ]; then

       usage

   fi


   rm -rf ${project}

}


function list {

   local domain=$2

   local host=$3

   local dir=$4

   if [ -z $domain ]; then

       ls $SRCDIR/*

       exit

   fi


   if [ -z $host ]; then

       usage

   fi


   #config ${domain}/${host}

       ls $SRCDIR/*/${domain}/${host}.${domain}

   #git ls ${REPOSITORIES}/$dir #| awk -F '/' '{print $1}'

}


function backup() {

   local domain=$2

   local host=$3

   local dir=$4

       local logfile=${LOGDIR}/${host}.${domain}.log


   if [ -z $domain ]; then

               usage

   fi


   if [ -z $host ]; then

       usage

   fi


   config ${domain}/${host}


   if [ -z $dir ]; then

       dir=$TMPDIR

   fi


   for addr in ${REMOTE}

   do

               dir=$dir/${addr}

       if [ ! -d ${dir} ]; then

           mkdir -p $dir

       fi

               RSYNC_OPTS=" -azv "

       ${RSYNC} ${RSYNC_OPTS} ${OPTION} ${addr}::${DESTINATION} $dir >> ${logfile}

               logging 'backup' "rsync://${addr}::${DESTINATION} to ${dir}"


       echo 'Backup Directory:' $dir

               exit

   done


}

function cron(){

   local fun=$2        

   case ${fun} in

       show)

           crontab -l

           ;;

       setup)

           cat $PREFIX/cron.d/crontab | crontab

           ;;

       edit)

           vim $PREFIX/cron.d/crontab

           cat $PREFIX/cron.d/crontab | crontab

           ;;

       *)

           usage

           ;;

   esac


}


function release() {


   local domain=$2

   local host=$3

   local ver=$4

   local message=$5


   if [ $# -lt 4 ]; then

       usage

   fi


   if [ -z $message ]; then

       echo -n "Message: "

       read message

   fi


   config ${domain}/${host}


   local logfile=${LOGDIR}/${host}.${domain}.log

       project=$SRCDIR/${STAGE}/${domain}/${host}.${domain}

       cd $project

   $GIT tag ${ver} >> $logfile


   logging 'release' "{GIT} tag ${ver} - ${message}"

}


function stage(){

   case $1 in

       development)

           STAGE='development'

           ;;

       testing)

           STAGE='testing'

           ;;

       production)

           STAGE='production'

           ;;

       *)

           echo "STAGE ERROR"

           exit

           ;;

   esac

   echo $"STAGE=$STAGE" > $SYSCONFDIR/stage.conf && echo $STAGE

   logging 'stage' "${STAGE}"

}


function branch(){

       local stage=$2

   local domain=$3

   local host=$4

   local branchname=$5


   cd $SRCDIR/${stage}/${domain}/$host.${domain}

   if [ -z $branchname ]; then

       git branch

   else

       git reset HEAD --hard

       git pull

       git checkout -fb $branchname origin/$branchname || { git checkout -f $branchname; git pull; }

       #git checkout $branchname

   fi

}


function usage(){

echo $"Usage: $0 [OPTION] <server-id> <directory/timepoint>"

echo -ne "

OPTION:

       development <domain> <host>

       testing <domain> <host>

       production <domain> <host>      


       branch {development|testing|production} <domain> <host> <branchname>

       revert {development|testing|production} <domain> <host> <revision>

       backup <domain> <host> <directory>

       release <domain> <host> <tags> <message>


       list

       list <domain> <host>


       clean {development|testing|production} <domain> <host>  

       log <project> <line>


       conf list      

       cron show

       cron setup

       cron edit

"

#       stage {development|testing|production}

#       deploy <domain> <host>

#       revert <domain> <host> <revision>


#       conf new <project>

#       conf remove <project>

#       conf show <project>

#       conf edit <project>      


   exit

}


case "$1" in

   stage)

       stage $2

           ;;

   development)

       STAGE='development'

       deploy $@

       ;;

   testing)

           STAGE='testing'

           deploy $@

       ;;

   production)

       STAGE='production'

           deploy $@

       ;;

   branch)

       branch $@

       ;;

   revert)

       STAGE=$2

       revert $@

       ;;      

   backup)

       backup $@

       ;;

   branch)

           branch $@

       ;;

   cron)

       cron $@

       ;;              

   release)

       release $@

       ;;

   clean)

       clean $@

       ;;

   list)

       list $@

       ;;

   log)

       ls -1 $LOGDIR/*

       ;;

   conf)

       conf $@

       ;;              

   *)

       usage

       exit 1


esac