#!/bin/bash

TIME="time_real %e : time_user %U : time_sys %S\nmem_avg %K : mem_max %M : mem_faults_major %F : mem_faults_minor %R\nio_fsin %I : io_fsout %O : io_sockin %r : io_sockout %s : io_signals %k\nexit: %x"
DISCOROOT=/var/disco
RSYNC=$(disco-param get disco/client/cmds/rsync || exit 1)
SERVERURI=$(disco-param get disco/server/uri || exit 1)
STORAGE=$(disco-param get disco/client/storage 2>/dev/null || echo "/var/disco/localstore")
mkdir -p ${STORAGE}
mkdir -p ${DISCOROOT}/reports/_internal

function init() {
    if [ "$1" == "" ]; then
	echo "Must enter a path to initialize" >&2
	return 1
    fi
    mkdir -p $1/templates
    mkdir -p $1/scripts
    mkdir -p $1/files
    touch $1/requires
    mkdir -p $1/parameters/$(basename $1)
}

function fetch_params() {
    # Sometimes there's some shell escaping voodoo and rsync doesn't like the command args some people will pass it straight on
    # the command line; so we wrap it in a little bash script, and everyone's happy.
    echo ${RSYNC} --delete ${SERVERURI}::parameters/$(hostname)/* ${DISCOROOT}/parameters/$(hostname)/ > /tmp/$$.sh
    echo 'exit $?' >> /tmp/$$.sh
    /usr/bin/time -f "$TIME" -o ${DISCOROOT}/reports/_internal/fetch_params /bin/bash /tmp/$$.sh
    RETVAL=$?
    rm -f /tmp/$$.sh
    return $RETVAL
}

function params() {
    if [ "$1" == "" ]; then
	echo "Must pass a module name to fetch data for"
	return 1
    fi
    mkdir -p ${DISCOROOT}/reports/$1
    rm -f ${DISCOROOT}/reports/${1}/params
    /usr/bin/time -f "$TIME" -o ${DISCOROOT}/reports/$1/params \
	rsync -aWH ${STORAGE}/parameters/* ${DISCOROOT}/parameters/$(hostname)/
    return $?
}

function fetch() {
    if [ "$1" == "" ]; then
	echo "Must pass a module name to fetch data for"
	return 1
    fi
    SRC="${SERVERURI}::${1}"
    if [ "$2" != "" ]; then
	SRC="$2"
    fi
    if [ "$NOOP" == "" ]; then
	DEST=/var/disco/testfs/real/scratchfs
    else
	DEST=/var/disco/testfs/noop/scratchfs
    fi

    rm -rf ${STORAGE}/${1}
    mkdir -p ${DISCOROOT}/reports/$1
    rm -f ${DISCOROOT}/reports/${1}/fetch
    # Sometimes there's some shell escaping voodoo and rsync doesn't like the command args some people will pass it straight on
    # the command line; so we wrap it in a little bash script, and everyone's happy.
    echo ${RSYNC} --delete ${SRC}/requires ${SRC}/scripts ${SRC}/parameters ${SRC}/templates ${STORAGE}/${1} > /tmp/$$.sh
    echo 'exit $?' >> /tmp/$$.sh
    /usr/bin/time -f "$TIME" -o ${DISCOROOT}/reports/${1}/fetch /bin/bash /tmp/$$.sh 2>/tmp/$$.errors | sed s/"^"/"info: ${1}: "/g
    cat /tmp/$$.errors | grep -v "some files/attrs were not transferred" | sed s/"^"/"error: ${1}: "/g
    RETVAL=$?
    rm -f /tmp/$$.sh
    return $RETVAL
}

function files() {
    if [ "$1" == "" ]; then
	echo "Must pass a module name to retrieve files for"
	return 1
    fi
    SRC="${SERVERURI}::${1}"
    if [ "$2" != "" ]; then
	SRC="$2"
    fi
    if [ "$NOOP" == "" ]; then
	DEST=/var/disco/testfs/real/scratchfs
    else
	DEST=/var/disco/testfs/noop/scratchfs
    fi

    mkdir -p ${DISCOROOT}/reports/$1
    rm -f ${DISCOROOT}/reports/${1}/files
    # Sometimes there's some shell escaping voodoo and rsync doesn't like the command args some people will pass it straight on
    # the command line; so we wrap it in a little bash script, and everyone's happy.
    echo ${RSYNC} ${SRC}/files/* ${DEST} > /tmp/$$.sh
    echo 'exit $?' >> /tmp/$$.sh
    /usr/bin/time -f "$TIME" -o ${DISCOROOT}/reports/${1}/files /bin/bash /tmp/$$.sh 2>/tmp/$$.errors | sed s/"^"/"info: ${1}: "/g
    cat /tmp/$$.errors | grep -v "some files/attrs were not transferred" | sed s/"^"/"error: ${1}: "/g
    RETVAL=$?
    rm -f /tmp/$$.sh
    return $RETVAL
}


function requires()
{
    if [ "$1" == "" ]; then
	echo "Must pass a module name for requirements"
	return 1
    fi
    cat ${STORAGE}/${1}/requires 2>/dev/null |\
        grep -v "^#" |\
        sed -e s/"^ *after"/"${1} "/g \
            -e s/"^ *before *\([a-zA-Z0-9\-_\.]*\)"/"\1 ${1}"/g
}

function exec() {
    RETVAL=0
    mkdir -p ${DISCOROOT}/reports/$1
    rm -f ${DISCOROOT}/reports/${1}/exec
    for file in $(find ${STORAGE}/${1}/scripts/ -type f | sort -u)
    do
	NOOP="$NOOP" /usr/bin/time -f "$TIME" -o /tmp/$$.exec.time disco-sh-exec $file /tmp/${1}-$(basename $file)
	RETVAL=$(expr $RETVAL + $?)
	SNAME=$(basename $file)
	echo "$SNAME : " >> ${DISCOROOT}/reports/${1}/exec
	cat /tmp/$$.exec.time | sed s/"^"/"    "/g >> ${DISCOROOT}/reports/${1}/exec
    done
    rm -f /tmp/$$.exec.time
    return $RETVAL
}

function template() {
    if [ "$1" == "" ]; then
	echo "Must pass a module name to template"
	return 1
    fi
    mkdir -p ${DISCOROOT}/reports/$1
    rm -f ${DISCOROOT}/reports/${1}/template
    DESTROOT=""
    if [ "$NOOP" != "" ]; then
	DESTROOT=/var/disco/testfs/noop/scratchfs
    fi
    if [ ! -d ${STORAGE}/${1}/templates ]; then
	return 0;
    fi
    cd ${STORAGE}/${1}/templates
    RETVAL=0
    for file in $(find . -type f | sed s/"^\.\/"//g)
    do
	NOOP=true /usr/bin/time -f "$TIME" -o /tmp/$$.template.time disco-sh-exec $(pwd)/$file /$file >/tmp/$$.tmpl
	echo "$file : " >> ${DISCOROOT}/reports/${1}/template
	cat /tmp/$$.template.time | sed s/"^"/"    "/g >> ${DISCOROOT}/reports/${1}/template
	if [ $? -eq 0 ]; then
	    mkdir -p $(dirname ${DESTROOT}/$file)
	    mv /tmp/$$.tmpl ${DESTROOT}/$file
	else
	    echo "error: template ${1}/templates/$file failed, not replacing /$file"
	    RETVAL=1
	fi
    done
    rm -f /tmp/$$.template.time
    return $RETVAL
}

function spin() {
    module=$1
    echo "info: Processing ${module}"
    NOOP="true" files $module
    NOOP="true" template $module
    if [ "$NOOP" == "" ]; then
	# We rsync all the configs and files into the 'real' scratchfs so that we can
	# just do one big diff at the very end, capturing every single disk change,
	# including ones made by the scripts.
	rsync -aWH /var/disco/testfs/noop/scratchfs/. /var/disco/testfs/real/scratchfs/
    fi
    NOOP="$NOOP" exec $module
    RETVAL=$?
    /usr/bin/time -f "$TIME" -o /var/disco/reports/${module}/diff disco-fs-diff
    if [ "$NOOP" == "" ]; then
	# Now for the real rsync back home
	cd /var/disco/testfs/real/scratchfs/.unionfs
	for file in $(find . -iname "*_HIDDEN~" | sed -e s/"^\."/""/g -e s/"_HIDDEN~$"/""/g); 
	do 
	    rm -rf /${file}
	done
	cd ..
	rm -rf ./.unionfs
	rsync -aWH /var/disco/testfs/real/scratchfs/. /
    fi
    rm -rf /var/disco/testfs/noop/scratchfs/*
    rm -rf /var/disco/testfs/real/scratchfs/*
    if [ $RETVAL -ne 0 ]; then
	echo "error: Failed to apply $module."
    fi
    return $?
}

$1 "$2" "$3" "$4" "$5" "$6" "$7" "$8"
