eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' & eval 'exec perl -S $0 $argv:q' if 0; # -*- perl -*- # 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 latest 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 () { 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 () { 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() { 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 () { # 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 () { 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 () { 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 () { # 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 () { 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;