#! /bin/bash

# GRIXEC--minimalistic user-level batch middleware
# Copyright (c) 2011 Alexandru Dan Corlan MD PhD (http://dan.corlan.net)
# this program is covered by the GNU General Public Licence version 3

# WELCOME TO GRIXEC, a set of minimalistic tools to run unix
# computational commands persistenly, that is to run commands that
# read data files and produce result file with the preservation of the
# command and the files. GRIXEC is meant as an experiment in order
# to gather the specification of a simpler, unified user interface to
# batch processing facilities, large and small, local or distributed

# HOME PAGE (and USER MANUAL):
# http://dan.corlan.net/software/grixec.html
# 
# RELEASE HISTORY:
# V0.1 -- June 27, 2011 -- basic functionality
#
# INSTALLING:
# download this file, named grixall, then
#
#   chmod a+x ./grixall
#   sudo ./grixall install
#
# this will install this file and a few links to it (gxec, gxac, gxay)
# in the /usr/local/bin directory; use the links as the user commands;
# change the INSTALLDIR variable below to install in another directory

INSTALLDIR=/usr/local/bin

jcount () {
    printf J%03d `ls data | wc -w`
}

grixec () {

    USAGE="Usage: grixec -c file* [-m user@machine] -x cmd arg*"
    PROJDIR=`pwd`
    THECALL="$@"
    JOBID=`uuid`
    
    if [ $1 != -c ]
    then echo $USAGE
	exit 33
    fi
    
    shift
    
    if [ $# -eq 0 ]
    then echo $USAGE
	exit 33
    fi
    
    mkdir -p ~/grixome
    mkdir -p ~/grixome/$JOBID
    mkdir -p ./data

    JNAME=`jcount`
    echo $JNAME $JOBID
    
    ln -sf ~/grixome/$JOBID data/$JNAME
    
    MACHINE="local"
    
    while [ $1 != -x  ] ; do
	if [ $1 == -m ] ; then
	    MACHINE=$2
	    shift; shift
	else
	    cp $1 ~/grixome/$JOBID
	    shift
	    if [ $# -eq 0 ]
	    then exit
	    fi
	fi
    done
    
    gxay dict jobnamed $JOBID $JNAME
    gxay dict joblink $JNAME $JOBID
    
    gxay $JNAME id $JNAME $JOBID
    gxay $JNAME projdir $JNAME $PROJDIR
    gxay $JNAME call $JNAME \"grixec $THECALL\"
    gxay $JNAME created $JNAME \"`date`\"
    gxay $JNAME by $JNAME $USER
    gxay $JNAME machine $JNAME $MACHINE
    gxay $JNAME runfrom $JNAME `hostname`
    
    shift
    cd ~/grixome/$JOBID
    echo "#! /bin/bash
# this script was automatically generated by grixec
# caled at: " `date` " 
# with: grixec $THECALL
# from project directory: $PROJDIR
# project-specific name: $JNAME
" $@ "
echo DONE > status
" >grixrun 

    chmod u+x grixrun

# run
    
    echo $MACHINE >machine
    
    if [ $MACHINE == "local" ] ; then
	exec /usr/bin/time -o timings `pwd`/grixrun >stdout.log 2>stderr.log &
	echo RUNNING >status
    else
	ssh $MACHINE "mkdir -p grixome"
	echo RUNNING >status
	scp -r `pwd` $MACHINE:grixome
	REMWD=`ssh $MACHINE "cd grixome/$JOBID; pwd"`
	ssh -n $MACHINE "cd grixome/$JOBID ; /usr/bin/time -o timings $REMWD/grixrun >stdout.log 2>stderr.log" 
	ST="RUNNING"
	until [ $ST == "DONE" ] ; do
	    sleep 2
	    ST=`ssh $MACHINE "cd grixome/$JOBID; cat status"`
	    echo $ST
	done
	scp -r $MACHINE:grixome/$JOBID/* .
    fi

}


UUIDPAT=[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]

grixacc.usage () {
    echo "Usage: grixacc a b c d e ..."
    echo "(where a, b, ... are increasingly specialised data locators)"
    echo "see the command source for details (more `which grixacc`)"
}

jobid () {
  ls -l data/$1 |  sed "s/.*\($UUIDPAT\).*/\1/"
}

dictassoc () {
  HDSTR="($2 $3 "
  grep "$HDSTR" $1 | tail -c +${#HDSTR} | tail -c +2
}

subfile () {
  FBN=`basename $1`
  if [ $1 == "dict" ] ; then
    dictassoc $1 $2 $3
    return
  fi
  if [ $FBN == "dict" ] ; then
    if [ -z $3 ] ; then
       FDN=`dirname $1`
       dictassoc $1 $2 `basename $FDN`
    else
       dictassoc $1 $2 $3
    fi
    return
  fi
}

synoptic() {
  echo $1 `jobid $1` `cat data/$1/status` `cat data/$1/machine`
}

# Usage: grixacc a b c d e ...
# 
# grixacc last jobdataspec... -- data for the latest started job from the current project
# grixacc loclist -- list of the current project jobs and their status
# grixacc job Jnnn jobdataspec... -- data for (local) job Jnnn
#
# jobdataspec... can be:
#   file <filename>  -- will cat the file on stdout
#   path <filename> -- will produce the pathname to the respective file of the job
#                   -- or the path to the respective job

jobdataspec () {
  if [ $# -lt 2 ] ; then
    echo $1
    return
  fi
  if [ $2 == "ls" ] ; then
    ls data/$1
    return
  fi
  if [ $2 == "id" ] ; then
    jobid $1
    return
  fi
  if [ $2 == "prjid" ] ; then
    echo $1
    return
  fi
  if [ $2 == "syno" ] ; then
    synoptic $1 
  fi
  if [ $2 == "format" ] ; then
    JID=$1
    shift ; shift
    for j in $@ ; do
      grixacc $JID $j
    done
  fi
  if [ -a data/$1/$2 ] ; then
    DAFILE="data/$1/$2"
    if [ $# -eq 2 ] ; then
      cat $DAFILE
    else
      shift ; shift
      subfile $DAFILE $@
    fi
    return
  else # we assume it is something related to the dictionary of the job
    DAFILE=data/$1/dict
    shift
    subfile $DAFILE $@
  fi
}

grixacc () {

    if [ $# -lt 1 ] ; then
	grixacc.usage
	exit 1
    fi
    
    if [ $1 == "last" ] ; then
	LASTJ=`ls -td data/J* | head -n 1`
	shift
	jobdataspec `basename $LASTJ` $@
    elif [ $1 == "dict" ] ; then
	shift
	subfile data/dict $@
    elif [ $1 == "all" ] ; then
	shift
	for i in `ls -td data/J*` ; do
	    jobdataspec `basename $i` $@
	done
    else
	jobdataspec $@
    fi

}

grixay () {

if [ $1 == "dict" ]; then
  shift
  echo '('$@ >> data/dict
  echo '  )' >> data/dict
  exit
fi

if [ $1 == "last" ] ; then
  LASTJ=`ls -t data | head -n 1`
  shift
  echo '('$@ >> data/$LASTJ/dict
  echo '  )' >> data/$LASTJ/dict
  exit
fi

LASTJ=$1
shift
echo '('$@ >> data/$LASTJ/dict
echo '  )' >> data/$LASTJ/dict

}



case `basename $0` in
grixall)
  if [ $1 == "install" ] ; then
      	cp grixall $INSTALLDIR
	chmod a+x $INSTALLDIR/grixall
	ln -sf $INSTALLDIR/grixall $INSTALLDIR/gxec
	ln -sf $INSTALLDIR/grixall $INSTALLDIR/gxac
	ln -sf $INSTALLDIR/grixall $INSTALLDIR/gxay
  fi
  ;;
gxec)
  grixec $@ 
  ;;
gxay)
  grixay $@
  ;;
gxac)
  grixacc $@
  ;;
esac

