#!/bin/bash
# shell wrapper for python script and autogenerated shell script
# idea from: http://www.linuxjournal.com/content/add-binary-payload-your-shell-scripts
CONF=`dirname $0`/delivery-check.conf
while true; do
  getopts "f:htdvyxcsp" OPT
  if [ $OPT = "f" ]; then
    CONF=$OPTARG
    break
  elif [ $OPT = "?" ]; then
    break
  fi
done
if [ -f $CONF ]; then
  . $CONF
  export CONF_REPO_URL CONF_REPO_BRANCH CONF_CHECK_PATH CONF_WITH_DOXYGEN CONF_WITH_TCL
  export CONF_TCL_CONFIG CONF_WITH_VERILOG CONF_SHOW_COMMIT_MAX CONF_EXTRA_LIBS 
  export CONF_CXXFLAGS CONF_WITH_PYTHON CONF_WITH_BROWSER_RESULT
else
  echo "error: config file not found: $CONF"
  echo "       try $0 -h to get help"
  exit 1
fi
match=$(grep --text --line-number '^PAYLOAD:$' $0 | cut -d ':' -f 1)
payload_start=$((match + 1))
scriptname=`mktemp -t delivery-check.XXXXXXXXXXXX`
if [ ! $? = 0 ]; then echo "error: mktemp not found or can't create temp file"; exit 1; fi
tail -n +$payload_start $0 | python - $scriptname $*
if [ $? = 0 -a -f $scriptname ]; then
  chmod 755 $scriptname
  $scriptname
  rm $scriptname
fi
exit 0
PAYLOAD:
# Python script
import sys
import os
import optparse
if sys.version_info[0] == 3:
  import io
else:
  import StringIO as io

def readArgs():
  def _f(flg):
    if flg: return "y"
    return "n"
  usage = """usage: delivery-check.sh [options] [sel-commit]

sel-commit: commit to use, it resets cloned repo to the selected number of commits BACK to find errors.
            See option -s for available commits! If this parameter isn't given, HEAD revision is used for check.

Default config file is "delivery-check.conf" in script directory. See option "-f" for selecting other config
file."""
  try:
    s = int(os.environ.get("CONF_SHOW_COMMIT_MAX"))
  except:
    s = 20
  p = optparse.OptionParser(usage = usage)
  p.add_option("-f", action = "store", dest = "conffile", default = None,
                     help = "use other config file instead of default")
  p.add_option("-d", action = "store_false", dest = "distcheck", default = True,
                     help = "disable dist check")
  p.add_option("-t", action = "store_false", dest = "buildtcl", default = True,
                     help = "disable build/install tcl module (if configured!)")
  p.add_option("-p", action = "store_false", dest = "buildpython", default = True,
                     help = "disable build/install python module")
  p.add_option("-v", action = "store_false", dest = "buildverilog", default = True,
                     help = "disable build/install verilog module (if configured!)")
  p.add_option("-y", action = "store_false", dest = "builddoxygen", default = True,
                     help = "disable build/install doxygen doc (because it needs time to build)")
  p.add_option("-x", action = "store_true", dest = "buildsphinx", default = False,
                     help = "build also sphinx and web docu (usefull combined with -n to not to delete it after creating!)")
  p.add_option("-c", action = "store_true", dest = "delworkarea", default = False,
                     help = "removes workarea, if exist, without question. Be carefull!")
  p.add_option("-s", action = "store_true", dest = "showcommit", default = False,
                     help = "shows last %d commits (for selecting a commit to check)" % s)
  opts, args = p.parse_args(sys.argv[1:])
  if len(args) < 1 or len(args) > 2: p.error("argument script name expected or to much arguments")
  opts.script = args[0]
  opts.selcommit = None
  if len(args) == 2:
    try:
      v = int(args[1])
      if v > 0 and v <= 99: opts.selcommit = v
    except:
      pass
  opts.commitmax = s
  v = os.environ.get("CONF_WITH_DOXYGEN", None)
  if v is None or v is not "y": opts.builddoxygen = False
  v = os.environ.get("CONF_REPO_URL", None)
  if v is None or len(v) == 0: p.error("setting CONF_REPO_URL in delivery-check.conf expected")
  opts.cloneurl = v
  v = os.environ.get("CONF_REPO_BRANCH", None)
  if v is None or len(v) == 0: v = "master"
  opts.clonebranch = v
  v = os.environ.get("CONF_CHECK_PATH", None)
  if v is None or len(v) == 0: p.error("setting CONF_CHECK_PATH in delivery-check.conf expected")
  opts.checkpath = v
  v = os.environ.get("CONF_WITH_VERILOG", None)
  if v is None or v is not "y": opts.buildverilog = False
  v = os.environ.get("CONF_WITH_PYTHON", None)
  if v is "n": opts.buildpython = False
  opts.tclpath = os.environ.get("CONF_TCL_CONFIG", None)
  v = os.environ.get("CONF_WITH_TCL", None)
  if v is None or v is not "y" or not opts.tclpath: opts.buildtcl = False
  opts.extralibs = os.environ.get("CONF_EXTRA_LIBS", None)
  opts.cxxflags = os.environ.get("CONF_CXXFLAGS", None)
  opts.display_html = True
  v = os.environ.get("CONF_WITH_BROWSER_RESULT", None)
  if v is not None and v is not "y": opts.display_html = False
  opts.fmtdict = dict(
    wa = opts.checkpath,
    maxc = opts.commitmax,
    url = opts.cloneurl,
    br = opts.clonebranch,
    sel = opts.selcommit,
    o_dist = _f(opts.distcheck),
    o_tcl = _f(opts.buildtcl),
    o_python = _f(opts.buildpython),
    o_verilog = _f(opts.buildverilog),
    o_sphinx = _f(opts.buildsphinx),
    o_doxy = _f(opts.builddoxygen),
  )
  return opts

_text_func_wh = """function writehtml() {
  # write global data
  echo "[global]" >> %(wa)s/log/log.cfg
  echo "output=%(wa)s/log" >> %(wa)s/log/log.cfg
  echo "repo-work=%(wa)s/repo" >> %(wa)s/log/log.cfg
  echo "versions=%(wa)s/repo/check-versions.out" >> %(wa)s/log/log.cfg
  echo "repo=%(url)s" >> %(wa)s/log/log.cfg
  echo "branch=%(br)s" >> %(wa)s/log/log.cfg
  echo "start=$LOG_DATE_START" >> %(wa)s/log/log.cfg
  date "+end=%%Y/%%m/%%d/%%H/%%M/%%S" >> %(wa)s/log/log.cfg
  echo "steps=$LOG_STEPS" >> %(wa)s/log/log.cfg  
  echo "opt-tcl=%(o_tcl)s" >> %(wa)s/log/log.cfg  
  echo "opt-python=%(o_python)s" >> %(wa)s/log/log.cfg  
  echo "opt-dist=%(o_dist)s" >> %(wa)s/log/log.cfg  
  echo "opt-verilog=%(o_verilog)s" >> %(wa)s/log/log.cfg  
  echo "opt-sphinx=%(o_sphinx)s" >> %(wa)s/log/log.cfg  
  echo "opt-doxy=%(o_doxy)s" >> %(wa)s/log/log.cfg  
  echo "conf-tcl=%(o_tcl)s" >> %(wa)s/log/log.cfg  
  echo "conf-doxy=%(o_doxy)s" >> %(wa)s/log/log.cfg  
  echo "conf-verilog=%(o_verilog)s" >> %(wa)s/log/log.cfg  
  echo "status-repo=%(wa)s/log/status.log" >> %(wa)s/log/log.cfg
  echo "commit-repo=%(wa)s/log/commit.log" >> %(wa)s/log/log.cfg
  if [ "$1" == "ok" ]; then
    echo "result=success" >> %(wa)s/log/log.cfg
  else
    echo "result=failed" >> %(wa)s/log/log.cfg
    echo "failed-step=$1" >> %(wa)s/log/log.cfg
  fi
  # if python exists, create html files
  python %(wa)s/repo/doc/log2html.py %(wa)s/log/log.cfg
  R=$?
"""

_text_func_wh_nodisp = """  # not displaying created html, do zip results instead
  echo "create result.tar.gz ..."
  (cd %(wa)s; tar czf result.tar.gz inst repo log)
}

"""
_text_func_wh_linux = """  # if xdg-open exists, open browser
  C=`which xdg-open`
  if [ ! -z "$C" -a $R == 0 ]; then
    $C %(wa)s/log/index.html
  fi
}

"""
_text_func_wh_msys = """  # open default browser
  cmd << EOT
start file:///%(wa)s/log/index.html
exit
EOT
}

"""
_text_func_wh_darwin = """  # open default browser
  cmd << EOT
open file:///%(wa)s/log/index.html
exit
EOT
}

"""

_text_del_wa_1 = """# delete workarea, if exists
echo "Workarea path: '%(wa)s'"
rm -rf %(wa)s

"""

_text_del_wa_2 = """# delete workarea, if exists
echo "Workarea path: '%(wa)s'"
if [ -f %(wa)s -o -d %(wa)s ]; then
  read -p "Workarea exists! Remove workarea? [Ny] " Q
  if [ "$Q" == "y" ]; then
    rm -rf %(wa)s
  else
    echo "workarea not removed"
    exit 2
  fi
fi

"""

_text_cr_wa = """# create workarea
mkdir -p %(wa)s/repo %(wa)s/inst %(wa)s/dist %(wa)s/log

# start date and time
LOG_DATE_START=`date "+%%Y/%%m/%%d/%%H/%%M/%%S"`
LOG_CONFIG=%(wa)s/log/log.cfg
LOG_STEPS="clone"

# clone repository
echo "clone repository ..."
pushd %(wa)s > /dev/null
git clone %(url)s -b %(br)s repo 2>&1 | tee %(wa)s/log/clone.log
popd > /dev/null
LOG_DATE_CLONE=`date "+%%Y/%%m/%%d/%%H/%%M/%%S"`

"""

_text_show_cmt = """pushd %(wa)s/repo > /dev/null
echo ""
echo "Last %(maxc)d commits in repo:"
git log --format=oneline | head -%(maxc)d | awk '{print NR,$0}'
popd > /dev/null
rm -rf %(wa)s
exit 0

"""

_text_reset_repo = """pushd %(wa)s/repo > /dev/null
SELCOMMIT=`git log --format=oneline | head -%(sel)d | tail -1 | cut "-d " -f1`
git reset --hard $SELCOMMIT >> %(wa)s/log/clone.log
popd > /dev/null

"""

_text_before_1 = """pushd %(wa)s/repo > /dev/null
git status -s > %(wa)s/log/status.log
git log -1 > %(wa)s/log/commit.log
echo "[clone]" >> %(wa)s/log/log.cfg
echo "start=$LOG_DATE_START" >> %(wa)s/log/log.cfg
echo "end=$LOG_DATE_CLONE" >> %(wa)s/log/log.cfg
echo "cmd=git clone %(url)s -b %(br)s repo" >> %(wa)s/log/log.cfg
echo "log=%(wa)s/log/clone.log" >> %(wa)s/log/log.cfg
echo "" >> %(wa)s/log/log.cfg

echo "run bootstrap and configure ..."
"""

_text_run_and_test = """echo "[%(name)s]" >> %(wa)s/log/log.cfg
echo "log=%(wa)s/log/%(name)s.log" >> %(wa)s/log/log.cfg
echo "cmd=%(cmd)s" >> %(wa)s/log/log.cfg
TMPNAME=`mktemp -t delivery-check.XXXXXXXXXXXX`
date "+start=%%Y/%%m/%%d/%%H/%%M/%%S" >> %(wa)s/log/log.cfg
(%(cmd)s 2>&1; echo $? >> $TMPNAME) | tee %(wa)s/log/%(name)s.log
date "+end=%%Y/%%m/%%d/%%H/%%M/%%S" >> %(wa)s/log/log.cfg
RES=`cat $TMPNAME`
rm -f $TMPNAME
echo "result=$RES" >> %(wa)s/log/log.cfg
echo "" >> %(wa)s/log/log.cfg
LOG_STEPS="$LOG_STEPS %(name)s"
"""

_text_run_and_test_2 = """if [ ! $RES = 0 ]; then
  writehtml %(name)s
  echo "'%(name)s' finished with exit code not equal 0 ($RES)"
  exit 3
fi

"""

_text_run_and_test_3 = """if [ ! $RES = 0 -a ! $RES = %(extrares)s ]; then
  writehtml %(name)s
  echo "'%(name)s' finished with exit code not equal 0 or %(extrares)s ($RES)"
  exit 3
fi

"""

def runAndTest(hdl, cmd, name, allowedResult = None):
  d = dict(cmd = cmd, name = name)
  d.update(hdl.opts.fmtdict)
  hdl.write(_text_run_and_test % d)
  if allowedResult is not None:
    d["extrares"] = str(allowedResult)
    hdl.write(_text_run_and_test_3 % d)
  else:
    hdl.write(_text_run_and_test_2 % d)

_text_configure_test = """echo "[%(name)s]" >> %(wa)s/log/log.cfg
echo "log=%(wa)s/log/%(name)s.log" >> %(wa)s/log/log.cfg
echo "cmd=%(cmd)s" >> %(wa)s/log/log.cfg
TMPNAME=`mktemp -t delivery-check.XXXXXXXXXXXX`
date "+start=%%Y/%%m/%%d/%%H/%%M/%%S" >> %(wa)s/log/log.cfg
(%(cmd)s 2>&1; echo $? >> $TMPNAME) | tee %(wa)s/log/%(name)s.log
date "+end=%%Y/%%m/%%d/%%H/%%M/%%S" >> %(wa)s/log/log.cfg
RES=`cat $TMPNAME`
rm -f $TMPNAME
echo "result=$RES" >> %(wa)s/log/log.cfg
echo "" >> %(wa)s/log/log.cfg
LOG_STEPS="$LOG_STEPS %(name)s"
if [ ! $RES = 0 ]; then
  writehtml %(name)s
  echo "'%(name)s' finished with exit code not equal 0 ($RES)"
  exit 4
fi

"""

def runConfigure(hdl, name):
  cmd = "./configure --prefix=/usr"
  if hdl.opts.buildpython: cmd += " --enable-python"
  if hdl.opts.buildtcl: cmd += " --with-tclconfig=%s" % hdl.opts.tclpath
  if hdl.opts.builddoxygen: cmd += " --enable-doxygen-doc"
  if hdl.opts.buildverilog: cmd += " --enable-verilog"
  if not hdl.opts.extralibs is None: cmd += ' EXTRA_LIBS="%s"' % hdl.opts.extralibs
  if not hdl.opts.cxxflags is None: cmd += ' CXXFLAGS="%s"' % hdl.opts.cxxflags
  d = dict(cmd = cmd, name = name)
  d.update(hdl.opts.fmtdict)
  hdl.write(_text_configure_test % d)

_text_dist = """pushd %(wa)s/dist > /dev/null
tar xzf ../repo/simulavr-*.tar.gz
pushd simulavr* > /dev/null
echo "dist: run bootstrap and configure ..."
"""

_text_end = """writehtml "ok"
echo "****** successfull *******"
exit 0
"""

class TXT(object):

  def __init__(self, opts):
    self.__s = io.StringIO()
    self.__opts = opts

  @property
  def opts(self): return self.__opts

  def getvalue(self): return self.__s.getvalue()

  def write(self, s): self.__s.write(s)
  def writeln(self, s): self.__s.write(s + "\n")
  def writeText(self, t): self.__s.write(t % self.__opts.fmtdict)

if __name__ == "__main__":

  # read arguments
  opts = readArgs()

  # create script
  s = TXT(opts)
  s.writeText(_text_func_wh)
  if opts.display_html:
    if sys.platform in ("win32", "cygwin"):
      s.writeText(_text_func_wh_msys)
    elif sys.platform == "darwin":
      s.writeText(_text_func_wh_darwin)
    else:
      s.writeText(_text_func_wh_linux)
  else:
    s.writeText(_text_func_wh_nodisp)
  if opts.delworkarea:
    s.writeText(_text_del_wa_1)
  else:
    s.writeText(_text_del_wa_2)
  s.writeText(_text_cr_wa)
  if opts.showcommit:
    s.writeText(_text_show_cmt)
  else:
    if opts.selcommit is not None: s.writeText(_text_reset_repo)
    s.writeText(_text_before_1)
    runAndTest(s, "./bootstrap", "bootstrap")
    runConfigure(s, "configure")
    s.write('echo "run make, make check and make dist ..."\n')
    runAndTest(s, "make", "make")
    runAndTest(s, "make check", "check")
    if opts.builddoxygen:
      runAndTest(s, "make doxygen-doc", "doxygen")
    if opts.buildsphinx:
      runAndTest(s, "make sphinx-doc", "sphinx")
      runAndTest(s, "make web-html", "sphinx-web")
    runAndTest(s, "make dist", "dist")
    s.write('echo "run make install ..."\n')
    runAndTest(s, "make DESTDIR=%s/inst install" % opts.checkpath, "install")
    runAndTest(s, "make DESTDIR=%s/inst install-info" % opts.checkpath, "install-info")
    runAndTest(s, "make DESTDIR=%s/inst install-pdf" % opts.checkpath, "install-pdf", 2)
    runAndTest(s, "make DESTDIR=%s/inst install-html" % opts.checkpath, "install-html")
    if opts.builddoxygen:
      runAndTest(s, "make DESTDIR=%s/inst install-doxygen" % opts.checkpath, "install-doxy")
    if opts.buildverilog:
      runAndTest(s, "make DESTDIR=%s/inst install-vpi" % opts.checkpath, "install-vpi")
    s.write("popd > /dev/null\n")
    if opts.distcheck:
      s.writeText(_text_dist)
      runAndTest(s, "./bootstrap", "dist-bootstrap")
      runConfigure(s, "dist-configure")
      s.write('echo "dist: run make, make check and make dist ..."\n')
      runAndTest(s, "make", "dist-make")
      runAndTest(s, "make check", "dist-check")
      runAndTest(s, "make dist", "dist-dist")
      s.write("popd > /dev/null\npopd > /dev/null\n")
    s.writeText(_text_end)

  # write script and return
  f = open(opts.script, "w")
  f.write("#!/bin/bash\n")
  f.write(s.getvalue())
  f.write("# EOF\n")
  f.close()
  sys.exit(0)

# EOF
