#! /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 -- will cat the file on stdout # path -- 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