eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}'
    & eval 'exec perl -S $0 $argv:q'
    if 0;

# -*- perl -*-
# $Id$
#
# This script checkouts ACE from CVS, updates the "clone" directory,
# compiles $ACE_ROOT/ace and $ACE_ROOT/tests and finally runs
# $ACE_ROOT/tests/run_tests.sh.
#
# If it detects any problem it send email.
#
# DO NOT invoke this script from your crontab, use
# auto_compile_wrapper for that.
#
# This script requires Perl5.
#
# TODO: Modify the script or split it in such a way that the main copy
# can be obtained either using cvs or downloading the lastest beta
# from the WWW.
#

# The first three lines above let this script run without specifying the
# full path to perl, as long as it is in the user's PATH.
# Taken from perlrun man page.

use File::Basename;
use File::Copy;
use FileHandle;
require POSIX;

# This are the sub-directories (in the module) we really compile.

# Find out the command name.
$CMD = basename($0);

$dont_update = 0;
# $copy_logs = 1;
# $LOG_DESTINATION = $ENV{'HOME'}.'/.www-docs/auto_compile';

$copy_logs = 0;
$LOG_DESTINATION='bugzilla'.'@cs.wustl.edu';

$dont_build_tao = 0;
$dont_run = 0;
$makefile_suffix = "";
$pre_realclean = 0;
$post_realclean = 0;
$report_success = 0;
$debug = 0;
$sandbox = '';
$sandbox_timeout = 600;
$sendreport = 0;
@BUILD_LIST= ();
@CONFIGURATION_OPTIONS = ();

@ARGS = ();
while ($#ARGV >= 0) {
  if (!($ARGV[0] =~ m/^-/)) {
    push @ARGS, $ARGV[0];
  } elsif ($ARGV[0] eq "-single_threaded") {
    print STDERR "$CMD: obsolete option $ARGV[0], "
      ."please use -config instead\n";
    push @CONFIGURATION_OPTIONS, 'ST';
  } elsif ($ARGV[0] eq "-minimum_corba") {
    print STDERR "$CMD: obsolete option $ARGV[0], "
      ."please use -config instead\n";
    push @CONFIGURATION_OPTIONS, 'MINIMUM';
  } elsif ($ARGV[0] eq "-ami") {
    print STDERR "$CMD: obsolete option $ARGV[0], "
      ."please use -config instead\n";
    push @CONFIGURATION_OPTIONS, 'AMI';
  } elsif ($ARGV[0] eq "-smart_proxies") {
    print STDERR "$CMD: obsolete option $ARGV[0], "
      ."please use -config instead\n";
    push @CONFIGURATION_OPTIONS, 'SMART_PROXIES';
  } elsif ($ARGV[0] eq "-static") {
    print STDERR "$CMD: obsolete option $ARGV[0], "
      ."please use -config instead\n";
    push @CONFIGURATION_OPTIONS, 'STATIC';
  } elsif ($ARGV[0] eq "-config") {
    shift;
    push @CONFIGURATION_OPTIONS, $ARGV[0];
  } elsif ($ARGV[0] eq "-build_list") {
    shift;
    @BUILD_LIST = split (/,/, $ARGV[0]);
  } elsif ($ARGV[0] eq "-dont_update") {
    $dont_update = 1;
  } elsif ($ARGV[0] eq "-copy_logs") {
    shift;
    $copy_logs = 1;
    $LOG_DESTINATION = $ARGV[0];
  } elsif ($ARGV[0] eq "-sandbox") {
    shift;
    $sandbox = $ARGV[0];
  } elsif ($ARGV[0] eq "-sandbox_timeout") {
    shift;
    $sandbox_timeout = $ARGV[0];
  } elsif ($ARGV[0] eq "-dont_run") {
    $dont_run = 1;
  } elsif ($ARGV[0] eq "-pre_realclean") {
    $pre_realclean = 1;
  } elsif ($ARGV[0] eq "-post_realclean") {
    $post_realclean = 1;
  } elsif ($ARGV[0] eq "-report_success") {
    $report_success = 1;
  } elsif ($ARGV[0] eq "-debug") {
    $debug = 1;
  } elsif ($ARGV[0] eq "-sendreport") {
    $sendreport = 1;
  } elsif ($ARGV[0] eq "-notao") {
    $dont_build_tao = 1;
  } elsif ($ARGV[0] eq "-make_type") {
    shift;
    $makefile_suffix = $ARGV[0];
  } else {
    print "Ignoring option $ARGV[0]\n";
  }
  shift;
}

# Extract configuration information from command line.
  # TODO: Some validation and checking should be done here.
$CHECKOUT = $ARGS[0];
$BUILD    = $ARGS[1];
$LOGDIR   = $ARGS[2];
$ADMIN    = $ARGS[3];
$MAIL     = "mail";
if ($#ARGS >= 4) {
  $MAIL     = $ARGS[4];
}
$LOG_URL  = "http://ace.cs.wustl.edu/~bugzilla/auto_compile_logs/";
if ($#ARGS >= 5) {
  $LOG_URL = $ARGS[5];
}
# This is the module we will checkout unless a different one is on the
# command line.
$MODULE='ACE_wrappers';
if ($#ARGS >= 6) {
  $MODULE = $ARGS[6];
}

$ENV{'ACE_ROOT'} = $CHECKOUT . '/' . $MODULE . '/build/' . $BUILD;
$ENV{'TAO_ROOT'} = $CHECKOUT . '/' . $MODULE . '/build/' . $BUILD . '/TAO';

# We obtain our revision to report errors.
$REVISION='$Revision$ ';

# When an error is found we try to die gracefully and send some email
# to ADMIN.

$disable_file = $LOGDIR . '/.disable';
$histfile = $LOGDIR . '/history';
$LOGBASE = POSIX::strftime("%Y_%m_%d_%H_%M", localtime);
$LOGFILE = $LOGDIR . '/' . $LOGBASE . '.txt';
$HOST = `hostname`;
chop $HOST;
$LOG_NAME =  $HOST . '_' . $BUILD . '/' . $LOGBASE . '.txt';
$STATUS = "OK";

if ($debug) {
  print "CHECKOUT = $CHECKOUT\n";
  print "BUILD = $BUILD\n";
  print "LOGDIR = $LOGDIR\n";
  print "ADMIN = $ADMIN\n";
  print "MAIL = $MAIL\n";
  print "ACE_ROOT = $ENV{ACE_ROOT}\n";
  print "TAO_ROOT = $ENV{TAO_ROOT}\n";
  print "CONFIGURATION_OPTIONS = ", @CONFIGURATION_OPTIONS, "\n";
}

push @INC, $CHECKOUT . '/' . $MODULE . '/bin';

require PerlACE::ConfigList;

$config_list = new PerlACE::ConfigList;

$config_list->my_config_list (@CONFIGURATION_OPTIONS);

if ($#BUILD_LIST == -1) {
  if ($dont_build_tao) {
    @BUILD_LIST=('ace', 'netsvcs', 'tests');
  }
  else {
    @BUILD_LIST=('.', 'TAO');
  }
}

sub mydie {
  my $DEST_DIR = $LOG_DESTINATION.'/'.$HOST.'_'.$BUILD;
  mkdir $DEST_DIR,0755 if (!-d $DEST_DIR);
  if (open(STATUS, '>'.$DEST_DIR.'/status.txt')) {
    print STATUS "SCOREBOARD_STATUS: Inactive\n";
    close STATUS;
  }
  unlink $disable_file;
  die $_ . "\n";
}

@RUN_LIST = ();

if ($debug) {

  @BUILD_LIST = ('ace');
  @RUN_LIST = ('TAO/tests/OctetSeq/run_test.pl');
  $ADMIN = $ENV{'LOGNAME'};

} else {
  $config_list->load ($CHECKOUT . '/' . $MODULE . '/' . 'build/' . $BUILD . '/bin/auto_run_tests.lst');
  
  @RUN_LIST = $config_list->valid_entries ();
}

sub mail_logs {
  open (MAIL, "|".$MAIL.' -s AUTO_COMPILE_LOG='.$LOG_NAME.' '.$LOG_DESTINATION)
    || mydie "Cannot open mail pipe for: $LOG_NAME\n";

  print MAIL 'This is the log for: ', "\n";
  print MAIL $CMD, ' [', $REVISION, "] for $HOST/$BUILD\n";

  print MAIL "\n================================================================\n";

 if (open (THELOG, "$LOGFILE"))
    {
      while (<THELOG>) {
        print MAIL $_;
      }
      close (THELOG);
    }
  close (MAIL); # Ignore errors....
}

sub copy_logs {
  local $DEST_DIR = $LOG_DESTINATION.'/'.$HOST.'_'.$BUILD;
  mkdir $DEST_DIR,0755 if (!-d $DEST_DIR);

  copy($LOGFILE, $DEST_DIR.'/'.$LOGBASE.'.txt');

  local $MAKE_PRETTY="$CHECKOUT/$MODULE/bin/make_pretty.pl";
  system ("perl $MAKE_PRETTY -b -i $LOGFILE >$DEST_DIR/$LOGBASE"."_brief.html");
  system ("perl $MAKE_PRETTY    -i $LOGFILE >$DEST_DIR/$LOGBASE".".html");

  chmod 0644, $DEST_DIR.'/'.$LOGBASE.'.txt'
            , $DEST_DIR.'/'.$LOGBASE.'_brief.html'
            , $DEST_DIR.'/'.$LOGBASE.'.html' ;
}

sub report_errors {
  
  # First clear the lock, so the next execution works...
  unlink $disable_file; # Ignore errors!

  if ($sendreport) {
	# Now send a summary of the errors to the ADMIN account, if there are any.

	if ($#_ >= 0) {
	  local $to = $ADMIN;

	  open (MAIL, "|".$MAIL.' -s "[AUTO_COMPILE] '.$HOST.' '.$BUILD.'" '.$to)
	    || mydie "Cannot open mail pipe for: $_\n";

	  print MAIL 'The following message is brought to you by: ', "\n";
	  print MAIL $CMD, ' [', $REVISION, "] for $BUILD on $HOST\n\n";

	  print MAIL "\nPlease check the following log for more info:\n\n";
	  print MAIL $LOG_URL, '?', $HOST, '_', $BUILD, "\n\n";

	  local $m;
	  foreach $m (@_) {
	    print MAIL $m, "\n";
	  }
	  close (MAIL); # Ignore errors....
	}
  }
  
  # Now send the complete log to bugzilla...
  if ($copy_logs) {
    copy_logs ();
  } else {
    mail_logs ();
  }
}

### MAIN FUNCTION

if (-f $disable_file) {
  print 'The following message is brought to you by: ', "\n";
  print $CMD, ' [', $REVISION, "] for $BUILD on $CHECKOUT\n";

  print "DISABLED\n";

  exit 0;
}

open (DISABLE, '>' . $disable_file)
    || die "cannot open disable file <$disable_file>\n";
print DISABLE "auto_compile <$date> is running\n";
close (DISABLE)
    || die "cannot close disable file";

open(HIST, '>>' . $histfile)
    # Do not use 'mydie' to report the problem, it tries to remove the
    # disable file
    || mydie "cannot open history file \"$histfile\"\n";

$date = localtime;

print HIST $CMD, ': running at ', $date, ' ';

open(LOG, '>' . $LOGFILE)
    || mydie "cannot open log file";

LOG->autoflush ();

# The following lines are useful when debugging the script or wrapper.
# print LOG $CHECKOUT, " ", $BUILD, " ", $LOGDIR, " ", $ADMIN, "\n";
#while (($key,$value) = each %ENV) {
#  print LOG $key, " = ", $value, "\n";
#}

print LOG "#################### CVS\n";
my $DEST_DIR = $LOG_DESTINATION.'/'.$HOST.'_'.$BUILD;
mkdir $DEST_DIR,0755 if !-d $DEST_DIR;
if (open(STATUS, '>'.$DEST_DIR.'/status.txt')) {
  print STATUS "SCOREBOARD_STATUS: CVS\n";
  close STATUS;
}

chdir($CHECKOUT)
    || mydie "Cannot chdir to $CHECKOUT";

if ($dont_update == 0) {
  $date = localtime;
  print LOG "$CMD: starting checkout at ", $date, "\n";
  open(CVS, "cvs -q checkout -P $MODULE 2>&1 |")
    || mydie "cannot start checkout of $MODULE";

  $conflicts = 0;
  while (<CVS>) {
    if (m/^C /) {
      ($unused, $entry) = split('/');
      if (($entry ne "ChangeLog\n") && ($entry ne "THANKS\n")) {
        $conflicts = 1;
      }
    }
    print LOG $_;
  }
  close(CVS);
#    || mydie "error while checking out $MODULE";
  $date = localtime;
  print LOG "$CMD: checkout finished at ", $date, "\n";

  if ($conflicts != 0) {
    mydie "conflicts on checkout";
  }
}

chdir($MODULE)
    || mydie "cannot chdir to $MODULE";

$date = localtime;
print LOG "$CMD: starting clone at ", $date, "\n";
open(CLONE, "perl bin/create_ace_build -a -v $BUILD 2>&1 |")
    || mydie "cannot clone directory";
while(<CLONE>) {
    print LOG $_;
}
close(CLONE)
    || mydie "error while cloning ACE_ROOT";
$date = localtime;
print LOG "$CMD: clone finished at ", $date, "\n";

chdir('build/' . $BUILD)
    || mydie "cannot chdir to $BUILD";

@failures = ();

if ($makefile_suffix ne "") {
  $MAKEFLAGS = "-f Makefile.$makefile_suffix";
}

print LOG "#################### Compiler\n";
if (open(STATUS, '>'.$DEST_DIR.'/status.txt')) {
  print STATUS "SCOREBOARD_STATUS: Compile\n";
  close STATUS;
}

if ($pre_realclean) {
  foreach $i (reverse(@BUILD_LIST)) {
    $date = localtime;
    print LOG "$CMD: =============================================\n";
    print LOG "$CMD: make realclean in $i started at ", $date, "\n";
    open(MAKE, "make -k $MAKEFLAGS -C $i realclean 2>&1 |")
      || mydie "cannot start make in $i";

    while (<MAKE>) {
      # Ignore errors....
    }
    if (close(MAKE) == 0) {
        push @failures, "errors while cleaning $i";
    }
    $date = localtime;
    print LOG "$CMD: make realclean in $i finished at ", $date, "\n";
    print LOG "$CMD: =============================================\n\n";
  }
}

$MAKEFLAGS .= "";
foreach $i (@BUILD_LIST) {
    $date = localtime;
    print LOG "$CMD: =============================================\n";
    print LOG "$CMD: make for $i started at ", $date, "\n";
    open(MAKE, "make -k $MAKEFLAGS -C $i 2>&1 |")
        || mydie "cannot start make for $i";

    local $current_dir = $i;
    local $last_error = "";
    local $this_error = 0;
    local $this_warning = 0;
    while (<MAKE>) {
        chop;
        $this_error = $this_warning = 0;
        if ($^O eq 'hpux'
            && m/^Warning:[ \t]+[0-9]+ future errors were detected/) {
            next;
        }
        print LOG $_, "\n";

        if (m/^make(\[[0-9]+\])?: Entering directory /) {
            s/^make(\[[0-9]+\])?: Entering directory //;
            s%^$ENV{'ACE_ROOT'}/%%;
            $current_dir = $_;
        }
        if (m/error:/i || m/error /i
            || m/^make(\[[0-9]+\])?: \*\*\*/) {
            $this_error = 1;
        }
        if ($^O eq 'aix'
            && m/\d+-\d+ \([SI]\)/) {
            $this_error = 1;
        }
        if ($this_error) {
            if ($last_error ne $current_dir
                || STATUS eq "COMPILATION WARNING") {
              $STATUS = "COMPILATION ERROR";
              push @failures, "Error while compiling in $current_dir \n";
              $last_error = $current_dir;
            }
        }
        if (m/warning:/i
	    || m/warning /i
	    || m/Info: /i) {
            $this_warning = 1;
            if ($^O eq 'aix'
                && m/^ld: \d+-\d+ WARNING: Duplicate symbol: .*ACE.*/) {
                $this_warning = 0;
            }
        }
        if ($^O eq 'aix'
            && m/\d+-\d+ \(W\)/) {
            $this_warning = 1;
        }
        if ($this_warning) {
          if ($last_error ne $current_dir) {
            if ($STATUS eq "OK") {
              $STATUS = "COMPILATION WARNING";
            }
            push @failures, "Warning while compiling in $current_dir\n";
            $last_error = $current_dir;
          }
        }
    }
    if (close(MAKE) == 0) {
        push @failures, "errors while running make in $i";
    }
    $date = localtime;
    print LOG "$CMD: make for $i finished at ", $date, "\n";
    print LOG "$CMD: =============================================\n\n";
}

print LOG "#################### Tests\n";
if (open(STATUS, '>'.$DEST_DIR.'/status.txt')) {
  print STATUS "SCOREBOARD_STATUS: Tests\n";
  close STATUS;
}

if ($dont_run == 0) {
  my $config_params;
  if ($#CONFIGURATION_OPTIONS != -1) {
    $config_params = ' -Config ';
  }
  $config_params .= join ' -Config ', @CONFIGURATION_OPTIONS;

  foreach my $i (@RUN_LIST) {

    local $directory = '.';
    local $program = $i;

    if ($i =~ /(.*)\/([^\/]*)$/) {
        $directory = $1;
        $program = $2;
    }

    $date = localtime;
    print LOG "\n\n$CMD: ================  $date ================\n";
    print LOG "auto_run_tests: $i\n";
    local $subdir =
        $CHECKOUT .'/'. $MODULE .'/build/'. $BUILD .'/'. $directory;
    chdir ($subdir)
        || mydie "cannot chdir to $subdir";

    $run_error = 0;
    my $prefix = '';
    if ($sandbox ne "") {
      $prefix = $sandbox.' '.$sandbox_timeout.' ';
    }
    if (open(RUN, $prefix."perl $program $config_params 2>&1 |") == 0) {
        push @failures, "cannot run $program in $directory";
        next;
    }
    while (<RUN>) {
        print LOG $_;
        if (m/Error/
            || m/ERROR/
            || m/FAILED/
            || m/EXCEPTION/
            || m/pure virtual /i) {
          if ($STATUS eq "OK") {
            $STATUS = "RUNTIME ERROR";
          }
          $run_error = 1;
        }
    }
    if (close(RUN) == 0) {
      if ($STATUS eq "OK") {
        $STATUS = "RUNTIME ERROR";
      }
      print LOG "ERROR, non-zero status returned by test script\n";
      push @failures, "Error when closing pipe for $program in $directory";
      next;
    }
    $date = localtime;
    print LOG "$CMD: $program finished ", $date, "\n";

    if ($run_error != 0) {
      push @failures,
      "errors detected while running $program in $directory";
    }
  }
}

if ($post_realclean) {
  foreach $i (reverse(@BUILD_LIST)) {
    $date = localtime;
    print LOG "$CMD: =============================================\n";
    print LOG "$CMD: make realclean in $i started at ", $date, "\n";
    open(MAKE, "make -k $MAKEFLAGS -C $i realclean 2>&1 |");

    while (<MAKE>) {
      # Ignore errors....
    }
    if (close(MAKE) == 0) {
        push @failures, "errors while cleaning $i";
    }
    $date = localtime;
    print LOG "$CMD: make realclean in $i finished at ", $date, "\n";
    print LOG "$CMD: =============================================\n\n";
  }
}

print LOG "#################### Config\n";

chdir($CHECKOUT . "/" . $MODULE . "/build/" . $BUILD)
  || mydie "Cannot chdir to $CHECKOUT/$MODULE/build/$BUILD";

open (CONFIG, "perl bin/nightlybuilds/print_config.pl $CHECKOUT/$MODULE/build/$BUILD 2>&1 |")
  || mydie "Cannot run print_config.pl script";
while (<CONFIG>) {
  print LOG $_;
}
close (CONFIG)
  || mydie "Error while running print_config.pl script";

report_errors @failures;

print LOG "#################### End\n";
if (open(STATUS, '>'.$DEST_DIR.'/status.txt')) {
  print STATUS "SCOREBOARD_STATUS: Inactive\n";
  close STATUS;
}

close(LOG)
    || mydie "cannot close LOGFILE";

print HIST "$STATUS\n";
close(HIST)
    || mydie "cannot close history file";

unlink $disable_file
    || die "cannot unlink disable file";

if ($report_success && $STATUS eq "OK") {
  report_errors "Congratulations: No errors or warnings detected\n";
}

exit 0;
