#!/usr/bin/perl -w

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some shell
use strict;

=pod

=head1 NAME

bric_apachectl - Bricolage Apache controller

=head1 SYNOPSIS

   bric_apachectl start

   bric_apachectl stop

   bric_apachectl restart

   bric_apachectl single

   bric_apachectl debug

=head1 DESCRIPTION

This script controls the Bricolage Apache server. The usage of the script is
the same as the normal apache "apachectl" script but only "start", "stop" and
"restart" are supported. Also, "restart" performs a hard stop and start since
a SIGHUP isn't enough for mod_perl. The "debug" command starts the server
under the Perl debugger - see L<Bric::Hacker|Bric::Hacker> for details.

Usage information can be obtained by running the script with no arguments.

=head1 AUTHOR

Sam Tregar <stregar@about-inc.com>

=cut

# how long to wait for stop on restart (in seconds)
use constant MAX_RESTART_WAIT => 10;

$|++;

use File::Spec::Functions qw(catdir);

BEGIN {
    # $BRICOLAGE_ROOT defaults to /usr/local/share/bricolage
    $ENV{BRICOLAGE_ROOT} ||= "/usr/local/share/bricolage";

    # use $BRICOLAGE_ROOT/lib if exists
    my $lib = catdir($ENV{BRICOLAGE_ROOT}, "lib");
    if (-e $lib) {
        $ENV{PERL5LIB} = defined $ENV{PERL5LIB} ?
          "$ENV{PERL5LIB}:$lib" : $lib;
        unshift @INC, $lib;
    }

    # make sure Bric is found
    eval { require Bric };
    die <<"END" if $@;
######################################################################

   Cannot load Bricolage libraries. Please set the environment
   variable BRICOLAGE_ROOT to the location of your Bricolage
   installation or set the environment variable PERL5LIB to the
   directory where Bricolage's libraries are installed.

   The specific error encountered was as follows:

   $@

######################################################################
END
}

use Bric::Config qw(:apachectl);

# the httpd command
my $httpd = APACHE_BIN . ' -f ' . APACHE_CONF . ' -u ';

# the pid file
my $pid_file = PID_FILE;

# get status
my $running = 0;
my $pid;
if (-e $pid_file) {
    $pid = `cat $pid_file`;
    chomp $pid;
    if ($pid and kill(0, $pid)) {
        $running = 1;
    }
}

# check for args
usage() unless @ARGV;

my $command = shift @ARGV;

if ($command eq 'start') {
    if ($running) {
        print "bric_apachectl $command: httpd (pid $pid) already running\n";
        exit;
    }

    # clear the cache before starting the server to avoid stale cache data
    require Bric::App::Cache;
    Bric::App::Cache->clear();

    print "bric_apachectl $command: starting httpd\n";
    unless (system($httpd)) {
        print "bric_apachectl $command: httpd started\n";
        exit;
    } else {
        print "bric_apachectl $command: httpd could not be started\n";
    exit 3;
    }
}

if ($command eq 'stop') {
    unless ($running) {
        print "bric_apachectl $command: httpd not running\n";
        exit;
    }
    if (kill 15, $pid) {
        print "bric_apachectl $command: httpd stopped\n";
        exit;
    } else {
        print "bric_apachectl $command: httpd could not be stopped\n";
        exit 3;
    }
}

if ($command eq 'restart') {
    # stop
    if ($running) {
        if (kill 15, $pid) {
            print "bric_apachectl $command: waiting for httpd to stop";
        } else {
            print "bric_apachectl $command: httpd could not be stopped\n";
            exit 3;
        }

        # wait for stop - check pid file for removal
        my $stopped = 0;
        for my $wait (0 .. MAX_RESTART_WAIT) {
            if (not -e $pid_file) {
                $stopped = 1;
                last;
            }
            print ".";
            sleep 1;
        }

        if ($stopped) {
            print "\nbric_apachectl $command: httpd stopped\n";
        } else {
            print "\nbric_apachectl $command: httpd not stopped in time\n";
            exit;
        }

    }
    # clear the cache before starting the server to avoid stale cache data
    require Bric::App::Cache;
    Bric::App::Cache->clear();

    # start
    print "bric_apachectl $command: starting httpd\n";
    unless (system($httpd)) {
        print "bric_apachectl $command: httpd started\n";
        exit;
    } else {
        print "bric_apachectl $command: httpd could not be started\n";
        exit 3;
    }
}

if ($command eq 'single') {
    if ($running) {
        print "bric_apachectl $command: httpd (pid $pid) already running\n";
        exit;
    }

    # clear the cache before starting the server to avoid stale cache data
    require Bric::App::Cache;
    Bric::App::Cache->clear;

    print "bric_apachectl $command: starting httpd -X\n";

    # use exec since with -X this command won't return till the server
    # is killed.
    exec "$httpd -X";
}

if ($command eq 'debug') {
    if ($running) {
        print "bric_apachectl $command: httpd (pid $pid) already running\n";
        exit;
    }

    # clear the cache before starting the server to avoid stale cache data
    require Bric::App::Cache;
    Bric::App::Cache->clear();

    print "bric_apachectl $command: starting httpd -X\n";

    # use exec since with -X this command won't return till the server
    # is killed.
    exec "$httpd -X -D BRICOLAGE_DEBUG";
}

usage();

sub usage {
  print <<END;
usage: bric_apachectl (start|stop|restart|debug|single)

start      - start httpd
stop       - stop httpd
restart    - restart httpd if running
debug      - start httpd in the debugger
single     - start httpd in -X mode, no debugger

END

  exit;
}
