#!/bin/bash
# ======================================================================
#
# BACKUP SCRIPTS - CREATE LOCAL DUMPS
#
# ----------------------------------------------------------------------
# ah - Axel Hahn <axel.hahn@iml.unibe.ch>
# ds - Daniel Schueler <daniel.schueler@iml.unibe.ch>
#
# 2016-11-04  ah,ds  created
# 2016-11-10  .....  v1.0
# 2017-03-27  .....  added first param for mode backup|restore
# 2018-02-09  .....  fix: restore-selection of target uses default on return only
# 2021-05-18  .....  move supported backup types to plugins/localdump/[service].sh
# 2021-07-13  .....  remove leading ./ in localdump.sh restore
# ======================================================================



# ----------------------------------------------------------------------
# CONFIG VARS
# ----------------------------------------------------------------------


  . `dirname $0`/jobhelper.sh
  . `dirname $0`/inc_bash.sh
  if [ -r ~/.backup.conf ]; then
    . ~/.backup.conf
  fi

  if [ ! -r "${JOBFILE}" ]; then
    color error
    echo ERROR: missing config file ${JOBFILE}.
    color reset
    exit 1
  fi

  BACKUP_BASEDIR=`_j_getvar ${JOBFILE} "dir-localdumps"`
  BACKUP_PLUGINDIR=`dirname $0`/plugins/localdump

  # check
  if [ -z "$BACKUP_BASEDIR" ]; then
    color error
    echo ERROR: missing config for backup target.
    echo There must be an entry dir-localdumps in ${JOBFILE}
    color reset
    exit 1
  fi

  # CLEANUP AFTER N DAYS...
  typeset -i BACKUP_KEEP_DAYS=`_j_getvar ${JOBFILE} "keep-days"`

  if [ $BACKUP_KEEP_DAYS -eq 0 ]; then
    BACKUP_KEEP_DAYS = 7
  fi


  # ----- additional vars

  BACKUP_DATE=$(/bin/date +%Y%m%d-%H%M)


# ----------------------------------------------------------------------
# FUNCTIONS 4 BACKUP
# ----------------------------------------------------------------------


  # ------------------------------------------------------------
  # cleanup a backup dir: remove old files and delete empty dirs
  function cleanup_backup_target(){
    h3 "CLEANUP ${BACKUP_TARGETDIR} older $BACKUP_KEEP_DAYS days ..."
    if [ -d "${BACKUP_TARGETDIR}" ]; then
      echo find "${BACKUP_TARGETDIR}" -mtime +$BACKUP_KEEP_DAYS -delete -print
      color cmd
      find "${BACKUP_TARGETDIR}" -mtime +$BACKUP_KEEP_DAYS -delete -print
      color reset

      if [ `find "${BACKUP_TARGETDIR}" -type f | wc -l` -eq 0 ]; then
        echo "INFO: the directory is empty - deleting it"
        rm -rf "${BACKUP_TARGETDIR}"
      fi
    else
      echo "SKIP: directory does not exist (no error)"
    fi
  }

  # ------------------------------------------------------------
  # compress a file
  # shared function in localdump_*
  # param  string  filename of uncompressed output file
  function compress_file(){
    echo compressing $1 ...
    gzip -9 -f "${1}"
    fetchrc
  }

  # ------------------------------------------------------------
  # create a backup directory with name of service
  # shared function in localdump_*
  function create_targetdir(){
    mkdir -p "${BACKUP_TARGETDIR}" 2>/dev/null
    if [ ! -d "${BACKUP_TARGETDIR}" ]; then
      color error
      echo FATAL ERROR: directory ${BACKUP_TARGETDIR} was not created
      color reset
      exit 1
    fi
  }


  # ------------------------------------------------------------
  # generate a base filename for backup dump based on on db name
  # ... and added timestamp
  # param  string  name of database schema
  # --> see listBackupedDBs() and guessDB() - these function must be able to split this
  function get_outfile(){
    echo $*__${BACKUP_DATE}
  }

  # ------------------------------------------------------------
  # get name of a service script
  # param  string  name of a service 
  function get_service_script(){
    local _service=$1
    ls -1 ${BACKUP_PLUGINDIR}/${_service}.sh 2>/dev/null
  }

  # ------------------------------------------------------------
  # get a list of existing dumper scripts
  function get_services(){
    #ls -1 `dirname $0`/localdump_* | sed "s#`dirname $0`/localdump_##" | sed "s#\.sh##"
    ls -1 ${BACKUP_PLUGINDIR}/*.sh | sed "s#${BACKUP_PLUGINDIR}/##" | sed "s#\.sh##" | sort
  }

  # ------------------------------------------------------------
  # show directory infos with count of files and used space
  # show used space and count of files and dirs
  function show_info_backup_target(){

    h3 "INFO about backup target ${BACKUP_TARGETDIR}"

    if [ -d "${BACKUP_TARGETDIR}" ]; then
      echo -n "used space: "
      du -hs "${BACKUP_TARGETDIR}"

      echo -n "subdirs   : "
      find "${BACKUP_TARGETDIR}" -type d | wc -l

      echo -n "files     : "
      find "${BACKUP_TARGETDIR}" -type f | wc -l

      echo -n "free space: "
      df -h "${BACKUP_TARGETDIR}" | tail -1 | awk '{ print $4 }'
    else
      echo "SKIP: directory does not exist (no error)"
    fi
    echo

  }

# ----------------------------------------------------------------------
# FUNCTIONS 4 RESTORE
# ----------------------------------------------------------------------


  # ------------------------------------------------------------
  # restore: show databases that can be restored
  # param  string  file filter optional;
  function listBackupedDBs(){
    if [ -d "${BACKUP_TARGETDIR}" ]; then
      cd "${BACKUP_TARGETDIR}"
      if [ -z $1 ]; then
        find -type f | sed "s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g" | grep -v ".meta" | sort -ud| sed "s#^\./##g"
      else
        ls -ltr "$*__"* | sed "s#^\./##g"
      fi
      cd - >/dev/null
    else
      color error
      echo ERROR: ${BACKUP_TARGETDIR} does not exist - here are no backups to restore.
      color reset
      echo
      echo You can try to restore dumps:
      echo "1) Restore dump files from a backup set"
      echo "     `dirname $0`/restore.sh $BACKUP_BASEDIR"
      echo "2) Move restored dumps into $BACKUP_TARGETDIR"
      echo "3) Start database restore again"
      echo "     `dirname $0`/localdump.sh restore"
      echo
 
      exit 1
    fi
  }


  # ------------------------------------------------------------
  # guess name of the database file
  # param  string  filename of db dump; can be full path or not
  function guessDB(){
    dumpfile=$1

    # the metafile is written in sqlite backup to store full path
    metafile=${BACKUP_TARGETDIR}/${dumpfile}.meta
    if [ -f $metafile ]; then
      cat $metafile
    else
      sBasename=`basename $1`
      sDb=`echo ${sBasename} | sed "s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g"`
      if [ -z $sDb ]; then
        color error
        echo ERROR: db name was not detected from file $1
        color reset
        exit 1
      fi
      echo $sDb
    fi
  }


  # ------------------------------------------------------------
  # show help
  # ------------------------------------------------------------
  function showhelp(){
    echo "SYNTAX: "
    echo "`basename $0` [[operation]] [Name_of_service] [[more services]]"
    echo "`basename $0` restore  [Name_of_service] [file-to-restore]"
    echo
    echo "  operation       - one of backup|restore; optional parameter; default is backup"
    echo "  Name_of_service - name of database service"
    echo "                    You get a list of all available services without parameter"
    echo "                    Use ALL for bulk command"
    echo "  file            - filename of db dump to restore"
  }


# ----------------------------------------------------------------------
# INIT
# ----------------------------------------------------------------------

  # . /usr/local/bin/inc_cronfunctions.sh
  j_requireUser "root"

  h1 `date` IML BACKUP :: LOCALDUMP :: $*
  echo Start `date`
  echo

  if [ $# -eq 0 ]; then
    color error
    echo "ERROR: missing parameter."
    color reset
    echo
    showhelp
    echo
    echo "Known services (see ${BACKUP_PLUGINDIR}):"
    get_services
    exit 1
  fi

  mode="backup"
  if [ "$1" = "backup" -o "$1" = "restore" ]; then
    mode=$1
    shift 1
  fi


  if [ "$mode" = "backup" ]; then

    if [ "$1" = "ALL" ]; then
       services=`get_services`
       echo AUTO: calling local backup scripts for all known services
       echo $services
       echo
    else
       services=$*
    fi

    # ----- check all params
    for SERVICENAME in $services
    do
      BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )
      if [ ! -f $BACKUP_SCRIPT ]; then
        color error
        echo ERROR: parameter $SERVICENAME seems to be wrong.
        echo The backup script does not exist: $BACKUP_SCRIPT
        color reset
        echo
        echo services in this folder are:
        get_services
        exit 2
      fi
    done

    # ----- GO
    for SERVICENAME in $services
    do

      BACKUP_TARGETDIR=${BACKUP_BASEDIR}/${SERVICENAME}
      BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )


      # show_info_backup_target


      # ----- start service specific script
      echo
      h2 "START SCRIPT FOR ${SERVICENAME} - $BACKUP_SCRIPT"

      . $BACKUP_SCRIPT $mode

      # ----- post jobs: cleanup
      cleanup_backup_target
      show_info_backup_target

    done
  fi

  if [ "$mode" = "restore" ]; then
    SERVICENAME=$1
    BACKUP_TARGETDIR=${BACKUP_BASEDIR}/${SERVICENAME}
    BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )

    h1 "RESTORE DATABASE"
    if [ -z $2 ]; then

      # ----- file selection

      h2 "select database"
      listBackupedDBs
      color input
      echo -n "name of db to restore >"
      color reset
      read fileprefix
      echo

      h2 "select a specific dump for that database"
      listBackupedDBs $fileprefix
      color input
      echo -n "backupset to import >"
      color reset
      read dbfile
      echo

      color input
      sTargetDb=`guessDB ${dbfile}`
      echo -n "new database name [$sTargetDb] >"
      color reset
      read sTargetDb
      if [ -z $sTargetDb ]; then
        sTargetDb=`guessDB ${dbfile}`
      fi
      echo

      sDumpfile="${BACKUP_TARGETDIR}/${dbfile}"
    else
      sDumpfile=$2
      sTargetDb=$3
    fi
    shift 2
    if [ ! -f "${sDumpfile}" ]; then
      color error
      echo ERROR: ${sDumpfile} is not a file
      color reset
      rc=$rc+1
    else

      . $BACKUP_SCRIPT $mode "${sDumpfile}" "${sTargetDb}"
      if [ $? -ne 0 -o $rc -ne 0 ]; then
        color error
        echo ERROR: $mode failed. See ouput above. :-/
        color reset
      else
        color ok
        echo OK, $mode was successful.
        color reset
      fi

    fi
  fi


  echo _______________________________________________________________________________


  echo STATUS $0 exit with final returncode rc=$rc
  exit $rc

# ----------------------------------------------------------------------