#! /bin/bash
# -*- coding: utf-8 -*-
# Execute now a selected statement from crontab
# Tool for test cron
#
# author: Antonio M. Vigliotti - antoniomaria.vigliotti@gmail.com
# (C) 2015-2021 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"

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.10

CRONTAB_SAVED=~/$THIS.crontab
CRONTAB_TMP=~/$THIS.crontab.$$.tmp
CRONTAB_TMP2=~/$THIS.crontab.$$_2.tmp
VIM_RC=~/$THIS.vim


extract_cmdline() {
    local cronline=$(grep "$opt_sel" $CRONTAB_SAVED|head -n1)
    local SUBM_TIME=$(date +"%H:%M" -d"+1 minutes")
    local SUBM_HH=$(echo $SUBM_TIME|awk -F: '{print $1}')
    local SUBM_MM=$(echo $SUBM_TIME|awk -F: '{print $2}')
    SK_CMD=
    SK_RCMD=
    SKTIME=
    local i=0
    for i in {1..19}; do
      if [ $i -eq 1 ]; then
        SK_CMD="$SUBM_MM"
        SKTIME="$SUBM_MM"
      elif [ $i -eq 2 ]; then
        SK_CMD="$SK_CMD $SUBM_HH"
        SKTIME="$SKTIME $SUBM_HH"
      else
        local p=$(echo "$cronline"|awk '{print $'$i'}')
        SK_CMD="$SK_CMD $p"
      fi
    done
    FQN_THIS=$(readlink -f $0)
    SK_RCMD="$SKTIME * * * SHELL=/bin/bash $FQN_THIS -R"
}

cron_wait() {
    local sts=0
    local cronline=$(crontab -l|grep "$FQN_THIS -R"|head -n1)
    if [ -n "$cronline" ]; then
      local SUBM_TIME=$(echo "$cronline"|awk '{print $2":"$1}')
    fi
    local wctr=20
    while [ -n "$cronline" -a $wctr -gt 0 ]; do
      local NOW_TIME=$(date +"%H:%M")
      echo "$NOW_TIME waiting for cron activation ($SUBM_TIME), please do not execute crontab command! $REM"
      sleep 6
      cronline=$(crontab -l|grep "$FQN_THIS -R"|head -n1)
      ((wctr--))
    done
    if [ $wctr -eq 0 ]; then
      sts=1
    fi
    return $sts
}

cron_list() {
    if [ -f $CRONTAB_SAVED ]; then
      cat $CRONTAB_SAVED
      echo "****************************************************************************"
      echo "$THIS is waiting for cron activation, please do not execute crontab command!"
    else
      crontab -l
    fi
    return $?
}

cron_runow() {
    local sts=0
    local del_saved=0
    if [ -f $CRONTAB_SAVED ]; then
      if [ $opt_force -eq 0 ]; then
        echo "$THIS already running or previous crashed execution"
        echo "Use -f for run after previous crash"
        return 1
      fi
    else
      crontab -l >$CRONTAB_SAVED
      if [ $opt_dry_run -gt 0 ]; then
        del_saved=1
      fi
    fi
    extract_cmdline
    cronline="$SK_CMD"
    if [ $opt_edit -eq 0 ]; then
      if [ $opt_dry_run -gt 0 ]; then
        echo "crontab statement simulated by DRY_RUN:"
        echo "$cronline"
      else
        cp $CRONTAB_SAVED $CRONTAB_TMP
        echo "$SK_CMD">>$CRONTAB_TMP
        echo "$SK_RCMD">>$CRONTAB_TMP
        if [ $opt_verbose -gt 0 ]; then
          echo "crontab statement added:"
          echo "$cronline"
        fi
        cat $CRONTAB_TMP|crontab
        sts=$?
      fi
    else
      if [ $opt_dry_run -eq 0 ]; then
        echo "GA">$VIM_RC
        echo "$SK_CMD">>$VIM_RC
        echo "$SK_RCMD">>$VIM_RC
        echo -e "\e">>$VIM_RC
        echo ":w!q">>$VIM_RC
        # VISUAL="vim -s $VIM_RC" crontab -e
        EDITOR="vim -s $VIM_RC" crontab -e
        sts=$?
      fi
    fi
    if [ $sts -eq 0 -a $opt_dry_run -eq 0 ]; then
      crontab -l >$CRONTAB_TMP
      diff -qr $CRONTAB_SAVED $CRONTAB_TMP &>/dev/null
      sts=$?
      if [ $sts -eq 0 ]; then
        sts=1
      else
        sts=0
      fi
    fi
    if [ $sts -ne 0 ]; then
      echo "Warning: crontab does not accept new jobs!!"
    fi
    if [ $del_saved -gt 0 ]; then
      rm -f $CRONTAB_SAVED
    fi
    return $sts
}

cron_recover() {
    local sts=0
    if [ -f $CRONTAB_SAVED ]; then
      if [ $opt_dry_run -eq 0 ]; then
        crontab -l >$CRONTAB_TMP
        head $CRONTAB_TMP -n-2>$CRONTAB_TMP2
        mv -f $CRONTAB_TMP2 $CRONTAB_TMP
        diff -qr $CRONTAB_SAVED $CRONTAB_TMP &>/dev/null
        sts=$?
        if [ $sts -eq -0 ]; then
          cat $CRONTAB_SAVED|crontab
          rm -f $CRONTAB_SAVED
        else
          echo "**********************************************"
          echo "Warning: crontab schedulation was modified during execution"
          echo "---- Initial crontab ----"
          cat $CRONTAB_SAVED
          echo "---- Current crontab ----"
          cat $CRONTAB_TMP
          echo "-------------------------"
          if [ "$opt_action" != "-e" ]; then
            echo "run '$THIS -e' to restore correct values"
          fi
          sts=1
        fi
        if [ "$opt_action" == "-e" ]; then
          read
          echo "G">$VIM_RC
          echo "dd">>$VIM_RC
          echo "dd">>$VIM_RC
          echo ":w!q">>$VIM_RC
          # VISUAL="vim -s $VIM_RC" crontab -e
          EDITOR="vim -s $VIM_RC" crontab -e
          sts=$?
          if [ -f "$CRONTAB_SAVED" ]; then
            rm -f $CRONTAB_SAVED
          fi
        fi
      fi
    elif [ "$opt_action" == "-e" ]; then
      crontab -e
      sts=$?
    fi
    return $sts
}

cron_clean() {
    if [ -f $CRONTAB_TMP ]; then
      rm -f $CRONTAB_TMP
    fi
    if [ -f $VIM_RC ]; then
      rm -f $VIM_RC
    fi
}

OPTOPTS=(h        e        f         l          n            R          s       V           v           w)
OPTDEST=(opt_help opt_edit opt_force opt_action opt_dry_run  opt_action opt_sel opt_version opt_verbose opt_wait)
OPTACTI=("+"      "1>"     1         "*>"       "1>"         "*>"       "=>"    "*>"        1           "1>")
OPTDEFL=(1        0        0         ""         0            ""         "^$"    ""          0           0  )
OPTMETA=("help"   "edit"   "force"   "list"     "do nothing" "rollbck"  "regex" "version"   "verbose"   "wait")
OPTHELP=("this help"\
 "edit crontab [after selection or crash]"\
 "force execution after crash"\
 "list crontab entries"\
 "do nothing (dry-run)"\
 "rollbak from cron execution (never use this option!)"\
 "select statement to execute now"\
 "show version"\
 "verbose mode"\
 "wait for job activation")
OPTARGS=()

parseoptargs "$@"
if [[ "$opt_version" ]]; then
  echo "$__version__"
  exit 0
fi
if [[ $opt_help -gt 0 ]]; then
  print_help "Run now a selected cron statement from crontab"\
  "(C) 2015-2021 by zeroincombenze®\nhttp://wiki.zeroincombenze.org/en/Linux/dev\nAuthor: antoniomaria.vigliotti@gmail.com"
  exit 0
fi
if [ -z "$opt_action" ]; then
  if [ "$opt_sel" != "^\$" ]; then
    opt_action="--"
  elif [ $opt_edit -ne 0 ]; then
    opt_action="-e"
  elif [ $opt_wait -gt 0 ]; then
    opt_action="-w"
  fi
fi
if [ "$opt_action" == "-l" ]; then
  cron_list
  sts=$?
elif [ "$opt_action" == "--" ]; then
  cron_runow
  sts=$?
  if [ $sts -eq 0 -a $opt_wait -gt 0 ]; then
    cron_wait
  fi
elif [ "$opt_action" == "-R" -o "$opt_action" == "-e" ]; then
  cron_recover
  sts=$?
elif [ "$opt_action" == "-w" ]; then
  cron_wait
  sts=$?
else
  print_help "Submit now to crontab a selected cron statement"\
  "(C) 2015-2021 by zeroincombenze®\nhttp://wiki.zeroincombenze.org/en/Linux/dev\nAuthor: antoniomaria.vigliotti@gmail.com"
  sts=1
fi
cron_clean
exit $sts
