#! /bin/bash
# -*- coding: utf-8 -*-
#
# Backup postgres DB
#
# This free software is released under GNU Affero GPL3
# author: Antonio M. Vigliotti - antoniomaria.vigliotti@gmail.com
# (C) 2015-2023 by SHS-AV s.r.l. - http://www.shs-av.com - info@shs-av.com
#
READLINK=$(which greadlink 2>/dev/null) || READLINK=$(which readlink 2>/dev/null)
export READLINK
# Based on template 2.0.0
THIS=$(basename "$0")
TDIR=$(readlink -f $(dirname $0))
[ $BASH_VERSINFO -lt 4 ] && echo "This script $0 requires bash 4.0+!" && exit 4
if [[ -z $HOME_DEVEL || ! -d $HOME_DEVEL ]]; then
  [[ -d $HOME/odoo/devel ]] && HOME_DEVEL="$HOME/odoo/devel" || HOME_DEVEL="$HOME/devel"
fi
[[ -x $TDIR/../bin/python3 ]] && PYTHON=$(readlink -f $TDIR/../bin/python3) || [[ -x $TDIR/python3 ]] && PYTHON="$TDIR/python3" || PYTHON=$(which python3 2>/dev/null) || PYTHON="python"
[[ -z $PYPATH ]] && PYPATH=$(echo -e "import os,sys\no=os.path\na=o.abspath\nj=o.join\nd=o.dirname\nb=o.basename\nf=o.isfile\np=o.isdir\nC=a('"$TDIR"')\nD='"$HOME_DEVEL"'\nif not p(D) and '/devel/' in C:\n D=C\n while b(D)!='devel':  D=d(D)\nN='venv_tools'\nU='setup.py'\nO='tools'\nH=o.expanduser('~')\nT=j(d(D),O)\nR=j(d(D),'pypi') if b(D)==N else j(D,'pypi')\nW=D if b(D)==N else j(D,'venv')\nS='site-packages'\nX='scripts'\ndef pt(P):\n P=a(P)\n if b(P) in (X,'tests','travis','_travis'):\n  P=d(P)\n if b(P)==b(d(P)) and f(j(P,'..',U)):\n  P=d(d(P))\n elif b(d(C))==O and f(j(P,U)):\n  P=d(P)\n return P\ndef ik(P):\n return P.startswith((H,D,K,W)) and p(P) and p(j(P,X)) and f(j(P,'__init__.py')) and f(j(P,'__main__.py'))\ndef ak(L,P):\n if P not in L:\n  L.append(P)\nL=[C]\nK=pt(C)\nfor B in ('z0lib','zerobug','odoo_score','clodoo','travis_emulator'):\n for P in [C]+sys.path+os.environ['PATH'].split(':')+[W,R,T]:\n  P=pt(P)\n  if B==b(P) and ik(P):\n   ak(L,P)\n   break\n  elif ik(j(P,B,B)):\n   ak(L,j(P,B,B))\n   break\n  elif ik(j(P,B)):\n   ak(L,j(P,B))\n   break\n  elif ik(j(P,S,B)):\n   ak(L,j(P,S,B))\n   break\nak(L,os.getcwd())\nprint(' '.join(L))\n"|$PYTHON)
[[ $TRAVIS_DEBUG_MODE -ge 8 ]] && echo "PYPATH=$PYPATH"
for d in $PYPATH /etc; do
  if [[ -e $d/z0librc ]]; then
    . $d/z0librc
    Z0LIBDIR=$(readlink -e $d)
    break
  fi
done
[[ -z "$Z0LIBDIR" ]] && echo "Library file z0librc not found in <$PYPATH>!" && exit 72
[[ $TRAVIS_DEBUG_MODE -ge 8 ]] && echo "Z0LIBDIR=$Z0LIBDIR"
ZARLIB=$(findpkg zarrc "$PYPATH")
[[ -z "$ZARLIB" ]] && echo "Library file zarrc not found!" && exit 72
. $ZARLIB
[[ $TRAVIS_DEBUG_MODE -ge 8 ]] && echo "ZARLIB=$ZARLIB"
TESTDIR=$(findpkg "" "$TDIR . .." "tests")
[[ $TRAVIS_DEBUG_MODE -ge 8 ]] && echo "TESTDIR=$TESTDIR"
RUNDIR=$(readlink -e $TESTDIR/..)
[[ $TRAVIS_DEBUG_MODE -ge 8 ]] && echo "RUNDIR=$RUNDIR"

# DIST_CONF=$(findpkg ".z0tools.conf" "$PYPATH")
# TCONF="$HOME/.z0tools.conf"
CFG_init "ALL"
link_cfg_def
link_cfg $DIST_CONF $TCONF
[[ $TRAVIS_DEBUG_MODE -ge 8 ]] && echo "DIST_CONF=$DIST_CONF" && echo "TCONF=$TCONF"
get_pypi_param ALL
RED="\e[1;31m"
GREEN="\e[1;32m"
CLR="\e[0m"

__version__=2.0.4


inherit_options() {
    OPTS=
    if [ $opt_ex -gt 0 ]; then
      OPTS=e$OPTS
    fi
    if [ $opt_cron -gt 0 ]; then
      OPTS=K$OPTS
    fi
    if [ $opt_dry_run -gt 0 ]; then
      OPTS=n$OPTS
    fi
    if [ $opt_verbose -gt 0 ]; then
      OPTS=v$OPTS
    fi
    if [ $test_mode -gt 0 ]; then
      OPTS=T$OPTS
    fi
    if [ -n "$opt_user" ]; then
      OPTS="${OPTS}U$opt_user"
    fi
    if [ -n "$OPTS" ]; then
      OPTS=-$OPTS
    fi
    if [ -n "$opt_conf" -a "$opt_conf" != "$TDIR/zar.conf" ]; then
      OPTS="$OPTS -c $opt_conf"
    fi
}


OPTOPTS=(h        c        e      K        l       n            o        R        T         U          V           v)
OPTDEST=(opt_help opt_conf opt_ex opt_cron opt_log opt_dry_run  opt_name opt_repl test_mode opt_user   opt_version opt_verbose)
OPTACTI=("+"      "="      1      1        "="     1            "="      1        1         "="        "*>"        1)
OPTDEFL=(0        ""       0      0        ""      0            ""       0        0         "postgres" ""          0)
OPTMETA=("help"   "file"   ""     "cron"   "file"  "do nothing" "fname"  ""       "test"    "username" "version"   "verbose")
OPTHELP=("this help"\
 "configuration file (def zar.conf)"\
 "exact DB name (rather matches DB name)"\
 "run in cron environment"\
 "log filename (def /var/log/bckdb.log)"\
 "do nothing (dry-run)"\
 "output filename (def dbname-date)"\
 "do not backup but just replica to backup host"\
 "test mode (implies dry-run)"\
 "username (def postgres)"\
 "show version"\
 "verbose mode")
OPTARGS=(dbsel)

parseoptargs "$@"
if [ "$opt_version" ]
then
  echo "$__version__"
  exit 0
fi
if [ $opt_help -gt 0 ]
then
  print_help "Backup postgres DB"\
  "(C) 2015-2023 by zeroincombenze®\nhttp://www.zeroincombenze.it\nAuthor: antoniomaria.vigliotti@gmail.com"
  exit 0
fi
CFG_init

conf_default "bckdb"
if [ $opt_cron -gt 0 ]; then
  detached_login "$@"
fi
link_cfg $FCONF
wlog "=== Starting backup $__version__ by $opt_user ==="

init_vars "$dbsel"
if [ ! -d $DBCKDIR ]; then
  mkdir -p $DBCKDIR
fi
if [ "$BCKFORMAT" == "0" ]; then
  wlog "-- Backupped DBs stored in sql files --"
else
  wlog "-- Backupped DBs stored in compress tar files --"
fi
if [ "$BCK_ENV" == "PRD" ]; then
  wlog "-- Production environment --"
elif [ "$BCK_ENV" == "DEV" ]; then
  wlog "-- Development/backup environment --"
else
  wlog "-- Unique environment w/o dev/backup host --"
fi
wlog "PRD=$HOST_PRD//$URL_PRD"
wlog "DEV=$HOST_DEV//$URL_DEV"
wait_4_prod=$(get_cfg_value 0 wait_4_prod)
((ctr_wait=wait_4_prod/3))
[ $ctr_wait -lt 10 ] && ctr_wait=10
if [ "$BCK_ENV" == "DEV" ]; then
  wlog "WAIT_4_PROD=$wait_4_prod (mins)"
fi
if [ "$BCK_ENV" != "DEV" -a -z "$opt_name" ]; then
  dblist=$(create_db_list_from_pg "$DBSEL" "$PGDIR" "$DBCKDIR" "$REDB")
else
  dblist=$(create_db_list_from_file "$DBSEL" "$PGDIR" "$DBCKDIR" "$REDB")
fi
wlog "- DB to Backup:$dblist"
wlog "-- exclusion list: $EXCL_LIST"
ctr=0
if [ -n "$dblist" ]; then
  inherit_options
  if [ "$BCK_ENV" != "DEV" -a -z "$opt_name" -a $test_mode -eq 0 -a $opt_repl -eq 0 ]; then
    if [ -f $TDIR/zar_purge ]; then
      ZAR_PURGE=$TDIR/zar_purge
    else
      ZAR_PURGE=./zar_purge
    fi
  fi
  pushd $DBCKDIR >/dev/null
  dtc=$(date +%Y%m%d)
  for db in $dblist
  do
    if [ "$BCK_ENV" != "DEV" -o -n "$opt_name" ]; then
      wlog "- Backupping $db ..."
    else
      wlog "- DB $db to receive"
    fi
    if [ -z "$opt_name" ]; then
      if [ -z "$ZAR_PURGE" ]; then
        expand_tar "$db"
      else
        wlog "\$ $ZAR_PURGE $OPTS -i -e $db"
        eval $ZAR_PURGE $OPTS -i -e "'$db'"
      fi
      sqlfname=$DBCKDIR/$db-$dtc.sql
    else
      sqlfname=$opt_name
      if [ -f $sqlfname ]; then
        echo "File $sqlfname already exists!"
        exit 1
      fi
    fi
    if [ "$BCK_ENV" != "DEV" -o -n "$opt_name" ]; then
      run_traced "pg_db_active -k"
      if [ $opt_dry_run -ne 0 -o $opt_repl -ne 0 ]; then
        wlog "> pg_dump $PG_DUMP_OPT -U$opt_user -Fp -f $sqlfname \"$db\""
        [ ${test_mode:-0} -ne 0 ] && touch $sqlfname
      else
        run_traced "pg_dump $PG_DUMP_OPT -U$opt_user -Fp -f $sqlfname \"$db\""
      fi
      if [[ -n $ODOO_FILESTORE_ROOT ]]; then
        filestore=$(for p in $(find $ODOO_FILESTORE_ROOT -maxdepth 2 -type d -name filestore 2>/dev/null); do find $p -maxdepth 2 -type d -name $db; done)
        if [[ -n $filestore ]]; then
          fsfn="$DBCKDIR/$db-filestore.gz"
          if [[ $opt_dry_run -ne 0 ]]; then
            echo "> tar -czf $fsfn $filestore"
          else
            run_traced "tar -czf $fsfn $filestore"
          fi
        fi
      fi
      if [ -z "$opt_name" -a "$BCK_ENV" == "PRD" ]; then
        if [[ $RMTBCKDIR == "/dev/null" ]]; then
          wlog "> scp $sqlfname $URL_DEV:$RMTBCKDIR  # No file copied!"
        else
          rmtfn=$(basename "$sqlfname")
          if [ $opt_dry_run -ne 0 ]; then
            wlog "> scp $sqlfname $URL_DEV:$RMTBCKDIR/$rmtfn"
          else
            run_traced "scp $sqlfname $URL_DEV:$RMTBCKDIR/$rmtfn"
          fi
        fi
      fi
      ((ctr++))
    else
      wlog "Waiting for backup file $sqlfname from production host"
      if [ $opt_dry_run -eq 0 ]; then
        wctr=$ctr_wait
        [ $ctr_wait -gt 10 ] && ((ctr_wait--))
        while [ ! -f $sqlfname -a $wctr -gt 0 ]; do
          sleep 180
          ((wctr--))
        done
      fi
      if [ -f $sqlfname ]; then
        wlog "Received $sqlfname"
        ((ctr++))
      else
        wlog "File $sqlfname not received!"
      fi
    fi
    if [ -z "$opt_name" ]; then
      compress_tar "$db" $sqlfname
    fi
  done
  if [ "$BCK_ENV" != "DEV" -o -n "$opt_name" ]; then
    if [ $opt_dry_run -eq 0 ]; then
      wlog "== $ctr databases are backupped!"
    else
      wlog "== $ctr databases should be backupped!"
    fi
  else
    wlog "== $ctr files received from production!"
  fi
  if [ -z "$opt_name" -a $test_mode -eq 0 ]; then
    if [ -f $TDIR/zar_purge ]; then
      cmd=$TDIR/zar_rest
    else
      cmd=./zar_rest
    fi
    if [ "$BCK_ENV" == "DEV" -o "$REST2" == "1" ]; then
      wlog "\$ $cmd $OPTS"
      eval $cmd $OPTS
    fi
  fi
  popd >/dev/null
fi
exit 0

