#!/bin/bash
#
# for copyright infos see /usr/share/doc/kusa/COPYRIGHT
# maintained by KUBiC Labs - Taverne (CH)
#
# common shell functions for www software installation

## includes part of apache2 environment
#
__file="/etc/apache2/envvars"
[ -f $__file ] || {
	echo "file '$__file' not found (no apache2 installation on this machine?" >&2
	exit 1
}
eval $( grep "^export APACHE_RUN_USER=" $__file )
eval $( grep "^export APACHE_RUN_GROUP=" $__file )
unset __file

# set temps location
[ -f /etc/default/kusa-paths ] && . /etc/default/kusa-paths
KUSA_PATH_TMPDIR=${KUSA_PATH_TMPDIR:-"/tmp"}
TMPBASE="$KUSA_PATH_TMPDIR/www-install-"
TMPTEMPLATE="${TMPBASE}XXXXXXXXX"

set -e	# abort on errors
set -u	# abort on undefined vars

export MYUSER=$( ls -ld . | awk '{ print $3; }' )
export MYGROUP=$( ls -ld . | awk '{ print $4; }' )
export FIXPERMS="chown $MYUSER:$MYGROUP"
export FIXGROUP="chgrp $MYGROUP"
export CHMOD="chmod"
export CHOWN="chown"
export CHGRP="chgrp"
export CP="cp"
export HERE=`pwd`
export BASEURL=

export VERBOSE=${VERBOSE:-true}
export DEBUG=${DEBUG:-false}
export BACKUPDIR=${BACKUPDIR:-"`pwd`/.backup"}
export DFLAG=
export DUMMYTAG=
export F_EXEC=true

export REPO_URL=${REPO_URL:-"http://repos.kubit.ch/install"}
export REPO_DIR=${REPO_DIR:-""}


cleanup()
{
	[ "$TMPBASE" != "" ] && rm -f ${TMPBASE}-*
}

trap 'echo -e "\n*INTR*\n"; cleanup; exit 255' 1 2 3
trap 'echo -e "\nunknown error $? in $LINENO\n"; cleanup' ERR
trap 'cleanup' EXIT


## warning title message
##
warning()
{
	local title=$1	; shift
	local msg="$*"
	local out=

	out=`echo -e "$msg" | fold -s -w 76 | sed -e 's/^/    /'`

	echo -e "\n `tput bold 2>/dev/null`warn: $title`tput sgr0 2>/dev/null`\n"
	echo -e "$out\n"
}

error()
{
	echo -e "\n `tput bold 2>/dev/null`error:`tput sgr0 2>/dev/null` $*\n"
}


## check_installdir directory
##
check_installdir()
{
	local wwwbase=`kusa-conf path.wwwdir`	|| exit $?
	local dir=$1 ; shift
	local valid_dirs=$*
	local check_dir=
	local is_valid=
	local repl=

	[ -d "$dir" ] || {
		echo "error: '$dir' not a directory or not accessibile" >&2
		return 1
	}

	# absolutize path
	dir=`(cd $dir ; pwd)` || return $?

	echo "$dir" | grep -q " " && {
		echo "error: installation path can't contain spaces" >&2
		echo "	now is: '$dir'" >&2
		return 1
	}

	echo "$dir" | grep -q "^$wwwbase" || {
		warning "wrong dir?" \
			"You want to install your software in: $dir\n\n" \
			"The software should be installed in a webserver" \
			"accessibile tree, on this system the main folder (wwwdir)" \
			"is: $wwwbase" >&2
		echo -n "Press <Return> to continue, or Ctrl-C to interrupt: " >&2
		read repl
	}

	if [ `basename $dir` == "docs" ]
	then
		BASEURL=
	else
		BASEURL="/`basename $dir`"

		is_valid=false
		[ "$valid_dirs" ] && {
			for check_dir in $valid_dirs
			do
				[ $BASEURL == "/$check_dir" ] && {
					is_valid=true
					break
				}
			done
		}

		$is_valid || {
		    warning "wrong dir?" \
			"You want to install your software in: $dir\n\n" \
			"This doesn't match suggested dirs: docs, $valid_dirs." \
			"On standard kusa system, with apache configured to use" \
			"virtual hosts, you should have a directory named 'docs' where" \
			"store http documents and www software" >&2
		    echo -n "Press <Return> to continue, or Ctrl-C to interrupt: " >&2
		    read repl
		}
	fi
	return 0
}


wgetfile()
{
	local stat=0
	local tmpfile=$(mktemp $TMPTEMPLATE) || return $?

	echo -n "  getting file '$1' ... "

	case $1 in
	  http:*|ftp:*)	wget "$1" -O "$2.part" >$tmpfile 2>&1 || stat=$? ;;
	  *:*)		scp "$1" "$2.part" >$tmpfile 2>&1 || stat=$?  ;;
	  *)		cp "$1" "$2.part" >$tmpfile 2>&1 || stat=$? ;;
	esac

	if [ $stat == 0 ]
	then
		echo "ok"
		rm -f "$2"
		mv "$2.part" "$2"
	else
		echo "ERROR"
		cat $tmpfile
		rm -f "$2.part"
	fi

	rm -f $tmpfile
	return $stat
}



## set_file_commands
##
## try to get the best chown/chgrp and copy commands
##
set_file_commands()
{
	local checkfile="check.tmp"

	cp /dev/null $checkfile >/dev/null 2>/dev/null || {
		echo "ERROR: you don't have write permission here" >&2
		exit 1
	}

	echo ""
	echo "  current user/group: $MYUSER:$MYGROUP"
	echo "  apache2 user/group: $APACHE_RUN_USER:$APACHE_RUN_GROUP"
	echo ""
	echo -n "  checking if you can 'chown' files ... "

	FIXPERMS="sudo $FIXPERMS"
	FIXGROUP="sudo $FIXGROUP"
	CHMOD="sudo chmod"
	CHOWN="sudo chown"
	CHGRP="sudo chgrp"
	CP="sudo cp"
	CPIO="sudo cpio"
	if $FIXPERMS $checkfile >/dev/null 2>/dev/null
	then
		echo "ok (using sudo)"
	else
		echo -n "  no, try only 'chgrp' ... "
		FIXPERMS="chgrp $APACHE_RUN_GROUP"
		CHMOD="chmod"
		CHOWN="echo '(not performing)' chown"
		CHGRP="chgrp"
		if $FIXPERMS $checkfile >/dev/null 2>/dev/null
		then
			warning "file permissions" "fix perms will works only on GROUP" >&2
		else
			echo -e "\nERROR: you can't chown files here in any way, abort" >&2
			exit 1
		fi
	fi
	rm -f $checkfile
	echo

	return 0
}

# calls commands setup
set_file_commands




## === installfile filename dest [owner [mode [do_parse_true_false]]] ===
##
## installa un templatefile ricercandolo nel searchpath,
## eseguendo eventuale backup del file originale se esiste, e
## operando la sostituzione delle variabili (solo se il file
## e` di testo, altrimento viene copiato senza espansioni)
##
## i files vengono installati solo se risultano differenti da
## quelli eventualmente gia` presenti sul sistema (in questo
## modo non si generano falsi positivi)
##
## in caso di installazione la variabile di environment FILES_HAS_INSTALLED
## viene impostata a true, e FILES_INSTALLED (una lista separata da spazi)
## viene aggiornata aggiungendo il nome del file, queste due variabili
## possono essere controllate nello script di '''run-install''' per
## decidere se compiere o meno certe operazioni, assieme alla piu` generica
## SOMETHING_HAS_CHANGED, anch'essa posta a true in caso di installazione
##

export SOMETHING_HAS_CHANGED=false
export FILES_HAS_INSTALLED=false
export FILES_INSTALLED=

installfile()
{
	local file="$1"
	local to="$2"
	local own=${3:-""}
	local perms=${4:-""}
	local do_parse=${5:-true}

	local from=
	local tmpfile=
	local backup=
	local dir=

	case "$file" in
		./*|/*) from="$file" ;;
		*)	from=`filepath "$file"`	|| {
				echo "can't find file '$file'" >&2
				return 1
			}
			;;
	esac

	# se la destinazione finisce con "/" ed esiste la directory
	# appende il nome del file originale alla directory
	#
	if [ -d $to ]
	then
		if echo "$to" | grep -q "/$"
		then
			to="$to`basename $file`"
		else
			echo "destination '$to' is a directory" >&2
			return 1
		fi
	else
		if echo "$to" | grep -q "/$"
		then
			echo	"error: you asked to install '$file' into '$to'\n" \
				"but destination is not a directory" >&2
			return 1
		fi
	fi

	$VERBOSE && printf "\r\033[K checking $to ... \r" >&2

	# se non ho i permessi di installazione, esco senza errori
	# se non esisteva gia` da prima lo rimuovo per evitare falsi backup
	#
	###if [ -f "$to" ]
	###then
		###[ -w "$to" ] || return 0
	###else
		###touch "$to" 2>/dev/null || return 0
		###rm -f "$to"
	###fi

	backup="$BACKUPDIR/$to.`date '+%Y%m%d'`"
	tmpfile=$(mktemp $TMPTEMPLATE) || return 1

	$do_parse && {
		case `file "$from"` in
			*text*)	;;
			*)	do_parse=false ;;
		esac
	}

	if $do_parse
	then
		jtconf-parse $DFLAG --simple "$from" > "$tmpfile" || {
			echo "install of '$to' failed, error parsing" >&2
			return 1
		}
	else
		cp "$from" "$tmpfile" || {
			echo "install of '$to' failed, copy error on $tmpfile" >&2
			return 1
		}
	fi
	[ -f "$to" ] && {
		# both have zero size?
		[ ! -s "$tmpfile" -a ! -s "$to" ] && {
			rm -f "$tmpfile"
			__installfile_fixperms true "$to" "$own" "$perms"
			$VERBOSE && printf "\r\033[K\r" >&2
			return 0
		}
		# are equal? (not changed)?
		[ `stat --format='%s' "$tmpfile"` == `stat --format='%s' "$to"` ] && \
		   cmp "$tmpfile" "$to" >/dev/null && {
			rm -f "$tmpfile"
			__installfile_fixperms true "$to" "$own" "$perms"
			$VERBOSE && printf "\r\033[K\r" >&2
			return 0
		}
	}
	$VERBOSE && printf "\r\033[K\r" >&2

	echo " $DUMMYTAG install '$from' $perms $own" >&2
	echo " $DUMMYTAG     --> '$to'" >&2

	[ -f "$to" -a ! -f "$backup" ] && {
		echo " $DUMMYTAG  backup '$backup'" >&2
		$F_EXEC && {
			dir=`dirname $backup`
			[ -d "$dir" ] || mkdir -p "$dir"
			mv "$to" "$backup" || return 1
		}
	}

	$F_EXEC || return 0

	mv "$tmpfile" "$to" || {
		echo "installing file" >&2
		rm -f "$tmpfile"
		return 1
	}
	# updates global vars
	#
	FILES_HAS_INSTALLED=true
	FILES_INSTALLED="$FILES_INSTALLED $to"
	SOMETHING_CHANGED=true

	__installfile_fixperms false "$to" "$own" "$perms" "$backup"

	return 0
}

__installfile_fixperms()
{
	local verbose=$1
	local to=$2
	local own=$3
	local perms=$4
	local backup=${5:-""}
	local before=`ls -l "$to"`

	if [ "$own" = "" ]
	then
		if [ "$backup" != "" -a -f "$backup" ]
		then
			$CHOWN --reference="$backup" "$to"
		else
			$CHOWN $MYUSER:$MYGROUP "$to"
		fi
	else
		$CHOWN $own "$to"
	fi

	if [ "$perms" = "" ]
	then
		if [ -f "$backup" ]
		then
			$CHMOD --reference="$backup" "$to"
		else
			$CHMOD 664 "$to"
		fi
	else
		$CHMOD $perms "$to"
	fi

	$verbose || return 0

	local after=`ls -l "$to"`
	[ X"$before" != X"$after" ] && {
		echo "  warning: $before"
		echo "  newmode: $after"
	}

	return 0
}


#------------------------------------------------------------------------------
# ritorna il path completo di un file cercandolo in $TEMPLATEPATH
#------------------------------------------------------------------------------
## === filepath filename [mode1 [mode2]] ===
##
##  * se non sono passati altri parametri viene cercato un file che sia
##  leggibile; e` possibile passare oltre al filename anche uno o due attributi
##  che devono essere soddisfatti perche` la ricerca sia considerata valida,
##  gli attributi sono quelli standard della shell (r=read, x=execute, d=dir),
##  quindi ad esempio per cercare una directory invece di un file, usare
##  {{{
## filepath nomedir -d
##  }}}
##
export TEMPLATEPATH="."

filepath()
{
	local file="$1"
	local flag1=${2:-"-r"}
	local flag2=${3:-"-r"}

	local search=
	local dir=
	local path=
	local packagedir=
	local saveifs=$IFS

	search="`pwd`:$TEMPLATEPATH"

	for packagedir in $PRJ/$PACKAGE "$PRJ/${PACKAGE}-install"
	do
		[ "$packagedir" != `pwd` ] && {
			search="$search:$packagedir"
		}
	done

	decho "filepath(): searching '$file' in: $search"

	IFS=":"
	for dir in $search
	do
		path="$dir/$file"

		[ -f "$path" -o -d "$path" ] && {
			[ $flag1 "$path" -a $flag2 "$path" ] || continue
			echo "$path"
			decho "filepath(): found '$path'"
			IFS="$saveifs"
			return 0
		}
	done
	decho "filepath(): '$file' not found"
	IFS="$saveifs"
	return 1	# file/dir not found
}

## == decho string(s) ==
##
## echoes on stderr, if $F_DEBUG=true
##
export F_DEBUG=false
decho()
{
	$F_DEBUG || return 0
	echo -e "@> " "$@" >&2
}



