<commit_before>#!/bin/bash
#
#This script compiles, runs, records output, and diff's student submissions.
#
#We assume that ./organize.sh has been run prior to executing this script (as
#   in the lab folder passed-in has been "organized") and that the provided,
#   test, and expected output files are stored in the correct folders
#
#Authors:
#
#   <NAME> @schuylermartin45
#

#Work through the sym links back to the script's actual running directory 
SOURCE="${BASH_SOURCE[0]}"
while [ -h "${SOURCE}" ]; do 
    DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
    SOURCE="$(readlink "${SOURCE}")"
    [[ ${SOURCE} != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
declare -r DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
#load up the common library
source ${DIR}"/.commonLib.sh"

####  CONSTANTS  ####
declare -r USAGE="Usage: ./batchRun.sh [-q] [-t] [time_out] #_tests lab exec_file"

#file extensions for comparison purposes; does not include dot for pattern 
#   purposes (issue with escaping the character in a variable)
declare -r EXT_JAVA="java"
declare -r EXT_PY="py"

#timeout exits with a 124 error code
declare -r TIME_ERR=124

####    FLAGS    ####
#All flags are = 0 for on

#User-specified timeout for the program runs
TIMEFLAG=1

#### GLOBAL VARS ####
#Default timeout given to a program's run time; this value can change with flag
TIME_OUT="60s"

#values passed in
#number of tests to run
numTests=0
#path to lab
labDIR=""
#file that gets run
execFile=""

#determined file type for this lab
fileType=""

#array of test arguments; one index for test
testArgs=()
#expected output files for each test; these are the files we diff against
expectedOut=()

#compile-order of Java files; specified input as a string of args
javaCompile=""

#global stat tracking
statComplete=0
statFail=0
statTime=0
#only applies to Java programs
statCompile=0

####  FUNCTIONS  ####

#Determine if this is a Python (CS1) or Java (CS2) lab
#   Exits the script if a file type can't be determined
#@param: 
#
#@return: 
#
#@global:
#        - execFile used to determine the type of project
#        - fileType type of lab this is
function determineFileType {
    local check=""
    check="$(echo "${execFile}" | grep -oe ".*\.${EXT_PY}$")"
    if [[ ! -z ${check} ]]; then
        fileType=${EXT_PY}
    fi
    check="$(echo "${execFile}" | grep -oe ".*\.${EXT_JAVA}$")"
    if [[ ! -z ${check} ]]; then
        fileType=${EXT_JAVA}
        #ask for compilation order; to pass directly to javac
        read -p "Enter files to compile: " javaCompile
    fi
    if [[ -z ${fileType} ]]; then
        echoerr "Lab type (Java/Python) could not be determined."
        echoerr "Make sure your directory structure is correct"
        echoerr "Exiting..."
        exit 1
    fi
}

#Asks for the arguments to pass to each program for each test and stores them
#as a list of test arguments; for simplicity files 
#@param: 
#
#@return: 
#
#@global:
#        - testArgs List of test arguments that is set
function testArgMenu {
    local index=0
    #pathing to test files relative to file execution
    local labPath="$(echo "${labDIR}" | sed 's/\//\\\//g')"
    local relPath="${labPath}\/${TEST_DIR}\/"
    #subsitution system to handle relative pathing to files in test_files
    local subsArray=()
    #don't ask for files to diff against if they aren't in the folder
    local askForDiff=0
    echosucc "==== Setting Test Arguments ===="
    #display all files in the test files folder, for user's convenience
    #Note that users can use substitutions ($n) to automatically handle
    #pathing to the test files; users can also manually do this
    if [[ -z "$(ls ${labDIR}/${TEST_DIR})" ]]; then
        #warn that test files are missing
        echowarn "No files were found in the ${TEST_DIR} directory"
    else
        echo "Files found in the ${TEST_DIR} directory:"
        for file in "${labDIR}/${TEST_DIR}"/*; do
            echo "    \$${index} = $(basename "${file}")"
            subsArray[${index}]="${relPath}$(basename "${file}")"
            let index++
        done
        echo "Use '\$num' to automatically substitute-in these files and paths"
    fi
    #display all files in the expected output files folder
    #Note that the subsitution system is not applied here because there
    #should only need to be one file to diff against, not a list of args
    if [[ -z "$(ls ${labDIR}/${EXPECTED_DIR})" ]]; then
        #warn that test files are missing
        echowarn "No files were found in the ${EXPECTED_DIR} directory"
        askForDiff=1
    else
        echo "Files found in the ${EXPECTED_DIR} directory:"
        for file in "${labDIR}/${EXPECTED_DIR}"/*; do
            echo "    $(basename "${file}")"
        done
    fi
    #read in the arguments
    local i=0
    local args=""
    local exOutFile=""
    while [[ $i -lt ${numTests} ]]; do
        #do not check input(s) for empty strings, in case a program doesn't
        #need arguments or have expected output files to test against
        read -p "Enter args for test[$i]: " args
        #parse through subsitutions
        local cntr=0
        for sub in "${subsArray[@]}"; do
            args="$(echo "${args}" | sed 's/$'"${cntr}"'/'"${sub}"'/g')"
            let cntr++
        done
        testArgs[$i]="${args}"
        if [[ ${askForDiff} = 0 ]]; then
            read -p "Enter an expected output file for test[$i]: " exOutFile
            expectedOut[$i]="${exOutFile}"
        fi
        let i++
    done
}

#Copy all provided files into a student's directory
#   This will not stomp over any files with the same name; if students submit
#   modified files they were not supposed to change, their programs will fail 
#   to run initially, but the original will be preserved for partial credit
#   Note: these backups will be hidden and numbered
#@param: 
#        $1 current student directory
#
#@return: 
#
#@global:
#
function cpProvidedFiles {
    local stuDIR="$1"
    local file=""
    local errCode=0
    #check if the provided_files directory is empty
    if [[ ! -z "$(ls "${labDIR}/${PROVIDED_DIR}/")" ]]; then
        echo "Starting to copy provided files for $(basename "${stuDIR}")"
        for file in "${labDIR}/${PROVIDED_DIR}/"*; do
            cp --backup=t "${file}" "${stuDIR}"
            errCode=$?
            if [[ ${errCode} = 0 ]]; then
                echosucc "Successfully copied ${file}"
            else
                echoerr "Failed to copy ${file} with error code: ${errCode}"
            fi
        done
    fi
}

#Run a Python program
#@param:
#        $1 Path to student's directory
#        $2 Test number
#@return:
#        - errCode Exit Code returned after run
#@global:
#
function runPy { 
    local stuDIR="$1"
    local testNum=$2
    errCode=0
    #location to store output
    local outFile="${stuDIR}${OUTPUT_DIR}/${OUT_FILE}${execFile%.*}_$i"
    #set a processing time-out per execution, push test arguments in (CS1 does 
    #not go over cmd line args and uses user input instead) and records output<commit_msg>Will now copy directories in provided files<commit_after>#!/bin/bash
#
#This script compiles, runs, records output, and diff's student submissions.
#
#We assume that ./organize.sh has been run prior to executing this script (as
#   in the lab folder passed-in has been "organized") and that the provided,
#   test, and expected output files are stored in the correct folders
#
#Authors:
#
#   <NAME> @schuylermartin45
#

#Work through the sym links back to the script's actual running directory 
SOURCE="${BASH_SOURCE[0]}"
while [ -h "${SOURCE}" ]; do 
    DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
    SOURCE="$(readlink "${SOURCE}")"
    [[ ${SOURCE} != /* ]] && SOURCE="${DIR}/${SOURCE}"
done
declare -r DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
#load up the common library
source ${DIR}"/.commonLib.sh"

####  CONSTANTS  ####
declare -r USAGE="Usage: ./batchRun.sh [-q] [-t] [time_out] #_tests lab exec_file"

#file extensions for comparison purposes; does not include dot for pattern 
#   purposes (issue with escaping the character in a variable)
declare -r EXT_JAVA="java"
declare -r EXT_PY="py"

#timeout exits with a 124 error code
declare -r TIME_ERR=124

####    FLAGS    ####
#All flags are = 0 for on

#User-specified timeout for the program runs
TIMEFLAG=1

#### GLOBAL VARS ####
#Default timeout given to a program's run time; this value can change with flag
TIME_OUT="60s"

#values passed in
#number of tests to run
numTests=0
#path to lab
labDIR=""
#file that gets run
execFile=""

#determined file type for this lab
fileType=""

#array of test arguments; one index for test
testArgs=()
#expected output files for each test; these are the files we diff against
expectedOut=()

#compile-order of Java files; specified input as a string of args
javaCompile=""

#global stat tracking
statComplete=0
statFail=0
statTime=0
#only applies to Java programs
statCompile=0

####  FUNCTIONS  ####

#Determine if this is a Python (CS1) or Java (CS2) lab
#   Exits the script if a file type can't be determined
#@param: 
#
#@return: 
#
#@global:
#        - execFile used to determine the type of project
#        - fileType type of lab this is
function determineFileType {
    local check=""
    check="$(echo "${execFile}" | grep -oe ".*\.${EXT_PY}$")"
    if [[ ! -z ${check} ]]; then
        fileType=${EXT_PY}
    fi
    check="$(echo "${execFile}" | grep -oe ".*\.${EXT_JAVA}$")"
    if [[ ! -z ${check} ]]; then
        fileType=${EXT_JAVA}
        #ask for compilation order; to pass directly to javac
        read -p "Enter files to compile: " javaCompile
    fi
    if [[ -z ${fileType} ]]; then
        echoerr "Lab type (Java/Python) could not be determined."
        echoerr "Make sure your directory structure is correct"
        echoerr "Exiting..."
        exit 1
    fi
}

#Asks for the arguments to pass to each program for each test and stores them
#as a list of test arguments; for simplicity files 
#@param: 
#
#@return: 
#
#@global:
#        - testArgs List of test arguments that is set
function testArgMenu {
    local index=0
    #pathing to test files relative to file execution
    local labPath="$(echo "${labDIR}" | sed 's/\//\\\//g')"
    local relPath="${labPath}\/${TEST_DIR}\/"
    #subsitution system to handle relative pathing to files in test_files
    local subsArray=()
    #don't ask for files to diff against if they aren't in the folder
    local askForDiff=0
    echosucc "==== Setting Test Arguments ===="
    #display all files in the test files folder, for user's convenience
    #Note that users can use substitutions ($n) to automatically handle
    #pathing to the test files; users can also manually do this
    if [[ -z "$(ls ${labDIR}/${TEST_DIR})" ]]; then
        #warn that test files are missing
        echowarn "No files were found in the ${TEST_DIR} directory"
    else
        echo "Files found in the ${TEST_DIR} directory:"
        for file in "${labDIR}/${TEST_DIR}"/*; do
            echo "    \$${index} = $(basename "${file}")"
            subsArray[${index}]="${relPath}$(basename "${file}")"
            let index++
        done
        echo "Use '\$num' to automatically substitute-in these files and paths"
    fi
    #display all files in the expected output files folder
    #Note that the subsitution system is not applied here because there
    #should only need to be one file to diff against, not a list of args
    if [[ -z "$(ls ${labDIR}/${EXPECTED_DIR})" ]]; then
        #warn that test files are missing
        echowarn "No files were found in the ${EXPECTED_DIR} directory"
        askForDiff=1
    else
        echo "Files found in the ${EXPECTED_DIR} directory:"
        for file in "${labDIR}/${EXPECTED_DIR}"/*; do
            echo "    $(basename "${file}")"
        done
    fi
    #read in the arguments
    local i=0
    local args=""
    local exOutFile=""
    while [[ $i -lt ${numTests} ]]; do
        #do not check input(s) for empty strings, in case a program doesn't
        #need arguments or have expected output files to test against
        read -p "Enter args for test[$i]: " args
        #parse through subsitutions
        local cntr=0
        for sub in "${subsArray[@]}"; do
            args="$(echo "${args}" | sed 's/$'"${cntr}"'/'"${sub}"'/g')"
            let cntr++
        done
        testArgs[$i]="${args}"
        if [[ ${askForDiff} = 0 ]]; then
            read -p "Enter an expected output file for test[$i]: " exOutFile
            expectedOut[$i]="${exOutFile}"
        fi
        let i++
    done
}

#Copy all provided files into a student's directory
#   This will not stomp over any files with the same name; if students submit
#   modified files they were not supposed to change, their programs will fail 
#   to run initially, but the original will be preserved for partial credit
#   Note: these backups will be hidden and numbered
#@param: 
#        $1 current student directory
#
#@return: 
#
#@global:
#
function cpProvidedFiles {
    local stuDIR="$1"
    local file=""
    local errCode=0
    #check if the provided_files directory is empty
    if [[ ! -z "$(ls "${labDIR}/${PROVIDED_DIR}/")" ]]; then
        echo "Starting to copy provided files for $(basename "${stuDIR}")"
        for file in "${labDIR}/${PROVIDED_DIR}/"*; do
            cp -r --backup=t "${file}" "${stuDIR}"
            errCode=$?
            if [[ ${errCode} = 0 ]]; then
                echosucc "Successfully copied ${file}"
            else
                echoerr "Failed to copy ${file} with error code: ${errCode}"
            fi
        done
    fi
}

#Run a Python program
#@param:
#        $1 Path to student's directory
#        $2 Test number
#@return:
#        - errCode Exit Code returned after run
#@global:
#
function runPy { 
    local stuDIR="$1"
    local testNum=$2
    errCode=0
    #location to store output
    local outFile="${stuDIR}${OUTPUT_DIR}/${OUT_FILE}${execFile%.*}_$i"
    #set a processing time-out per execution, push test arguments in (CS1 does 
    #not go over cmd line args and uses user input instead) and records output
{'fraction_non_alphanumeric': 0.12582219393167834, 'fraction_numerical': 0.005233750618855648, 'mean_word_length': 2.8707911305776075, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '444166', 'n_tokens_mistral': 4312, 'n_tokens_neox': 4158, 'n_words': 1716}