#!/usr/bin/perl
#syntax one of: wraptests filename directory                 to run all accounts

#               wraptests filename directory seas            to run all accounts alphabetically 
#strictly AFTER seas which is useful if seas crashed, then this continues after that student.  
#wraptest echos to screen the current seas account so that it is easy to see which was the one 
#that caused a crash/infinite loop/etc.
#               wraptests filename directory seas [redo] anything      to run ONLY seas

#If $redo is set to 0 (should be done after runtest script and test cases are finalized), then 
#wraptest will only call runtests for those students who do not have a results file.  It 
#currently does NOT check that the newest submission is older then the results file.  Note that
#the rename script will report new resubmissions (see rename for details and limitations). If the
#redo option is the word 'redo', then wraptest will call runtests even if there is a results file.
#By setting $redo=1, the script will always run in redo, helpful during debugging of runtests.
#see also the current alias' in glogin: wt, rt, ng, and ren.

#filename is the name of the submission ($filename), directory ($script_dir) is the name of the 
#directory containing the relevant runtests
#executes $home/$script_dir/runtests in each student directory. 
#Last code in this script is a call to system ("@commands"), change system to print and it will 
#output the commands it would have executed.

#In Perl, $ is a scalar variable (number, string, etc), @ is an array, % is a hash.
#array look up is $array[index], hash get is $hash{key}, $ is b/c result is a scalar variable
#There aren't any hashes in this script.

#$skips is a space separated list of students whose code should be skipped.  Useful if no ahead of 
#time (b/c of rerunning script) that a student's code will infinite loop. Can also handle them 
#separately (see end of code) if it is known what tests to skip.

$filename=shift @ARGV;			#exact filename
$script_dir=shift @ARGV;	 	#directory with runtests script in it
$home="/u/cs/class/cs131/cs131xx";	#home directory
$errorfile="$script_dir-error";	#for compilation error output, mainly for Java
$resultsfile="$script_dir-results";	#output file of runtests
$redo=0;				#flag==1 -->rerun runtests even if results present

unless ($filename && $script_dir) {
  print "Syntax is wraptest filename directory [seas] [opt]\n";
  exit;
}


#$skips='';

$start=shift @ARGV;		#get a starting seas directory
if ($start eq "redo") {
  $start='';
  $redo=1;
}
elsif ($start eq "this") {
  $redo=1;
  $temp=`pwd`;
  ($start) = $temp =~ m:/(\w+)\n:;
  $ARGV[0]=1;
}
if ($ARGV[0] eq "redo") {	#redo present?
  $redo=1;
  shift @ARGV;
}
if (@ARGV) {			#'anything' was present, so just run on seas which is in $start
  $files[0]="$start";
}
else {
  @files=`ls $home/*/$filename`;	#get list of all submissions, assumes rename already run
	#shells out, runs ls, each line is a file and each line is element of array @files.
  map {s:$home/(\w+)/$filename.*:$1:so} @files;	#strips off filename so that it is now a directory
  shift @files if ($files[0] eq "$script_dir"); #I use capital names for script dir so it will be 
	#first if present, present if file with submission name is there from testing
  while ($start && $#files>=0) {	#if have starting account then skip past it using shift
    $start="" if ($files[0] eq $start);	#found start, remove it and stop shifting afterwards
    shift @files;
  }
}
shift @files while ($files[0]=~ m:[A-Z]:);
require "$home/$script_dir/runtests";

$count=0;
foreach $dir (@files) {
#  next if ($skips =~ m:\b$dir\b:);	#\b so that if xyz isn't skipped b/c axyzb is in list
  next if (!$redo && (-f "$home/$dir/$resultsfile") );  # skip if results present and not redoing
  if ((-e "$home/$dir/$errorfile"       && -s "$home/$dir/$errorfile"      ) ||#no compile student
      (-e "$home/$dir/${errorfile}Test" && -s "$home/$dir/${errorfile}Test")) {#no compile driver
    `echo \"Did not compile\n\nFinal Score is 0\n\" > $resultsfile`;
  }
  else {
    print "    $dir\n";
    chdir "$home/$dir";
    if (-f "$home/$dir/$resultsfile") {rename  $resultsfile, "$resultsfile.bak";}
#    if (-f "$home/$dir/$resultsfile") {rename  $resultsfile, "$resultsfile.orig";}
    if (-f "$home/$dir/${errorfile}Run") {rename  "${errorfile}Run", "${errorfile}Run.bak";}
    &runtests; # >${errorfile}Run 2>&1\n";}
  }
}
&killbad;

#This loop will go through the seas accounts listed in $skips and try them on a subset of the test 
#cases.  This is useful if there are a couple of cases that a lot of people crash/loop on.  Only 
#does this if not testing 1 single seas account and if $skips contains people. Runtests is assumed 
#to support parameters indicating tests to skip.  For my code, runtests N would skip test N, 
#runtests X M-N Y would skip tests M through N, test X and test Y.  So list here whichever tests 
#are causing the problem. May still have to test them individually

#if (!@ARGV && $skips) {	
#  $loops="1 5-8";	#put tough tests here
#  push @commands, "echo 'Trying skips'\n";
#  @files=sort split (/\s+/, $skips);	#try them in alphabetical order, if they still crash
#	#easier to track which ran if in order.
#  foreach $dir (@files) {
#    push @commands, "echo \"    $dir\"\ncd $home/$dir\n$home/$script_dir/runtests $loops\n";
#  }
#}


sub killbad {
#this is specialized for speed versus killbad in Scripts directory
#also avoids shell for killbad and recompilation.
  my @procs=`ps -u cs131xx`;
  shift @procs;
  foreach $ps (@procs) {kill 9, $1 if ($ps =~ m:\s+(\d+)\s.*\bmzscheme\b:);}
}
