#!/bin/zsh

set -e
setopt err_return
autoload colors;
[[ -t 1 ]] && colors

function warn { print 1>&2 -- $bg[red]$*$bg[default] }
function die { warn $@; return 1 }

progname=$0
function usage {
    cat <<EOF 1>&2
Usage: \$yl_scripts/${progname:t} [-n | -q] DESTDIR

This script will setup cgi-bin/runyatt.cgi and .htaccess in DESTDIR.
Short options:
  -n   dry run. Do not actually change any files; just print what would happen.
  -q   quiet.
EOF
    exit ${1:-0}
}

#========================================

# $0 == lib/YATT/scripts/setup-min.zsh

# lib/YATT/scripts
scriptsdir=$(cd $0:h && print $PWD)

# lib
libdir=$scriptsdir:h:h

samplecgi=$libdir/YATT/samples/runyatt.cgi
sampletmpl=$libdir/YATT/ytmpl

driver_name=runyatt

#========================================

opt_spec=(
    h=o_help
    x=o_xtrace
    n=o_dryrun
    q=o_quiet
    C=o_clean
    -setup=o_try_setup
)

zparseopts -D -A opts $opt_spec

if ((ARGC)) && [[ $1 == -* ]]; then
    warn "Unknown option '$1'"
    usage
fi

(($#o_help)) && usage

[[ -n $o_xtrace ]] && set -x
if [[ -z $o_quiet ]]; then o_verbose=(-v); else o_verbose=(); fi

((ARGC)) || usage

destdir=$1; shift

if [[ $destdir == . ]]; then
    destdir=$PWD
elif [[ $destdir != /* ]]; then
    destdir=$PWD/$destdir
fi

#========================================
# utils.
#========================================
function x {
    if [[ -z $o_quiet ]]; then
	print -- $bg[cyan]"$@"$bg[default]
    fi
    if [[ -z $o_dryrun ]]; then
	"$@"
    fi
}

function mkfile {
    zparseopts -D m:=mode
    if [[ -z $o_quiet ]]; then
	echo $bg[cyan]mkfile $1 "$bg[default] as:"
	echo "$bg[blue]#{{{{{{{{{{{{$bg[default]"
    fi
    if [[ -n $o_dryrun ]]; then
	cat
    elif [[ -n $o_quiet ]]; then
	cat > $1
    else
	tee $1
    fi
    if [[ -z $o_quiet ]]; then
	echo "$bg[blue]#}}}}}}}}}}}}$bg[default]"
    fi
    if [[ -n $mode ]]; then
	x chmod $o_verbose $mode[-1] $1
    fi
}

function find_pat {
    perl -nle '
      BEGIN {$PAT = shift}
      if (/$PAT/) {print $1 and exit 0}
      elsif (eof) {print STDERR "Not found: $PAT\n"; exit 1}
' "$@"
}

#========================================
# Env checking.
#========================================

if ! perl -le 'exit 1 if $] < 5.010'; then
    die Perl 5.010 or higher is required for YATT::Lite!
fi

o_chmod_c=(-c)
CGI_BIN=cgi-bin
USER_DIR=public_html
integer wo_apache=0

if [[ $OSTYPE == darwin* ]]; then
    CGI_BIN=CGI-Executables
    USER_DIR=Sites
    o_chmod_c=()

    apache=/etc/apache2/httpd.conf
    [[ -r $apache ]] || die "Can't find $apache!"

    document_root=$(find_pat '^DocumentRoot\s+"([^"]*)"' $apache) ||
    document_root=/Library/WebServer/Documents

    APACHE_RUN_GROUP=$(find_pat '^Group\s+(\S+)' $apache) ||
    APACHE_RUN_GROUP=www

elif [[ -r /etc/redhat-release ]]; then
    apache=/etc/httpd/conf/httpd.conf
    [[ -r $apache ]] || die "Can't find $apache!"
    document_root=$(find_pat '^DocumentRoot\s+"([^"]*)"' $apache)
    APACHE_RUN_GROUP=$(find_pat '^Group\s+(\S+)' $apache)
elif [[ -r /etc/lsb-release ]] && source /etc/lsb-release; then
    case $DISTRIB_ID in
	(*Ubuntu*)

	apache=/etc/apache2/sites-available/default
	if [[ -r $apache ]]; then
	    document_root=$(find_pat '^\s*DocumentRoot\s+"?([^"]*)"?' $apache)
	    # for APACHE_RUN_GROUP
	    source /etc/apache2/envvars
	    if [[ -z $APACHE_RUN_GROUP ]]; then
		die "Can't find APACHE_RUN_GROUP!"
	    fi

	    curgroups=($(id -Gn))
	    if (($curgroups[(ri)$APACHE_RUN_GROUP] >= $#curgroups)); then
		die User $USER is not a member of $APACHE_RUN_GROUP, stopped.
	    fi
	else
	    # Fake settings when apache2 is not installed.
	    document_root=/var/www
	    APACHE_RUN_GROUP=nogroup
	    wo_apache=1
	fi

	;;
	(*)
	die "Unsupported distribution! Please modify $0 for $DISTRIB_ID"
	;;
    esac
else
    document_root=/var/www
    APACHE_RUN_GROUP=apache
fi

if (($#o_document_root)); then
    document_root=${o_document_root[2][2,-1]}
fi

if [[ -n $APACHE_RUN_GROUP ]] && (($+commands[groups])); then
    mygroups=($(groups))
    if ((!wo_apache && UID != 0 && $mygroups[(ri)$APACHE_RUN_GROUP] > $#mygroups)); then
	warn "You are not a member of $APACHE_RUN_GROUP. To change this, do \"sudo usermod -aG $APACHE_RUN_GROUP $USER\" and re-login this server."
    fi
fi

if ((wo_apache)); then
    location=/
    cgi_bin_perm=755
    install_type=sys
    cgi_bin=$destdir/$CGI_BIN

elif [[ $destdir = $document_root(|/*) ]]; then
    location=${destdir#$document_root}
    cgi_bin_perm=775
    install_type=sys
    cgi_bin=$destdir/$CGI_BIN

elif [[ $destdir = $HOME/$USER_DIR(|/*) ]]; then
    location=/~$USER${destdir#$HOME/$USER_DIR}
    cgi_bin_perm=755; # for suexec
    install_type=user
    cgi_bin=$destdir/cgi-bin

else
    die Can\'t extract URL from destdir=$destdir.
fi

# SELinux check.
if (($+commands[selinuxenabled])) && selinuxenabled; then
    is_selinux=1
else
    is_selinux=0
fi

#========================================
# Main.
#========================================
cgi_loc=$location/cgi-bin

if ! [[ -d $cgi_bin ]]; then
    x install -d $o_verbose -m 2$cgi_bin_perm $cgi_bin
else
    x chmod $o_chmod_c 2$cgi_bin_perm $cgi_bin
fi

x install -m $cgi_bin_perm $samplecgi $cgi_bin/$driver_name.cgi
if (($is_selinux)); then
    x chcon $o_verbose -t httpd_${install_type}_script_exec_t $cgi_bin/$driver_name.cgi || true
fi

dn=$cgi_bin/$driver_name.ytmpl
if ! [[ -e $dn ]]; then
    x ln $o_verbose -nsf $sampletmpl $dn
fi

x ln $o_verbose -nsf $driver_name.cgi $cgi_bin/$driver_name.fcgi

((wo_apache)) || mkfile $cgi_bin/.htaccess <<EOF
Options +ExecCGI
EOF

dn=$destdir/../var
if [[ -d $dn ]]; then
    dirs=($dn/*/tmp(/N))
    if (($#dirs && $#o_clean)); then
	rm -rf $dirs
    fi
    if (cd $dn && git rev-parse --is-inside-work-tree >/dev/null); then
        x git checkout $dn
    fi
    x chgrp -R $APACHE_RUN_GROUP $dn
    if (($#dirs && $#o_clean)); then
	mkdir -p $dirs
    fi
    if (($is_selinux)); then
	x chcon $o_verbose -R -t httpd_${install_type}_script_rw_t $dn
    fi
fi

if (($#o_try_setup)); then
    top_app=$destdir/html/.htyattrc.pl
    if [[ -r $top_app ]]; then
	# XXX: This can fail second time, mmm...
	x $realbin/yatt.command -d $top_app:h --if_can setup
    fi
fi

# Then activate it!
if ((wo_apache)); then
    ; #nop

elif [[ -r $destdir/dot.htaccess ]]; then
    x cp $o_verbose $destdir/dot.htaccess $destdir/.htaccess
    x sed -i -e "s|@DRIVER@|$cgi_loc/$driver_name.cgi|" $destdir/.htaccess
else
    # Mapping *.ytmpl(private template) to x-yatt-handler is intentional.
    mkfile $destdir/.htaccess <<EOF
Allow from all

Action x-yatt-handler $cgi_loc/$driver_name.cgi
# Action x-yatt-handler $cgi_loc/$driver_name.fcgi
AddHandler x-yatt-handler .yatt .ytmpl .ydo

Options -Indexes -Includes -ExecCGI
DirectoryIndex index.yatt index.html

<Files *.ytmpl>
deny from all
</Files>
EOF
fi

if [[ -z $o_dryrun ]]; then
    echo $bg[green]OK$bg[default]: URL=http://localhost$location/
fi