#!/usr/bin/perl -w
# /Trilinos/commonTools/test/harness/runharness

################################################################################
# The Trilinos Project - runharness
# 
# Mike Phenow, Jim Willenbring
#
# This is the program used by the Trilinos Framework Developers to schedule
# and report the results of automated building and testing of the latest
# versions of Trilinos source.  This program is designed as a way to centrally
# control the intricacies of maintainting an automated build and test suite on
# a wide variety of distributed machines, each with their own demands and
# constraints.
#  
# This is *not intended* to be used by individual developers or users.  There
# is nothing to stop a user or developer from using it, but little support will
# be provided.  If you have a need for similar configure/build/test/report
# capability, see the utilities in commonTools/test/utilities.  Also, other
# programs, similar to this one but designed for a developer or user's use
# cases may be produced in the future.  If you have an interest in this,
# please send a note to trilinos-framework@software.sandia.gov detailing your
# needs.
#
################################################################################

use strict;

# Variable Declarations ========================================================

# Command line arguments:

my $trilinosDir;        # Trilinos directory            (required argument) 
my $buildName;          # Name of the build             (required argument) 
my $configFile;         # Config file to use            (default: ./config) 

my $verbosity;          # verbosity level               (default: 1)
my $logVerbosity;       # log file verbosity level      (default: 0)

my $shortCircuit;       # quit with a non-zero exit code as soon as anything fails
my $noUpdate;           # don't update
my $noReport;           # don't report
my $updated;            # have we been updated yet?

my $coverage;           # pass --coverage flag to runtests 

my $runStartTime;
my $runStartTimeForFilename;

# Constants
my $v0 = "0";           # quiet
my $v1 = "1";           # normal verbosity
my $v2 = "2";           # level 2 verbosity
my $v3 = "4";           # level 3 verbosity

# Grab program arguments for use with self-updating functionality (see cvsUpdate())
my @programArguments = @ARGV;
        
################################################################################
# Execution ####################################################################
################################################################################

getArgs();
if(!$noUpdate) { cvsUpdate(); }
init();

my $exitStatus = run();
cleanUp();
exit $exitStatus;

################################################################################
# Subroutines ##################################################################
################################################################################

    ############################################################################
    # getArgs()
    #
    # Parse command line arguments.
    #
    #   - args:     NONE
    #
    #   - returns:  NONE
    #

    sub getArgs {
        
        my $quiet;
        my $help;

        use Getopt::Long;
        GetOptions( "trilinos-dir=s" => \$trilinosDir,
                    "build-name=s" => \$buildName,
                    "short-circuit" => \$shortCircuit,
                    "no-update" => \$noUpdate,
                    "no-report" => \$noReport,
                    "coverage" => \$coverage,
                    "config-file=s" => \$configFile,
                    "verbosity=i" => \$verbosity,
                    "log-verbosity=i" => \$logVerbosity,
                    "updated" => \$updated,
                    "quiet" => \$quiet,
                    "help" => \$help );
        
        # Print help and exit.
        if ($help) { 
            printHelp();
            exit;
        }
        
        # Enforce and/or prepare arguments.
        
        # check for existance of trilinos-dir argument and actual directory
        if (!$trilinosDir) {
            die "trilinos-dir value required, see --help for more information\n"; 
        } else {
            if (!stat($trilinosDir)) {
                die "cannot stat trilinos-dir: $trilinosDir\n";
            }
        }
        
        # check for existance of build-name argument
        if (!$buildName) {
            die "build-name value required, see --help for more information\n"; 
        } 
        
        # check for existance of config-file argument and actual directory
        if ($configFile) {
            if (!stat($configFile)) {
                die "cannot stat config-file: $configFile\n";
            }
        } else {
            $configFile = "$trilinosDir/commonTools/test/harness/config";
        }
        
        # Set verbosity level to corresponding constant.  0, 1, 2, and 3 are
        # used for the levels the user may specify, but they are stored as 0,
        # 1, 2, and 4 so they can be combined and processed with bitwise
        # operations.
        if ($verbosity) {
            if      ($verbosity == 0) { $verbosity = $v0; }
            elsif   ($verbosity == 1) { $verbosity = $v1; }
            elsif   ($verbosity == 2) { $verbosity = $v2; }
            elsif   ($verbosity == 3) { $verbosity = $v3; }
        } else {
            $verbosity = $v1; 
        }
        
        # Set log verbosity level to corresponding constant.  Numbering scheme
        # is the same for the log verbosity as it is for the standard verbosity.
        # There is not distinct output and log output, the if a log verbosity
        # is given, then that level of output is written to a file instead of
        # to standard out.  
        if ($logVerbosity) {
            if      ($logVerbosity == 0) { $logVerbosity = $v0; }
            elsif   ($logVerbosity == 1) { $logVerbosity = $v1; }
            elsif   ($logVerbosity == 2) { $logVerbosity = $v2; }
            elsif   ($logVerbosity == 3) { $logVerbosity = $v3; }        
        } else {
            $logVerbosity = $v1; 
        }
        
        # Set quiet mode--same as passing --verbosity=0.
        if ($quiet) {
            $verbosity = $v0; 
        }
        
    } # getArgs()

    ############################################################################
    # cvsUpdate()
    #
    # Updates Trilinos from the CVS repository.
    #
    #   - args: 
    #
    #   - returns: 

    sub cvsUpdate {
        
        # If --updated flag is not set, update
        # If --updated flag is set, we've already updated and we've been
        #     replaced by the new, updated version of ourself--we want to skip
        #     this so we don't continue the process forever
        if (!$updated) {
        
            # If Trilinos3PL exists in the same directory as TrilinosRELEASE
            # (in the same directory as the directory containing $trilinosDir)
            # then update it as well.
            chdir "$trilinosDir" or die "cannot chdir to $trilinosDir, died";  
            if (! chdir "../../Trilinos3PL") {
                print "can't chdir to \"../../Trilinos3PL\", skipping update of Trilinos3PL\n";
            } else {
                my $output = `cvs -q update -dP 2>&1`;
                my $result = $?;
                if ($result) {
                    print "error updating Trilinos3PL";
                }
            }
        
            # If TrilinosData exists in the same directory as TrilinosRELEASE
            # (in the same directory as the directory containing $trilinosDir)
            # then update it as well.
            chdir "$trilinosDir" or die "cannot chdir to $trilinosDir, died";  
            if (! chdir "../../TrilinosData") {
                print "can't chdir to \"../../TrilinosData\", skipping update of TrilinosData\n";
            } else {
                my $output = `cvs -q update -dP 2>&1`;
                my $result = $?;
                if ($result) {
                    print "error updating TrilinosData";
                }
            }
            
            chdir "$trilinosDir" or die "cannot chdir to $trilinosDir, died";  
            my $output = `cvs -q update -dP 2>&1`;
            my $result = $?;
            if ($result) {
                die "error updating Trilinos, died";
            }

            # Finished updating.
            # Replace ourself with the new, updated version of ourselves.
            chdir "$trilinosDir/commonTools/test/harness";
            my $command = "perl $0 --updated ";
            foreach (@programArguments) { $command .= "$_ "; }
            exec $command;
        }
        
    } # cvsUpdate()

    ############################################################################
    # init()
    #
    # Prepares varibles.
    #
    #   - args:     NONE
    #
    #   - returns:  NONE
    #

    sub init {
    
        # Capture and format run start time.
        (my $se, my $mn, my $hr, my $da, my $mo, my $yr) = (localtime)[0..5];
        $yr = sprintf("%02d", $yr % 100);
        $mo = sprintf("%02d", $mo+1);
        $da = sprintf("%02d", $da);
        $hr = sprintf("%02d", $hr);
        $mn = sprintf("%02d", $mn);
        $se = sprintf("%02d", $se);
        $runStartTime = $yr."-".$mo."-".$da." ".$hr.":".$mn.":".$se;
        $runStartTimeForFilename = $yr."-".$mo."-".$da."_".$hr.".".$mn.".".$se;
        
        # Print list of variables for debugging.
        my $message = "";
        $message .= "init():\n";
        $message .= "  \$trilinosDir = $trilinosDir\n";
        $message .= "  \$verbosity = $verbosity\n";
        $message .= "  \$logVerbosity = $logVerbosity\n";
        $message .= "  \n";
        printMessage($message, $v3);
        
    } # init()
    
    ############################################################################
    # run()
    #
    # Runs runbuild and runtests as specified by the config file
    #
    #   - args:     NONE
    #
    #   - returns:  NONE
    #

    sub run {
        
        # cd to test utility directory.
        chdir "$trilinosDir/commonTools/test/utilities"
            or die "cannot chdir to $trilinosDir/commonTools/test/utilities, died";
    
        # List of runs, which are hashes of name/value properties
        my @buildListAoH;

        # Parse the config file, extracting run information
        (my $status, my @result) = parseConfig();
        if ($status) {
            printMessage ($result[0], $v1+$v2+$v3);
            return 1;
        } else {
            @buildListAoH = @result;
        }
        
        # Hash of build options from config file matching the given build-name
        my %buildOptions;
        
        # Find matching group from @buildListAoH
        for my $i (0 .. $#buildListAoH) {
            if ($buildName eq $buildListAoH[$i]{'BUILD-NAME'}) {
                %buildOptions = %{ $buildListAoH[$i] };
            }            
        }
        
        if (!%buildOptions) {
            die "cannot find build-name $buildName in the config file $configFile, died";
        } 
        
        my $argVerbosity;
        if      ($verbosity == $v0) { $argVerbosity = 0; }
        elsif   ($verbosity == $v1) { $argVerbosity = 1; }
        elsif   ($verbosity == $v2) { $argVerbosity = 2; }
        elsif   ($verbosity == $v3) { $argVerbosity = 3; }
        
        my $argLogVerbosity;
        if      ($logVerbosity == $v0) { $argLogVerbosity = 0; }
        elsif   ($logVerbosity == $v1) { $argLogVerbosity = 1; }
        elsif   ($logVerbosity == $v2) { $argLogVerbosity = 2; }
        elsif   ($logVerbosity == $v3) { $argLogVerbosity = 3; }
        
        my $cmd = "";
        my $output = "";
        $status = 0;
            
        # Run runbuild
        $cmd  = "perl runbuild ";
        $cmd .= "--trilinos-dir=$trilinosDir ";
        $cmd .= "--build-dir=".$buildOptions{'BUILD-DIR'}." ";
        $cmd .= "--invoke-configure=$trilinosDir/commonTools/test/harness/";
        $cmd .= "invoke-configures/".$buildOptions{'INVOKE-CONFIGURE'}." ";
        if ($buildOptions{'MAKE-COMMAND'}) {
            $cmd .= "--make-cmd=\"".$buildOptions{'MAKE-COMMAND'}."\" ";
        }
        if (!$shortCircuit) {
            $cmd .= "--recover ";
        }
        $cmd .= "--output-dir=$trilinosDir/commonTools/test/harness/results ";
        $cmd .= "--start-time=$runStartTimeForFilename ";
        $cmd .= "--verbosity=$argVerbosity ";
        $cmd .= "--log-verbosity=$argLogVerbosity ";
        $status = system("$cmd");
        my $skipTests = 0;
        if ($status != 0) { 
            $skipTests = 1;
            if ($shortCircuit) {
                print "short-circuit mode:  build failed:  quitting.\n";
                return 77;
            }
        }
    
        # Capture and format build end time.
        (my $se, my $mn, my $hr, my $da, my $mo, my $yr) = (localtime)[0..5];
        $yr = sprintf("%02d", $yr % 100);
        $mo = sprintf("%02d", $mo+1);
        $da = sprintf("%02d", $da);
        $hr = sprintf("%02d", $hr);
        $mn = sprintf("%02d", $mn);
        $se = sprintf("%02d", $se);
        my $buildEndTime = $yr."-".$mo."-".$da." ".$hr.":".$mn.":".$se;
            
        # Create build info file for database.
        my $buildInfoFile = "$trilinosDir/commonTools/test/harness/results";
        $buildInfoFile .= "/$runStartTimeForFilename-build/build.txt.tmp2";
        open (BUILD_FILE, ">>$buildInfoFile")
            or die "can't open build info file $buildInfoFile for writing, died";            
        my $string = "";        
        $string .= "BUILD_LABEL          = ".$buildOptions{'BUILD-LABEL'}."\n";
        $string .= "BUILD_START_TIME     = $runStartTime\n";
        $string .= "BUILD_END_TIME       = $buildEndTime\n";       
        $string .= "TIME_ZONE            = ".`date +%Z`."\n";    
        $string .= "BUILD_DIR            = ".$buildOptions{'BUILD-DIR'}."\n";
        $string .= "COMM                 = ".$buildOptions{'COMM'}."\n";  
        print BUILD_FILE $string;        
        close BUILD_FILE;
        $cmd = "mv $buildInfoFile $trilinosDir/commonTools/test/harness";
        $cmd .= "/results/$runStartTimeForFilename-build/build.txt > /dev/null 2>&1";
        system("$cmd");
                                                
        # Grab general information values for inclusion in machine info file. 
        my $hostName = "";          my $dnsName = "";           my $ipAddress = "";     
        my $operatingSystem = "";   my $kernelName = "";        my $kernelRelease = "";
        my $kernelVersion = "";     my $processor = "";         my $machineHardware = "";
        my $hardwarePlatform = "";  my $badCmd = 0;          
        $badCmd = system('hostname -s > /dev/null 2>&1');
        if (!$badCmd) { 
            chomp($hostName=`hostname -s`); 
        } else { 
            $badCmd = system('uname -n > /dev/null 2>&1');
            if (!$badCmd) { chomp($hostName=`uname -n`); }
        }
        $badCmd = system('hostname -d > /dev/null 2>&1');
        if (!$badCmd) { chomp($dnsName=`hostname -d`); }
        $badCmd = system('hostname -i > /dev/null 2>&1');
        if (!$badCmd) { chomp($ipAddress=`hostname -i`); }
        $badCmd = system('uname -o > /dev/null 2>&1');
        if (!$badCmd) { chomp($operatingSystem=`uname -o`); }
        $badCmd = system('uname -s > /dev/null 2>&1');
        if (!$badCmd) { chomp($kernelName=`uname -s`); }
        $badCmd = system('uname -r > /dev/null 2>&1');
        if (!$badCmd) { chomp($kernelRelease=`uname -r`); }
        $badCmd = system('uname -v > /dev/null 2>&1');
        if (!$badCmd) { chomp($kernelVersion=`uname -v`); }
        $badCmd = system('uname -p > /dev/null 2>&1');
        if (!$badCmd) { chomp($processor=`uname -p`); }
        $badCmd = system('uname -m > /dev/null 2>&1');
        if (!$badCmd) { chomp($machineHardware=`uname -m`); }
        $badCmd = system('uname -i > /dev/null 2>&1');
        if (!$badCmd) { chomp($hardwarePlatform=`uname -i`); }
            
        # Create machine info file for database.
        my $machineInfoFile = "$trilinosDir/commonTools/test/harness/results/$runStartTimeForFilename-build/machine.txt";
        open (MACHINE_FILE, ">$machineInfoFile")
            or die "can't open machine info file $machineInfoFile for writing, died";            
        $string = "";        
        $string .= "HOST_NAME            = $hostName\n";
        $string .= "DNS_NAME             = $dnsName\n";
        $string .= "IP_ADDRESS           = $ipAddress\n";
        $string .= "OPERATING_SYSTEM     = $operatingSystem\n";
        $string .= "KERNEL_NAME          = $kernelName\n";
        $string .= "KERNEL_RELEASE       = $kernelRelease\n";
        $string .= "KERNEL_VERSION       = $kernelVersion\n";
        $string .= "PROCESSOR            = $processor\n";
        $string .= "MACHINE_HARDWARE     = $machineHardware\n";
        $string .= "HARDWARE_PLATFORM    = $hardwarePlatform\n";     
        print MACHINE_FILE $string;        
        close MACHINE_FILE;
        
        # Run runtests
        if (!($skipTests || (defined $buildOptions{'BUILD-ONLY'} && $buildOptions{'BUILD-ONLY'} =~ m/YES/i))) {
            $cmd  = "perl runtests ";
            $cmd .= "--trilinos-dir=$trilinosDir ";
            $cmd .= "--build-dir=".$buildOptions{'BUILD-DIR'}." ";
            $cmd .= "--comm=".$buildOptions{'COMM'}." ";
            $cmd .= "--category=".$buildOptions{'TEST-CATEGORY'}." ";
            if ($buildOptions{'MAX-PROC'}) {    
                $cmd .= "--max-proc=".$buildOptions{'MAX-PROC'}." ";   
            }
            if ($buildOptions{'MPI-START'}) {   
                $cmd .= "--mpi-start=\"".$buildOptions{'MPI-START'}."\" ";       
            }
            if ($buildOptions{'MPI-PING'}) {   
                $cmd .= "--mpi-ping=\"".$buildOptions{'MPI-PING'}."\" ";       
            }
            if ($buildOptions{'MPI-STOP'}) {   
                $cmd .= "--mpi-stop=\"".$buildOptions{'MPI-STOP'}."\" ";       
            }
            if ($buildOptions{'MPI-GO'}) {   
                $cmd .= "--mpi-go=\"".$buildOptions{'MPI-GO'}."\" ";       
            }
            if ($coverage) {
                $cmd .= "--coverage ";       
            }
            if ($shortCircuit) {
                $cmd .= "--short-circuit ";
            }
            $cmd .= "--output-dir=$trilinosDir/commonTools/test/harness/results/";
            $cmd .= "$runStartTimeForFilename-build ";
            $cmd .= "--simple-dir-name ";
            $cmd .= "--verbosity=$argVerbosity ";
            $cmd .= "--log-verbosity=$argLogVerbosity ";
            $output = `$cmd`;
            $status = $?;
            if ($status != 0) {
                if ($shortCircuit) {
                    print "short-circuit mode:  test failed:  quitting.\n";
                    return 77;
                }
                return 1;
            }
        }
                   
        # Run report
        if (!$noReport) {
            $cmd  = "perl report ";
            $cmd .= "--ttr-dir=".$buildOptions{'TTR-DIR'}." ";
            $cmd .= "--results-dir=$trilinosDir/commonTools/test/harness/results/";
            $cmd .= "$runStartTimeForFilename-build ";
            $cmd .= "--ssg-username=".$buildOptions{'SSG-USERNAME'}." ";
            $cmd .= "--verbosity=$argVerbosity ";
            $output = `$cmd`;
            $status = $?;
            if ($status != 0) { 
                return 1;
            }
        }
        
        return 0;       
        
    } # run()
    
    ############################################################################
    # parseConfig()
    #
    # Parse config file and return data in configAoH.
    #
    #   - args:     NONE
    #
    #   - returns:  $configAoH       (array of runs, which contain...
    #                                    hashes of property names/values.)
    #

    sub parseConfig {
    
        my $status = 0;
        my $errorString = "";
    
        # Array of hashs of arrays that will be returned when all is said and done.
        my @configAoH = ();
        
        # Open config file for reading.
        open (CONFIG, "<$configFile") or die "Can't open config file, died";
            
        # Read config file into one string.
        undef $/;               # undefine input record separator
        my $file=<CONFIG>;      # copy entire file
        $/ = "\n";              # restore it to default newline
        close CONFIG;
        
        # Clean up file.
        $file =~ s/#.*$//mg;        # remove everything after any #
        $file =~ s/\n\s*\n/\n/g;    # remove any blank lines
        $file =~ s/^\s*//mg;        # remove leading spaces
        $file =~ s/\s*$//mg;        # remove trailing spaces
        $file =~ s/\n//g;           # remove all newlines (force ourselves
                                    # to avoid making assumptions about formatting)
        
        # Split config file into groups.
        # This gives us an array of strings of the essential form (.*){.*}.
        my @rawRunGroups = $file =~ m/(\(.*?\)\s*\{.*?\})/g;
        
        # Step through the list of raw run groups, parsing each with
        # parseRunGroup() and adding to the array.
        foreach my $rawRunGroup (@rawRunGroups) {
            (my $failures, my %result) = parseRunGroup($rawRunGroup);
            if (!$failures) {
                push(@configAoH, { %result });
            } else {
                $status += $failures;
                $errorString .= $result{"errorString"};
            }
        }
        
        # print @configAoH
        my $message = "";
        $message .= "parseConfig():\n";
        $message .= "  \@configAoH:\n";
        for my $i (0 .. $#configAoH) {
            $message .= "    run group $i:\n";
            foreach my $key (keys %{ $configAoH[$i] }) { 
                $message .= "      $key: $configAoH[$i]{$key}\n";
            }
        }
        $message .= "\n";
        printMessage($message, $v3);
        
        if (!$status) {         # Return properly parsed config file.
            return ($status, @configAoH);
        } else {                # Return $errorString string.
            return ($status, ($errorString));
        }
    
    } # parseConfig()
    
    ############################################################################
    # parseRunGroup()
    #
    # Given a raw {.*} string, parse it into a hash.
    #
    #   - args:     $rawGroupString     (raw (.*){.*} string)
    #
    #   - returns:  $status             (success(0)/failure(!0) status)
    #               %runGroup           (hash of property names/values.)
    #               $errorString        (record of malformed group error messages)
    #

    sub parseRunGroup {
        my $rawGroupString = $_[0];
        
        my $status = 0;
        my $errorString = "";
    
        # Hash that will be returned when all is said and done.
        my %runGroup = ();
        
        # Break raw string into category (.*) and property {.*} sections 
        my $propertyListString = "";
        if ($rawGroupString =~ m/\((.+?)\)\s*\{(.+?)\}/) {
            $runGroup{'BUILD-NAME'} = $1;
            $propertyListString = $2;
        } else {
            $status++;
            $errorString .= "! Malformed test group:  incorrect grouping.\n";
        }
        
        # Property section {.*}:       
        # Grap each raw 'PROPERTY = VALUE-1, VALUE-N;' string.
        my @rawPropertyStrings = $propertyListString =~ m/(.+?;)/g;        
        foreach my $propertyString (@rawPropertyStrings) {
                    
            # Grab property name & value.
            my $key = "";
            my $value = "";
            if ($propertyString =~ m/\s*((\w|-)+?)\s*=\s*(.*?);/) {
                $key = $1;
                $value = $3;
            } else {
                $status++;
                $errorString .= "! Malformed test group:  bad property list.\n";
            }
            
            # Add new key=>(values) entry in array.
            if (!$runGroup{$key}) {
                $runGroup{$key} = $value;
            } else {
                $runGroup{$key} .= $value;
            }
        }
        
        # Validate test group:
        
        # Enforce existance of BUILD-DIR property.
        if (!$runGroup{'BUILD-DIR'}) {
            $status++;            
            $errorString .= "! Malformed test group:  no BUILD-DIR property.\n";
        }
        
        # Enforce existance of COMM property.
        if (!$runGroup{'COMM'}) {
            $status++;            
            $errorString .= "! Malformed test group:  no COMM property.\n";
        }
        
        # Enforce existance of INVOKE-CONFIGURE property.
        if (!$runGroup{'INVOKE-CONFIGURE'}) {
            $status++;            
            $errorString .= "! Malformed test group:  no INVOKE-CONFIGURE property.\n";
        }
        
        # Add more validations as necessary to catch errors sooner...
        
        if (!$status) {         # Return properly parsed test group.
            return ($status, %runGroup);
        } else {                # Return $errorString string.
            return ($status, ("errorString", $errorString));
        }
    
    } # parseRunGroup()

    ############################################################################
    # cleanUp()
    #
    # Clean up environment variables, temp files, etc.
    #
    #   - args:     NONE
    #
    #   - returns:  NONE
    #

    sub cleanUp {
    
        # Currently, there is nothing to clean up, but I will leave this
        # subroutine here for potential future use.
           
    } # cleanUp()
    
    ############################################################################
    # printMessage()
    #
    # Prints an event if the verbosity is set.
    #
    #   - args:     $message        (message to be printed)
    #               $level          (verbosity level of message)
    #
    #   - returns:  NONE
    #

    sub printMessage {
        my $message = $_[0];
        my $level = $_[1];
        
        if ($verbosity & $level) {
            print $message;
        }
        
        if ($logVerbosity & $level) {
            my $log = "log-$runStartTimeForFilename.txt";
            open (LOG, ">>$log")
                or die "can't open $log";
            print LOG $message;
            close LOG;
        }
    } # printMessage()

    ############################################################################
    # printHelp()
    #
    # Prints help output.
    #
    #   - args:     NONE
    #
    #   - returns:  NONE
    #

    sub printHelp {
        print "runharness - The Trilinos Framework Test Harness\n";
        print "\n";
        print "Usage:  perl runharness --trilinos-dir=/home/user/Trilinos\n";
        print "        --build-name=beowulf-nightly-serial\n";
        print "\n";
        print "Options:\n";
        print "\n";
        print "  --trilinos-dir=DIR         Specify the absolute path to the top-level\n";
        print "                             Trilinos directory that contains this program.\n";
        print "                             Example: /home/user/Trilinos\n";
        print "                             REQUIRED.\n";
        print "\n";
        print "  --build-name=NAME          Specify the name of the build to perform as\n";
        print "                             given in the parenthesis of a \"run\"\n";
        print "                             definition.\n";
        print "                             Example: beowulf-nightly-serial\n";
        print "                             REQUIRED.\n";
        print "\n";
        print "  --short-circuit            Quit with a non-zero exit code as soon as\n";
        print "                             anything fails.\n";
        print "\n";
        print "  --no-update                Skip updating the repository.\n";
        print "\n";
        print "  --no-report                Skip reporting the results.\n";
        print "\n";
        print "  --config-file=FILE         Specify the path to the runharness config\n";
        print "                             file containing the given build name. If not\n";
        print "                             given, the standard config file in the\n";
        print "                             commonTools/test/harness directory will be\n";
        print "                             used.\n";
        print "                             Example: /home/user/config\n";
        print "\n";
        print "  --verbosity=LEVEL          0 = no non-fatal ouput (same as --quiet)\n";
        print "                             1 = normal output (default)\n";
        print "                             2 = level 2 verbosity\n";
        print "                             3 = level 3 verbosity\n";
        print "\n";
        print "  --log-verbosity=LEVEL      0 = no log\n";
        print "                             1 = normal output (default)\n";
        print "                             2 = level 2 verbosity\n";
        print "                             3 = level 3 verbosity\n";
        print "\n";
        print "  --help                     Print this help output and exit.\n";
        print "\n";
        print "Notes:\n";
        print "  - For more information, see README in\n";
        print "    Trilinos/commonTools/test/harness/\n";
        print "    or visit http://software.sandia.gov/trilinos/developer/\n";
        print "\n";
    } # printHelp()
