#!/bin/sh -efu
#
# Copyright (C) 2009  Alexey I. Froloff <raorn@altlinux.org>
#
# mongrel_cluster - runs cluster of mongrel servers for rails application
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#

. shell-args
. shell-config
. shell-getopt
. shell-quote
. shell-var

WITHOUT_RC_COMPAT=1
### HAK HAK HAK
NOLOCALE="${NOLOCALE-}"
BOOTUP="${BOOTUP-}"
LOGLEVEL="${LOGLEVEL-}"
IN_INITLOG="${IN_INITLOG-}"
TERM="${TERM-}"
COLUMNS="${COLUMNS-}"
: ${RES_OFFSET:=8}
start_daemon()
{
	fatal "start_daemon not defined"
}
stop_daemon()
{
	fatal "stop_daemon not defined"
}
status()
{
	fatal "status not defined"
}
### HAK HAK HAK
. /etc/init.d/functions

PROG="${0##*/}"
PROG_VERSION=1.0

show_help() {
	cat <<EOF
$PROG - Mongrel Cluster

Usage: $PROG COMMAND [OPTIONS]

Options:
  -C,--config=PATH     path to cluster configuration file;
  --clean              remove pid_file if needed;
  --only               port number of cluster member;
  --user=USER          default user to run process as, if not specified
                       in configuration files;
  --group=GROUP        default group to run process as, if not specified
                       in configuration files;
  -v,--verbose         print all called commands and output;
  -V,--version         print program version and exit;
  -h,--help            show this text and exit.

Valid commands are \`start', \`stop', \`restart' and \`status'.

Report bugs to http://bugzilla.altlinux.org/

EOF
	exit
}

print_version()
{
	cat <<EOF
$PROG version $PROG_VERSION
Written by Alexey I. Froloff <raorn@altlinux.org>

Copyright (C) 2009  Alexey I. Froloff <raorn@altlinux.org>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
EOF
	exit
}

read_options()
{
	local file="$1" opt val local dir base

	[ -r "$file" ] ||
		fatal "$file: file not available."

	for opt in environment address cwd timeout throttle mime_map docroot num_procs debug config_script user group prefix port pid_file log_file servers; do
		eval "opt_$opt=\"\${opt_$opt-}\""
		shell_var_trim "val" "$(shell_config_get "$file" "$opt" ': ')"
		[ -z "$val" ] ||
			quote_shell_variable "opt_$opt" "$val"
	done

	dir="$(dirname "$file")"
	base="$(basename "$file")"
	base="${base%.*}"

	SourceIfNotEmpty "$dir/$base.env"
}

__port_file()
{
	local file="$1" port="$2"
	local ext base dir

	dir="$(dirname "$file")"
	base="$(basename "$file")"
	ext="${base##*.}"
	[ -z "$ext" ] ||
		ext=".$ext"
	base="${base%$ext}"

	printf '%s/%s.%s%s' "$dir" "$base" "$port" "$ext"
}

port_pid_file()
{
	__port_file "$opt_pid_file" "$1"
}

port_log_file()
{
	__port_file "$opt_log_file" "$1"
}

opt_environment="${RAILS_ENV-development}"
opt_port=3000
opt_cwd="$(pwd)"
opt_pid_file=tmp/pids/mongrel.pid
opt_log_file=log/mongrel.log
opt_servers=2
opt_user=
opt_group=

[ "$#" -gt 0 ] ||
	show_usage 'not enough arguments'

cmd="$1" && shift

case "$cmd" in
	start|stop|reload|status) ;;
	restart)
		rc=0
		"$0" stop "$@" ||
			rc="$?"
		"$0" start "$@" ||
			rc="$?"
		exit "$rc"
		;;
	*) show_usage "invalid command '$cmd'";;
esac

TEMP=`getopt -n $PROG -o C:,v,V,h -l config:,clean,only:,user:,group:,pid_file:,log_file:,verbose,version,help -- "$@"` ||
	show_usage
eval set -- $TEMP

clean=
verbose=
config=config/mongrel_cluster.yml
only=
while :; do
	case "$1" in
		-C|--config) config="$(opt_check_read "$1" "$2")"; shift ;;
		--clean) clean=1;;
		--only) only="$(opt_check_number "$1" "$2")"; shift;;
		--user) shift; opt_user="$1";;
		--group) shift; opt_group="$1";;
		--log_file) shift; opt_log_file="$1";;
		--pid_file) shift; opt_pid_file="$1";;
		-v|--verbose) verbose=-v;;
		-V|--version) print_version;;
		-h|--help) show_help;;
		--) shift; break;;
		*) fatal "unrecognized option '$1'";;
	esac
	shift
done

config="$(readlink -ev "$config")"
read_options "$config"

cd "$opt_cwd" ||
	fatal "unable to change directory to \`$opt_cwd'"

port="${only:-$opt_port}"
end_port="${only:-$(($port + $opt_servers - 1))}"

while [ $port -le $end_port ]; do
	pid_file="$(port_pid_file "$port")"
	log_file="$(port_log_file "$port")"

	case "$cmd" in
		start)
			args='start -d'
			[ -z "$opt_environment" ] ||
				args="$args -e $(quote_shell "$opt_environment")"
			[ -z "$opt_address" ] ||
				args="$args -a $(quote_shell "$opt_address")"
			[ -z "$opt_cwd" ] ||
				args="$args -c $(quote_shell "$opt_cwd")"
			[ -z "$opt_timeout" ] ||
				args="$args -o $(quote_shell "$opt_timeout")"
			[ -z "$opt_throttle" ] ||
				args="$args -t $(quote_shell "$opt_throttle")"
			[ -z "$opt_mime_map" ] ||
				args="$args -m $(quote_shell "$opt_mime_map")"
			[ -z "$opt_docroot" ] ||
				args="$args -r $(quote_shell "$opt_docroot")"
			[ -z "$opt_num_procs" ] ||
				args="$args -n $(quote_shell "$opt_num_procs")"
			! shell_var_is_yes "$opt_debug" ||
				args="$args -B"
			[ -z "$opt_config_script" ] ||
				args="$args -S $(quote_shell "$opt_config_script")"
			[ -z "$opt_user" ] ||
				args="$args --user $(quote_shell "$opt_user")"
			[ -z "$opt_group" ] ||
				args="$args --group $(quote_shell "$opt_group")"
			[ -z "$opt_prefix" ] ||
				args="$args --prefix $(quote_shell "$opt_prefix")"

			args="$args -p $(quote_shell "$port")"
			args="$args -P $(quote_shell "$pid_file")"
			args="$args -l $(quote_shell "$log_file")"

			if [ -n "$clean" -a -f "$pid_file" ] && \
				! /sbin/start-stop-daemon --stop --test \
					--pidfile "$pid_file" \
					${opt_user:+--expect-user "$opt_user"} \
					--name mongrel_rails >/dev/null; then
				rm -f "$pid_file" ||:
			fi

			start_daemon --displayname "mongrel_rails on port $port" \
				${opt_user:+--expect-user "$opt_user"} \
				--name mongrel_rails \
				--pidfile "$pid_file" \
				-- \
				mongrel_rails $args ||:
			;;
		stop)
			stop_daemon --displayname "mongrel_rails on port $port" \
				${opt_user:+--expect-user "$opt_user"} \
				--name mongrel_rails \
				--pidfile "$pid_file" \
				-- \
				mongrel_rails ||:
			;;
		reload)
			stop_daemon --displayname "mongrel_rails on port $port" \
				${opt_user:+--expect-user "$opt_user"} \
				--name mongrel_rails \
				--pidfile "$pid_file" \
				-HUP \
				--announce \
				-- \
				mongrel_rails ||:
			;;
		status)
			status --displayname "mongrel_rails on port $port" \
				${opt_user:+--expect-user "$opt_user"} \
				--name mongrel_rails \
				--pidfile "$pid_file" \
				-- \
				mongrel_rails ||:
			;;
	esac
	port=$(($port + 1))
done
